我有三个关于VBA和控制/操纵新窗口的问题。
我设置了几张纸。
大师|工作表1 |工作表2 |备注|工作订单|联系信息
1)我在Notes,工作订单,联系信息上设置了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)现在,当我导航到不同的工作表(例如Master)时,我希望关闭额外的窗口并使主工作表处于活动状态。我在主表上使用了以下代码。
Private Sub WorkSheet_Activate()
Windows("Mastersheet.xlsm:2").Activate
ActiveWindow.Close
Windows("Mastersheet.xlsm:1").Activate
ActiveWindow.Close
ActiveWindow.WindowState = xlMaximized
End Sub
此代码的问题在于,如果额外的窗口未打开,则会出错。我可以进行某种逻辑检查以使其工作吗?我不知道要检查什么值......
3)最后一个问题是工作簿中的宏动态生成了新工作表。这些新的工作表不会带有上面的代码来关闭多个窗口并关注活动表。是否有一个不同的对象,我应该把代码,以便它适用于Master |工作表1 | Worksheet2工作表和任何新工作表?
答案 0 :(得分:5)
这是很多问题。 :)对于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
然后插入标准模块(插入 - 模块)并粘贴此代码
Option Explicit
Public gclsAppEvents As CAppEvents
Sub Auto_Open()
Set gclsAppEvents = New CAppEvents
Set gclsAppEvents.wb = ThisWorkbook
End Sub
以下是发生的情况:打开工作簿时,Auto_Open将运行,它将创建CAppEvents对象的新实例。由于gclsAppEvents是公共的(也就是全局的),因此只要工作簿是打开的,它就不会丢失范围。它将坐在那里监听事件(因为我们在类中使用了WithEvents关键字)。
在课堂上有一个名为mobjWb_SheetActivate的子课程。这是在激活此工作簿中的任何工作表时将触发的内容。首先,它检查您刚刚激活的工作表(Sh变量)是否是您要分割的工作表之一(使用IsSplitSheet)。如果是,则检查是否已经拆分。如果没有,它就会分裂它们。
如果Sh(您刚刚激活的工作表)不是“拆分工作表”之一,则会检查是否已完成拆分(IsSplit)。如果有,它会关闭所有分割窗口。
如果您甚至想要添加,更改或删除导致拆分的工作表,请转到GetSplitSheetNames函数并更改数组参数。
因为我们正在使用自定义类并在工作簿级别嗅探事件,所以您可以随意添加和删除工作表。
答案 1 :(得分:1)
1)要测试窗口是否已打开,请使用此功能
Function IsWindowOpen(windowTitle As String) As Boolean
Dim i As Long
For i = 1 To Windows.Count
If Windows(i).Caption = windowTitle Then
IsWindowOpen = True
Exit Function
End If
Next
IsWindowOpen = False
End Function
例如:
if not IsWindowOpen("Mastersheet.xlsm:2") then
' code to open windows
end if
2)您可以再次重复使用该功能,同样的想法:
if IsWindowOpen("Mastersheet.xlsm:2") then
' code to close windows
end if
3)将代码添加到模块,而不是工作表。然后从宏中调用例程,在完成此操作后添加新工作表。如果此宏位于不同的模块中,则可能必须确保您的Sub是公共的。