我有三个关于 VBA 和控制/操作新窗口的问题。
我设置了几张表。
大师|工作表1 |工作表2 |笔记|工单 |联系方式
1) 我在注释、工单、联系信息上设置了 WorkSheet_Activate 函数,这些函数在单独的窗口中打开所有三个工作表并垂直排列它们。
Private Sub WorkSheet_Activate()
ActiveWindow.NewWindow
ActiveWindow.NewWindow
Windows.Arrange ArrangeStyle:=xlVertical
Sheets("Notes").Select
Windows("Mastersheet.xlsm:2").Activate
Sheets("Work Orders").Select
Windows("Mastersheet.xlsm:1").Activate
Sheets("Contact Info").Select
End Sub
它的问题是,如果我可以再次激活这些工作表,它将打开更多窗口。我希望代码能够检测窗口是否已经打开,如果打开则中断。
2) 现在,当我导航到不同的工作表(例如主工作表)时,我希望关闭额外的窗口并使主工作表处于事件状态。我在主表上使用了以下代码。
Private Sub WorkSheet_Activate()
Windows("Mastersheet.xlsm:2").Activate
ActiveWindow.Close
Windows("Mastersheet.xlsm:1").Activate
ActiveWindow.Close
ActiveWindow.WindowState = xlMaximized
End Sub
此代码的问题是,如果未打开额外的窗口,则会出错。我可以进行某种逻辑检查以使其正常工作吗?我不知道要检查哪些值...
3) 最后一个问题是工作簿中的宏动态生成了新工作表。这些新工作表不会携带上述关闭多个窗口并专注于事件工作表的代码。是否有一个不同的对象我应该将代码放入其中,以便它适用于主|工作表1 | Worksheet2 工作表和任何新工作表吗?
最佳答案
有很多问题。 :) 对于 3,您需要将事件移出其所在位置并移至处理应用程序级事件的自定义类模块中。首先将一个新的类模块插入到您的项目中(插入 - 类模块)。将该模块命名为 CAppEvents(F4 显示属性表,您可以在其中更改名称)。然后将此代码粘贴到类模块中
Option Explicit
Private WithEvents mobjWb As Workbook
Private Sub Class_Terminate()
Set mobjWb = Nothing
End Sub
Public Property Get wb() As Workbook
Set wb = mobjWb
End Property
Public Property Set wb(objwb As Workbook)
Set mobjWb = objwb
End Property
Private Sub mobjWb_SheetActivate(ByVal Sh As Object)
Dim wn As Window
If IsSplitSheet(Sh) Then
If Not IsSplit(Sh) Then
CreateSplitSheets Sh
End If
Else
If IsSplit(Sh) Then
For Each wn In Me.wb.Windows
If wn.Caption Like Me.wb.Name & ":#" Then
wn.Close
End If
Next wn
ActiveWindow.WindowState = xlMaximized
Sh.Activate
End If
End If
End Sub
Private Function IsSplitSheet(Sh As Object) As Boolean
Dim vaNames As Variant
Dim i As Long
IsSplitSheet = False
vaNames = GetSplitSheetNames
For i = LBound(vaNames) To UBound(vaNames)
If vaNames(i) = Sh.Name Then
IsSplitSheet = True
Exit For
End If
Next i
End Function
Private Function IsSplit(Sh As Object) As Boolean
Dim wn As Window
IsSplit = False
For Each wn In Me.wb.Windows
If wn.Caption Like Sh.Parent.Name & ":#" Then
IsSplit = True
Exit For
End If
Next wn
End Function
Private Sub CreateSplitSheets(Sh As Object)
Dim vaNames As Variant
Dim i As Long
Dim wn As Window
Dim wnActive As Window
vaNames = GetSplitSheetNames
Set wnActive = ActiveWindow
For i = LBound(vaNames) To UBound(vaNames)
If vaNames(i) <> Sh.Name Then
Set wn = Me.wb.NewWindow
wn.Activate
On Error Resume Next
wn.Parent.Sheets(vaNames(i)).Activate
On Error GoTo 0
End If
Next i
Sh.Parent.Windows.Arrange xlVertical
wnActive.Activate
Sh.Activate
End Sub
Private Function GetSplitSheetNames() As Variant
GetSplitSheetNames = Array("Notes", "Work Orders", "Contact Info")
End Function
然后插入一个标准模块(Insert - Module)并粘贴此代码
Option Explicit
Public gclsAppEvents As CAppEvents
Sub Auto_Open()
Set gclsAppEvents = New CAppEvents
Set gclsAppEvents.wb = ThisWorkbook
End Sub
发生的情况如下:当您打开工作簿时,Auto_Open 将运行,并且它将创建 CAppEvents 对象的新实例。由于 gclsAppEvents 是公共(public)的(也称为全局的),只要工作簿打开,它就不会失去范围。它将坐在那里监听事件(因为我们在类中使用了 WithEvents 关键字)。
该类中有一个名为 mobjWb_SheetActivate 的子组件。每当激活此工作簿中的任何工作表时都会触发此操作。首先,它检查您刚刚激活的工作表(Sh 变量)是否是您要拆分的工作表之一(使用 IsSplitSheet)。如果是,它就会检查它是否已经被分割。如果不是,它会将它们分开。
如果 Sh(您刚刚激活的工作表)不是“拆分工作表”之一,则它会检查是否已完成拆分 (IsSplit)。如果有,它将关闭所有拆分窗口。
如果您甚至想添加、更改或删除导致拆分的工作表,您可以转到 GetSplitSheetNames 函数并更改数组参数。
由于我们使用自定义类并在工作簿级别嗅探事件,因此您可以根据需要添加和删除工作表。
关于excel - Worksheet_新工作表的激活代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2113008/