Reputation: 3205
I have a VBA script in Excel that freezes the panes of an Excel worksheet, but I'm curious to see if this is possible without first selecting a range. This is my current code which freezes rows 1–7 but uses Range.Select
:
ActiveSheet.Range("A8").Select
ActiveWindow.FreezePanes = True
Any suggestions?
Upvotes: 30
Views: 113001
Reputation: 11
Adjusted john k's test following ChrisB's comment of using different sheets & unfreezing in selection.
Sub testFreeze(targetsheet1 As Worksheet, targetsheet2 As Worksheet)
Dim numLoops As Long
Dim StartTime, LoopTime As Long, i As Long
numLoops = 1000
Application.ScreenUpdating = False
Debug.Print ("Timing test of numloops:" & numLoops)
StartTime = Timer
For i = 0 To numLoops
If i Mod 2 = 0 Then
targetsheet1.Activate
Else
targetsheet2.Activate
End If
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
If i Mod 2 = 0 Then
targetsheet1.Select
Else
targetsheet2.Select
End If
Application.Range("C2").Select
With Application.ActiveWindow
If .FreezePanes Then .FreezePanes = False
.FreezePanes = True
End With
Next i
LoopTime = Timer
Debug.Print ("Total time of select method:" & format((LoopTime - StartTime) / 86400, "hh:mm:ss"))
Application.ScreenUpdating = True
End Sub
And they essentially take the same time.
Timing test of numloops:1000
Total time of activate method:00:00:40
Total time of select method:00:00:41
Upvotes: 0
Reputation: 11
I am using the: "excel vba freeze pane without select code".
The only change I made was to add an additional parameter to pass an object for the 'Application' part to TheApp as 'Application' was undefined in my test environment.
Public Sub FreezeTopRowPane(ByRef MyWs As Excel.Worksheet, _
ByRef TheApp As Object, _
Optional ByVal AfterRowNr As Integer = 1)
Upvotes: 0
Reputation: 3777
There are many things to get wrong about freezing panes. I add my own answer, so I will find it here, and won't have to reinvent it next time.
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
Example usage:
FreezePanesAt ThisWorkbook.Worksheets("Sheet1").Range("B3")
FreezePanesAt ThisWorkbook.Names("Header").RefersToRange
Application.Windows
(Windows(Thisworkbook.Name)
) won't cause an error if you have more windows to the same workbook (the name would be "MyWorkbook:1"), or Excel attempted (which usually fails) to repair a workbook after a crash (the name would be "MyWorkbook [Repaired]")Upvotes: 15
Reputation: 115
The problem with splitting is that if a user unfreezes panes, the panes will remain split. (I couldn't find a way to turn off split afterwards while keeping the panes frozen)
This may be too obvious/simple, but what if the current selection is simply saved and then re-selected afterwards?
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
Upvotes: 1
Reputation: 6615
I did a timing test of Freezing using .Select vs .Activate. Here is the code
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"))
And here are the results.
Timing test of numloops:1000
Total time of activate method:00:00:39
Total time of select method:00:00:01
As you can see, .Select is much faster.
Upvotes: 0
Reputation: 1
Here is what i use...
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
Upvotes: 0
Reputation: 11
Yes, the ActiveWindow.ScrollRow = 1
and ActivWindow.ScrollColumn = 1
is a must for FreezePanes if your visible window does not include cell A1.
If you are freezing rows 1:3 by selecting row 4 or cell A4, and cell A3 is not visible, the FreezePanes function will freeze the window in the center of the visible window.
Also if cell B4 is selected, and column A is not visible, then only the rows 1:3 will be frozen (column A will not frozen). Similarly, if rows 1:3 are not visible, only column A will be frozen. If both column A and rows 1:3 are not visible, the FreezePanes function will freeze the window in the center of the visible window.
Upvotes: 1
Reputation: 31
I know this is old but I came across this tidbit that may be useful... as ChrisB stated, the SplitColumn/SplitRow values represent the last cell above/left of the split BUT of the currently visible window. So if you happen to have code like this:
Application.Goto Worksheets(2).Range("A101"), True
With ActiveWindow
.SplitColumn = 0
.SplitRow = 10
.FreezePanes = True
End With
The split will be between rows 110 and 111 instead of 10 and 11.
edited for clarification and to add more information:
My point is that the values are offsets of the upper left cell, not an address of a cell. Therefore, ChrisB's Dec 4 '15 at 18:34 comment under the main answer only holds if row 1 is visible in the Activewindow.
A couple of other points on this:
Application.Goto Worksheets(1).Range("A1"), True
With ActiveWindow
.SplitColumn = 100
.SplitRow = 100
.FreezePanes = True
End With
CETAB may be dealing with this in their answer.
Upvotes: 1
Reputation: 21
I need to be able to properly refreeze panes (when creating new windows, notably) without losing the activecell or messing up the visible range. It took a lot of playing around but I think I have something solid that works:
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
Upvotes: 1
Reputation: 31
I found the previous answers only worked with some sheets when looping
through tabs
. I found the following code worked on every tab
I looped
through (target was a single workbook
), despite which workbook
was the activeworkbook
.
The short of it:
With Application.Windows(DataWKB.Name)
Application.Goto ws.Cells(4, 5)
.SplitColumn = 4
.SplitRow = 3
.FreezePanes = True
End With
The code as it is in my Sub
: (be aware, I do a lot more formatting in this sub, I tried to strip that out and leave just the code needed here)
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
Hopefully, this will save someone some research time in the future.
Upvotes: 3
Reputation:
Record yourself using the View ► Freeze Panes ► Freeze Top Row command and this is what you get for .FreezePanes.
With ActiveWindow
If .FreezePanes Then .FreezePanes = False
.SplitColumn = 0
.SplitRow = 1
.FreezePanes = True
End With
So modifying the .SplitColumn and/or .SplitRow properties should do it for you regardless on what the ActiveCell property is.
Upvotes: 66