我在Excel中有一段VBA脚本可以冻结Excel工作表的窗格,但我想知道是否可以在不首先选择范围的情况下实现。以下是我的当前代码,它可以冻结1-7行,但使用了Range.Select
:
ActiveSheet.Range("A8").Select
ActiveWindow.FreezePanes = True
有什么建议吗?
使用“查看”菜单下的“冻结窗格”功能,将顶部行冻结。点击.FreezePanes查看效果。
With ActiveWindow
If .FreezePanes Then .FreezePanes = False
.SplitColumn = 0
.SplitRow = 1
.FreezePanes = True
End With
因此,无论ActiveCell property是什么,修改.SplitColumn和/或.SplitRow属性应该就可以了。
冻结窗格是有很多易错点的。我会添加自己的答案,这样下次我就能在这里找到它,而不必重新发明。
Public Sub FreezePanesAt(rngDataTopLeft As Range)
Dim wndCurrent As Window
For Each wndCurrent In rngDataTopLeft.Worksheet.Parent.Windows
With wndCurrent
.FreezePanes = False
If Not ((rngDataTopLeft.Row = 1) And (rngDataTopLeft.Column = 1)) Then
.ScrollRow = 1
.ScrollColumn = 1
.SplitRow = rngDataTopLeft.Row - 1
.SplitColumn = rngDataTopLeft.Column - 1
.FreezePanes = True
End If
End With
Next
End Sub
使用示例:
FreezePanesAt ThisWorkbook.Worksheets("Sheet1").Range("B3")
FreezePanesAt ThisWorkbook.Names("Header").RefersToRange
Application.Windows
(Windows(Thisworkbook.Name)
)不会导致错误,如果您有更多窗口指向同一工作簿(名称将是"MyWorkbook:1"),或者Excel尝试(通常失败)在崩溃后修复工作簿(名称将是"MyWorkbook [Repaired]")我发现之前的答案只在循环浏览标签时对某些工作表有效。我发现以下代码适用于我循环遍历的每个标签(目标是单个工作簿),无论哪个工作簿是活动工作簿。
简而言之:
With Application.Windows(DataWKB.Name)
Application.Goto ws.Cells(4, 5)
.SplitColumn = 4
.SplitRow = 3
.FreezePanes = True
End With
以下是我Sub
中的代码(请注意,我在这个子程序中还进行了很多格式化处理,我尝试去掉它们并只留下需要的代码):
Sub Format_Final_Report()
Dim DataWKB As Workbook
Set DataWKB = Workbooks("Report.xlsx")
Dim ws As Worksheet
Dim tabCNT As Long
Dim tabName As String
tabCNT = DataWKB.Sheets.Count
For i = 1 To tabCNT
Set ws = DataWKB.Worksheets(i)
tabName = ws.Name
With Application.Windows(DataWKB.Name)
Application.Goto ws.Cells(4, 5)
.SplitColumn = 4
.SplitRow = 3
.FreezePanes = True
End With
Next i
End Sub
我需要能够正确地冻结窗格(尤其是在创建新窗口时),而不会丢失活动单元格或混乱可见范围。经过多次尝试,我想我有一个可靠的解决方案:
Sub FreezePanes(nbLignes As Integer, nbColonnes As Integer, Optional ByVal feuille As Worksheet)
If feuille Is Nothing Then Set feuille = ActiveSheet Else feuille.Activate
Error GoTo erreur
With ActiveWindow
If .View = xlNormalView Then
If .FreezePanes Then .FreezePanes = False
If .Split Then .Split = False
.SplitColumn = nbColonnes
.SplitRow = nbLignes
If .Panes.Count = 4 Then 'rows and columns frozen
.Panes(1).ScrollRow = 1
.Panes(1).ScrollColumn = 1
.Panes(2).ScrollRow = 1 'top right pane
.Panes(3).ScrollColumn = 1 'bottom left pane
ElseIf nbLignes > 0 Then .Panes(1).ScrollRow = 1
ElseIf nbColonnes > 0 Then .Panes(1).ScrollColumn = 1
Else: GoTo erreur
End If
.FreezePanes = True
End If
End With
Exit Sub
erreur:
Debug.print "Erreur en exécutant le sub 'FreezePanes " & nbLignes & ", " & nbColonnes & ", '" & feuille.Name & "' : code #" & Err.Number & Err.Description
End Sub
我知道这已经过时了,但我发现这个小提示可能会有用......正如ChrisB所说,SplitColumn / SplitRow值表示分割线上方/左侧的最后一个单元格,但是当前可见窗口的。因此,如果您恰好拥有像这样的代码:
Application.Goto Worksheets(2).Range("A101"), True
With ActiveWindow
.SplitColumn = 0
.SplitRow = 10
.FreezePanes = True
End With
Application.Goto Worksheets(1).Range("A1"), True
With ActiveWindow
.SplitColumn = 100
.SplitRow = 100
.FreezePanes = True
End With
如果您可见的窗口不包括单元格A1,则ActiveWindow.ScrollRow = 1
和ActivWindow.ScrollColumn = 1
对于FreezePanes是必须的。
如果您选择行4或单元格A4来冻结1:3行,并且单元格A3不可见,则FreezePanes函数将在可见窗口中心冻结窗口。
同样,如果选择了B4单元格并且列A不可见,则只有1:3行会被冻结(列A不会被冻结)。 同样,如果1:3行不可见,则只有A列会被冻结。 如果列A和1:3行都不可见,则FreezePanes函数将在可见窗口中心冻结窗口。
Sub FreezeTopRow()
'First save the current selection to go back to it later
Dim rngOriginalSelection As Range
Set rngOriginalSelection = Selection
'Change selection to A2 to make .FreezePanes work
ActiveSheet.Range("A2").Select
ActiveWindow.FreezePanes = True
'Change selection back to original
rngOriginalSelection.Select
End Sub
这是我使用的...
Public Sub FreezeTopRowPane(ByRef MyWs As Excel.Worksheet, _
Optional ByVal AfterRowNr As Integer = 1)
Dim SavedWS As Worksheet
Dim SavedUpdating As Boolean
SavedUpdating = Application.ScreenUpdating 'save current screen updating mode
Set SavedWS = ActiveSheet 'save current active sheet
Application.ScreenUpdating = False 'turn off screen updating
MyWs.Activate 'activate worksheet for panes freezing
ActiveWindow.FreezePanes = False 'turn off freeze panes in case
With ActiveWindow
.SplitColumn = 0 'set no column to split
.SplitRow = AfterRowNr 'set the row to split, default = row 1
End With
ActiveWindow.FreezePanes = True 'trigger the new pane freezing
SavedWS.Activate 'restore previous (saved) ws as active
Application.ScreenUpdating = SavedUpdating 'restore previous (saved) updating mode
End Sub
我使用 .Select 和 .Activate 进行了 Freezing 的时间测试。以下是代码:
Dim numLoops As Long
Dim StartTime, LoopTime As Long
numLoops = 1000
Debug.Print ("Timing test of numloops:" & numLoops)
StartTime = Timer
For I = 0 To numLoops
targetSheet.Activate
With ActiveWindow
If .FreezePanes Then .FreezePanes = False
.SplitColumn = 2
.SplitRow = 1
.FreezePanes = True
End With
Next I
LoopTime = Timer
Debug.Print ("Total time of activate method:" & Format((LoopTime - StartTime) / 86400, "hh:mm:ss"))
StartTime = Timer
For I = 0 To numLoops
targetSheet.Select
Application.Range("C2").Select
Application.ActiveWindow.FreezePanes = True
Next I
LoopTime = Timer
Debug.Print ("Total time of select method:" & Format((LoopTime - StartTime) / 86400, "hh:mm:ss"))
Timing test of numloops:1000
Total time of activate method:00:00:39
Total time of select method:00:00:01
正如您所看到的,.Select 更快。
Select
方法没有先取消冻结窗格,因此,即使在工作表的不同位置已经冻结了窗格,它也不会做任何事情。我怀疑之所以时间如此之快,是因为循环2-1000没有完成任何操作,但我很好奇是否真的如此。 - ChrisBPublic Sub FreezeTopRowPane(ByRef MyWs As Excel.Worksheet, _
ByRef TheApp As Object, _
Optional ByVal AfterRowNr As Integer = 1)
With ActiveWindow .SplitColumn = 0 .SplitRow = 7 End With ActiveWindow.FreezePanes = True
- ChrisBWith ActiveWindow
块的第一行使用类似If .FreezePanes Then .FreezePanes = False
的代码可能是适当的。 - user4039065Application.Windows()
的工作簿名称是错误的,会导致Run-time error '9' Subscript out of range
错误,请参见https://stackoverflow.com/a/47177498/1026。 - Nickolay