Use cell value as range to hide columns - vba

I have a spreadsheet that there is a checkbox the purpose of the checkbox is to hide the name of clients in two adjacent columns. Because the spreadsheet changes from time to time the position of the columns changes thus it is currently P:Q but a year ago it was H:I.
I want to store the 'range' in a cell and reference that from my vba and get that to hide the columns. The checkbox is a simple toggle. I have tried various incarnations without success and my latest effort tells me that I have not se up the range properly. The cel I am using for teh range is F4. The code is currently:
Private Sub CheckBox2_Click()
Dim c As Range
Dim Visy As Integer
Dim My_range As String
'My_range is the range of filled rows stored as a range in cell F4
'Visy stores the state of the checkbox
If CheckBox2.Value = True Then
Visy = 1
Else
Visy = 0
End If
'Stop any use of the spread sheet and set variable initial states
Application.EnableEvents = False
My_range = Sheet9.Cells(4, 6).Value
'Hide the columns
Range(My_range).Hidden = Visy
'Sheet9.colums(My_range).Hidden = True
'Re enable application
On Error GoTo 0
Application.EnableEvents = True
End Sub

This is within a single sheet:
Sub qwerty()
My_range = Cells(4, 6).Value
Range(My_range).EntireColumn.Hidden = True
End Sub

Your Private Sub CheckBox2_Click should be in a worksheet's code sheet. I believe this is the worksheet identified by the Sheet9 worksheet .CodeName property.
A Private Sub in a worksheet codesheet does not have to explicitly reference the .Parent worksheet property on any Range object or
Range.Cells object unless you want to reference another worksheet's cells. These are bound to the cells on the worksheet whose codesheet you are on regardless of the ActiveSheet property.
Private Sub CheckBox2_Click()
Range(Cells(4, "F").Text).EntireColumn.Hidden = CBool(Me.Value)
End Sub
Do not confuse a worksheet's Private Sub behavior with a Private Sub on a module code sheet. A module codesheet should always explicitly reference the parent worksheet (and often the parent workbook) regardless of whether the Sub is Public or Private.

You have to use code in context:
Private Sub CheckBox2_Click()
Dim wsh As Worksheet
Dim sRangeName As String
'context!
Set wsh = ThisWorkbook.Worksheets("TypeNameHere")
sRangeName = wsh.Range("F4")
wsh.Range(sRangeName).EntireColumn.Hidden = CheckBox2.Value
Set wsh = Nothing
End Sub

Thanks to all who responded it helped a lot and put me on the right track. As several of you noted context is important and I was mixing private sub and sub and so had a scope problem when it came to ranges. I also from another source had the suggestion to use a named range rather than read a cell value since the columns were always adjacent. I have published the code below in case it is of value to anyone in the future.
Private Sub CheckBox2_Click()
'Requires ClientNameCol to be set to the range to be hidden
Dim Visy As Boolean
'Stop any use of the spread sheet and set variable initial states
Application.EnableEvents = False
'Check if sheet is to be hidden or not
If Worksheets("Client 16").CheckBox2.Value = True Then
Visy = True
Else
Visy = False
End If
'Hide/unhide the columns
With ThisWorkbook
.Worksheets("Client 16").Range("ClientNameCol").EntireColumn.Hidden = Visy
End With
On Error GoTo 0
Application.EnableEvents = True
End Sub

Related

Excel vba when adding or deleting sheet in workbook, show/hide button in main sheet

I have a button with a simple macro that deletes certain sheets.
I'd like to show this button only when those sheets are actually there (I can use worksheets.count because I have 2 "permanent" sheets; if > 2 then I know I have a new sheet and I want to show the button to delete it if I want to).
I think I have to use "Workbook.SheetChange event" because "Worksheet.Change event" doesn't seem to work for me in this case.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim foglio_parametri As Worksheet
Set foglio_parametri = ThisWorkbook.Worksheets("PARAMETRI") 'my main sheet where I want to show/hide the button
Application.ScreenUpdating = True
If Application.Worksheets.Count > 2 Then
foglio_parametri.CommandButton2.Visible = True
Else
foglio_parametri.CommandButton2.Visible = False
End If
End Sub
Thank you very much for your time.
I will not use your names as they are in a foreign language I do not understand .
Let's assume the button you are talking about is in a sheet with the name sheet3 which also has the codename sheet3. The button itself has the name CommandButton1. Let's further assume the certain sheets you are talking about have the names sheet4 and sheet5 then I would add the following code to the workbook module
Option Explicit
Private Sub Workbook_Open()
Sheet3.HidecmdBtn
End Sub
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name = "Sheet3" Then
Sheet3.HidecmdBtn
End If
End Sub
In the worksheet module of sheet3 you have the following code
Option Explicit
Private Sub CommandButton1_Click()
' Your code goes here
' In case your code deletes the sheets you have to hide the button
HidecmdBtn
End Sub
Sub HidecmdBtn()
Dim Sh As CommandButton
' My button is located on sheet 3 and has the name "CommandButton1"
Set Sh = CommandButton1
Dim sh1Name As String
Dim sh2Name As String
sh1Name = "Sheet4"
sh2Name = "Sheet5"
If SheetExists(sh1Name) Or SheetExists(sh2Name) Then
Sh.Visible = msoTrue
Else
Sh.Visible = msoFalse
End If
End Sub
In a normal module you have
Public Function SheetExists(SheetName As String, Optional wrkBook As Workbook) As Boolean
If wrkBook Is Nothing Then
Set wrkBook = ActiveWorkbook 'or ThisWorkbook - whichever appropriate
End If
Dim obj As Object
On Error GoTo HandleError
Set obj = wrkBook.Sheets(SheetName)
SheetExists = True
Exit Function
HandleError:
SheetExists = False
End Function

Unable to Activate Macro when Active Cell Changes Through formula

My aim is to trigger the advanced filter macro when cell B2 changes (a part of the filtering criteria). B2 is linked to another cell(in another worksheet) which dynamically gets data from external sources. The problem I am facing is that the macro does not activate automatically. Only when I manually change something in B2 is the macro activated. Otherwise the old criteria remains in place. A1 to G1 has the 7 categories and A2-G2 has the inputs for the filter. Only B2 changes effectively. I have not coded in VBA before so most of this code is copied from websites and modified for my workbook. Below is my code. Appreciate any help on this.
Option Explicit
'Create variable to hold values
Dim Monitored()
Sub Advanced_Filtering()
Range("A7:G730").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=Range("A1:G2"), CopyToRange:=Sheets("Sheet3").Range("L1:R1")
End Sub
Private Sub Worksheet_Activate()
Monitored = Range("B2:C2").Value 'Read in value prior to any changes
End Sub
Private Sub Worksheet_Calculate()
Dim Xrg As Range, c As Range, x As Integer
Set Xrg = Range("B2:C2")
If Not Intersect(Xrg, Range("B2:C2")) Is Nothing Then
Application.EnableEvents = False
'Compare monitored cell with initial value
x = 1
For Each c In Range("B2:C2")
If c.Value <> Monitored(x, 1) Then
Call Advanced_Filtering
Monitored(x, 1) = c.Value
End If
x = x + 1
Next c
'Reset events
Application.EnableEvents = True
End If
End Sub
Probably the easiest fix would be to place the Worksheet_Change event under the cells that generate the value on your cell B2, as changes in formula values don't trigger the Change event... or you can change it to Worksheet_Calculate event instead, this will pick up changes in formula results as below:
Option Explicit
'Create variable to hold values
Dim Monitored
Sub Advanced_Filtering()
Range("A7:G730").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=Range("A1:G2"), CopyToRange:=Sheets("Sheet3").Range("L1:R1")
End Sub
Private Sub Worksheet_Activate()
Monitored = Range("B2").Value 'Read in value prior to any changes
End Sub
Private Sub Worksheet_Calculate()
Dim Xrg As Range
Set Xrg = Range("B2")
If Not Intersect(Xrg, Range("B2")) Is Nothing Then
Application.EnableEvents = False
'Compare monitored cell with initial value
If Range("B2").Value <> Monitored Then
'Do things as a result of a change
Call Advanced_Filtering
'Reset Variable with new monitored value
Monitored = Range("B2").Value
End If
'Reset events
Application.EnableEvents = True
End If
End Sub
UPDATE:
To use a Range of cells instead of a single one, you should change the following:
Option Explicit
'Create variable to hold values
Dim Monitored()
Sub Advanced_Filtering()
Range("A7:G730").AdvancedFilter Action:=xlFilterCopy, CriteriaRange:=Range("A1:G2"), CopyToRange:=Sheets("Sheet3").Range("L1:R1")
End Sub
Private Sub Worksheet_Activate()
Monitored = Range("B2:C2").Value 'Read in value prior to any changes
End Sub
Private Sub Worksheet_Calculate()
Dim Xrg As Range, c As Range, x As Integer
Set Xrg = Range("B2:C2")
If Not Intersect(Xrg, Range("B2:C2")) Is Nothing Then
Application.EnableEvents = False
'Compare monitored cell with initial value
x = 1
For Each c In Range("B2:C2")
If c.Value <> Monitored(1, x) Then
Call Advanced_Filtering
Monitored(1, x) = c.Value
End If
x = x + 1
Next c
'Reset events
Application.EnableEvents = True
End If
End Sub

How to apply workbook_open to multiple sheets

I have a excel workbook that a number of users interact with daily and on multiple montiors with different resolutions, screen zooms etc.. I need all worksheets to adjust to the ranges on each sheet I want the user to see each time.
Below works for 1 worksheet, but how would I get it to apply to all worksheets (Sheet1,Sheet2,etc.)
Private Sub Workbook_Open()
With Sheets("Sheet1")
Columns("A:P").Select
ActiveWindow.Zoom = True
Range("A1").Select
End With
End Sub
You can use the Worksheet_Activate event, and place code such as
Private Sub Worksheet_Activate()
Columns("A:P").Select
ActiveWindow.Zoom = True
Range("A1").Select
End Sub
on each sheet, editing the range as required.
That code will execute every time the sheet is activated, which may or may not be what you would like, so you may need to use something a bit more complicated and use:
Private AlreadyRun As Boolean
Private Sub Worksheet_Activate()
If Not AlreadyRun Then
Columns("A:P").Select
ActiveWindow.Zoom = True
Range("A1").Select
AlreadyRun = True
End If
End Sub
which will only do something the first time the sheet is activated (as the AlreadyRun variable will originally be False, but will be changed to True once it is run once), or
Private AlreadyRun As Boolean
Private Sub Worksheet_Activate()
Dim CurRng as Range
Set CurRng = Selection
Columns("A:P").Select
ActiveWindow.Zoom = True
CurRng.Select
If Not AlreadyRun Then
Range("A1").Select
AlreadyRun = True
End If
End Sub
which will resize the sheet every time it is activated, but only move the selected cell to A1 the first time.
To avoid the issue caused by the sheet which is current when the Workbook is saved not going through the Worksheet_Activate event when the workbook is reopened, you can include a Workbook_Open event that says
Private Sub Workbook_Open()
Application.Screenupdating = False
Dim ws As Worksheet
Set ws = Activesheet
'For the next two lines, just pick any two of your worksheets
'All it is trying to do is to ensure whichever sheet was active at open
'is deactivated before being activated again in the "ws.Activate" command
Worksheets("Sheet1").Activate
Worksheets("Sheet2").Activate
ws.Activate
Application.Screenupdating = True
End Sub
(Disabling Screenupdating while the event is run will avoid the users seeing any "flickering" of worksheets.)

Run a Macro every time sheet is changed

i'm still fairly new to macros, i've got a bit of code i need to run on a sheet every time it gets updated, changed, or whatever.
Here is the code I need to run: How can i do this?
Sub UnMergeFill()
Dim cell As Range, joinedCells As Range
For Each cell In ThisWorkbook.ActiveSheet.UsedRange
If cell.MergeCells Then
Set joinedCells = cell.MergeArea
cell.MergeCells = False
joinedCells.Value = cell.Value
End If
Next
End Sub
You can boost the efficiency of your macro by locating the merged cells to process rather than looping through every cell in the Worksheet.UsedRange property and examining it for the Range.MergeCells Property.
Within the worksheet's conventional Range.Find method, there is an option to look for formatting. On this sub-dialog's Alignment tab, you'll find the option to locate Merged cells.
        
This can be incorporated into your VBA sub procedure using the Range.Find method and the Application object's .FindFormat property.
Your sub procedure using FindFormat:
Sub UnMergeFill(Optional ws As Worksheet)
If ws Is Nothing Then Set ws = ActiveSheet
Dim fndMrg As Range, joinedCells As Range
Application.FindFormat.MergeCells = True
With ws
On Error Resume Next
Set fndMrg = .Cells.Find(What:=vbNullString, SearchFormat:=True)
Do While Not fndMrg Is Nothing
Set joinedCells = fndMrg.MergeArea
fndMrg.MergeCells = False
'fndMrg.UnMerge '???
joinedCells.Value = fndMrg.Value
Set fndMrg = .Cells.Find(What:=vbNullString, SearchFormat:=True)
Loop
End With
Application.FindFormat.MergeCells = False
End Sub
Slightly revised Worksheet_Change event macro with more environment shutdown during processing.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo bm_Safe_Exit
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
Call UnMergeFill(Target.Parent)
bm_Safe_Exit:
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
I've opted to specify the worksheet to be processed rather than rely on the ActiveSheet property. There is the possibility that the Worksheet_Change could be initiated by an outside process when it is NOT the active sheet.
In short, opt for bulk operations whenever possible and avoid looping whenever you can. This is not blinding fast but it should be substantially quicker than looping through the cells.
In the code module for that particular worksheet, just add this:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
UnMergeFill
Application.EnableEvents = True
End Sub

Showing hidden column in another sheet

I am having trouble finding how to "show" a hidden column in another sheet with VBA.I am currently studying VBA and I wanted to have a hide/unhide code for every case, but this one is missing. Any suggestions?
My (updated) code is here:
Private Sub CommandButton1_Click()
'To Hide Sheet 2
Worksheets("Sheet2").Visible = False
'To Hide Rows 22 to 25
Rows("22:25").EntireRow.Hidden = True
'To Hide Columns E to G
Columns(":G").EntireColumn.Hidden = True
'More specific hidding (inside a different sheet)
Worksheets("Sheet3").Columns("A:G").EntireColumn.Hidden = True
End Sub
Public Sub UnHideAll()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
ws.Visible = xlSheetVisible
Rows.Hidden = False
Columns.Hidden = False
Next ws
End Sub
Private Sub CommandButton2_Click()
UnHideAll
End Sub
Try
Sub UnHideAll()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
ws.Visible = xlSheetVisible
ws.Rows.Hidden = False
ws.Columns.Hidden = False
Next ws
End Sub
The point of the code is that you need to qualify Rows and Columns by the worksheet if you want them to refer to anything other than the active sheet. Prefixing them by ws. lets VBA know what sheet the rows and columns are on. Then in the code for the button just:
Private Sub CommandButton1_Click()
UnHideAll
End Sub
I've tested it a number of times using both manually columns, rows, and sheets, as well as when it was VBA doing the hiding, and it seems to work fine.