I am trying to hide a commandbutton based on a specific cell value. I have looked up several codes and pasted them in excel (in the vba form when right clicking the sheet and selecting "view code").
What am I doing wrong?
Here's one of the codes I've tried:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("A1") = 0 Then ActiveSheet.CommandButton1.Visible = False
If Range("A1") = 1 Then ActiveSheet.CommandButton1.Visible = True
End Sub
Make sure you enable events before using your code. Also, you must place your code in Worksheet module, not in regular module. To enable events, use this simple sub.
Sub Enable_events()
Application.EnableEvents = True
End Sub
please run this first:
Sub enable_()
Application.EnableEvents = True
End Sub
and then your Code will run perfectly:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("A1") = 0 Then ActiveSheet.CommandButton1.Visible = False
If Range("A1") = 1 Then ActiveSheet.CommandButton1.Visible = True
End Sub
Your code is confusing, for a number of reasons.
Range, when it's not qualified with a Worksheet object, implicitly refers to the ActiveSheet, i.e. ActiveSheet.Range... but when it's in a worksheet's code-behind, it implicitly refers to that worksheet's Range property, i.e. Me.Range. Because the meaning of an unqualified Range call depends on context, it's best to always qualify it with an explicit Worksheet object.
So if you're in the code-behind module for Sheet1, then Range("A1") is equivalent to Sheet1.Range("A1"), or even better, Me.Range("A1").
The two conditions will be evaluated every time, but only one of them needs to be: it's inefficient.
Truth is, you don't need to assign a Boolean literal - a Boolean expression is much cleaner.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Me.CommandButton1.Visible = (Me.Range("A1") = 1)
End Sub
Now, assuming Application.EnableEvents returns True, that code will run every time the selection changes, which is rather overkill.
Handle the Worksheet.Change event instead, and only act when the modified cell is A1:
Private Sub Worksheet_Change(ByVal Target As Range)
If Application.Intersect(Target, Me.Range("A1")) Is Nothing And Target.Count <> 1 Then
' we don't care about that cell: bail out
Exit Sub
End If
Me.CommandButton1.Visible = (Me.Range("A1") = 1)
End Sub
Please try this code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A1")) Is Nothing Then
If Selection.Cells.Count = 1 Then
If Range("A1") = 0 Then ActiveSheet.CommandButton1.Visible = False
If Range("A1") = 1 Then ActiveSheet.CommandButton1.Visible = True
End If
End If
End Sub
Hope this help.
Related
I have simple macros for clearing cells on "Sheet1", which have drop down lists.
Sub reset1()
Range("D20:E21").ClearContents
Range("D8:E9").ClearContents
Range("D6:E7").ClearContents
End Sub
Sub reset2()
Range("D20:E21").ClearContents
Range("D8:E9").ClearContents
End Sub
Then I call these macros on "Sheet1" if the cell values change
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$D$4" Then
Call reset1
End If
If Target.Address = "$D$6" Then
Call reset2
End If
End Sub
This code is written on the "Sheet1".
Normally it works but sometimes reset1() doesn't work.
I should then save and reopen the excel or run the macro manually.
Should I better modify some codes?
First problem is that with Range("D20:E21") it is not clear in which worksheet that range should be. Always specify the worksheet like Worksheets("Sheet1").Range("D20:E21").
Second problem is that if you .ClearContents in a Worksheet_Change event this is a cell change and triggers another Worksheet_Change event and so on. So it is recommended to disable events Application.EnableEvents = False before changing cells in Worksheet_Change event.
Third problem is that if you test Target.Address = "$D$4" and you copy paste a range where D4 is included your code will not run even if your cell D4 changed. Therefore you always need to work with Intersect.
Option Explicit
Sub Reset1(ByVal ws As Worksheet)
ws.Range("D20:E21,D8:E9,D6:E7").ClearContents
' alternative:
' Union(ws.Range("D20:E21"), ws.Range("D8:E9"), ws.Range("D6:E7")).ClearContents
End Sub
Sub Reset2(ByVal ws As Worksheet)
ws.Range("D20:E21,D8:E9").ClearContents
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
On Error Goto ENABLE_EVENTS ' in any case an error happens make sure events are enabeld again
If Not Intersect(Target, Me.Range("D4")) Is Nothing Then
Reset1 Me ' here we tell Reset1 to take `Me` as worksheet. Me refers to the worksheet `Target` is in.
End If
If Not Intersect(Target, Me.Range("D6")) Is Nothing Then
Reset2 Me
End If
ENABLE_EVENTS:
Application.EnableEvents = True
If Err.Number Then
Err.Raise Err.Number
End If
End Sub
I have 4 Cells (S11:T12) and a Command Button 1, what I want is, until all 4 cells are populated the command button should be disabled (Which I can do from the properties tab) and once all 4 cells are filled with number, the command button should be enabled and once the data from these cells are deleted, the command button should be disabled again.
Under which event should I write the code?
I tried this, but it does not work.
Private Sub Workbook_Open(Cancel As Boolean)
If Sheets("WorkArea").Range("S11:T12") = "" Then
Sheets("WorkArea").CommandButton1.Enabled = False
Else
Sheets("WorkArea").CommandButton1.Enabled = True
End If
End Sub
Use the WorkSheet_Change event handler to handle the change in cells, and you can use the CountBlank worksheet function to determine if a range is empty.
Private Sub Worksheet_Change(ByVal Target As Range)
If WorksheetFunction.CountBlank(Range("S11:T12")) = 4 Then
Sheets("WorkArea").CommandButton1.Enabled = False
Else
Sheets("WorkArea").CommandButton1.Enabled = True
End If
End Sub
Worksheet_Change
CountBlank
According to your question however, you actually want:
Private Sub Worksheet_Change(ByVal Target As Range)
If WorksheetFunction.CountBlank(Range("S11:T12")) = 0 Then
Sheets("WorkArea").CommandButton1.Enabled = True
Else
Sheets("WorkArea").CommandButton1.Enabled = False
End If
End Sub
A Worksheet Change
This solution will not work if the critical range contains formulas.
To count the number of cells that are not empty you can use the WorksheetFunction.CountA method.
Usually you don't want this code to run when there are changes outside of the range, so you will restrict the code to the range with the Application.Intersect method. You don't have to enable or disable the command button on each change since obviously the code will run on each change.
Since this is all happening in worksheet "WorkArea", there is no need to refer to it by its name i.e. you can safely use Range(rngAddress) and CommandButton1 instead of ThisWorkbook.Worksheets("WorkArea").Range(rngAddress) and ThisWorkbook.Worksheets("WorkArea").CommandButton1 respectively.
The Code
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const rngAddress As String = "S11:T12"
Dim rng As Range
Set rng = Range(rngAddress)
If Not Intersect(Target, rng) Is Nothing Then
If WorksheetFunction.CountA(rng) = rng.Cells.Count Then
CommandButton1.Enabled = True
Else
CommandButton1.Enabled = False
End If
End If
End Sub
I am using worksheet change event to trigger copy paste values. Worksheet change code is in the sheet2
Sub worksheet_change(ByVal Target As Range)
Application.EnableEvents = True
Set Target = Range("AB2")
If Target.Value = "OK" Then
Call myTR1
End If
Please note AB2 cell takes it's value from another sheet
Copy paste code is in a Module
Sub myTR1()
Sheets("BA1").Range("AR6:AS8").Value = Sheets("BA1").Range("AL17:AM19").Value
End Sub
When target range changes to "OK", my copy paste macro is not triggering. What am I doing wrong?
Using your eaxct code worked, although you didnt have end sub in your example?
EDIT:
Bear in mind the 'OK' is case sensitive so it will have to be in uppercase to fire, if you want it to fire either on lower or upper you can use the second code.
Sub worksheet_change(ByVal Target As Range)
Application.EnableEvents = True
Set Target = Range("AB2")
If Target.Value = "OK" Then
Call myTR1
End If
End Sub
Sub worksheet_change(ByVal Target As Range)
Application.EnableEvents = True
Set Target = Range("AB2")
If Target.Value = "OK" Or Target.Value = "ok" Then
Call myTR1
End If
End Sub
I have two cells named INPUT_A_1 and INPUT_A_2 in worksheets named "Sheet1" and "Sheet2" respectively, that I'm linking (changing one cell triggers the identical change in the other) with the following sheet macros which work very well:
In Sheet1:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If (Target.Address = Range("INPUT_A_1").Address) Then
Sheets("Sheet2").Range("INPUT_A_2") = Target.Value
End If
Application.EnableEvents = True
End Sub
and in Sheet2:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If (Target.Address = Range("INPUT_A_2").Address) Then
Sheets("Sheet1").Range("INPUT_A_1") = Target.Value
End If
Application.EnableEvents = True
End Sub
My problem is that owing to the syntax Sheets(sheetname).Range(rangename), if I decide to rename either or both worksheets, then I have to alter the macros accordingly. Is there some sort of workaround to this that does not involve summoning the cells by the corresponding worksheet name? This problem becomes decidedly more compelling when I have 3 or more linked cells each in a different worksheet.
Thanks
The "workaround" is to use the codename of the worksheet instead
Using the Code Name of a Worksheet
The best method of accessing the worksheet is using the code name.
Each worksheet has a sheet name and a code name. The sheet name is the
name that appears in the worksheet tab in Excel.
Changing the sheet name does not change the code name meaning that
referencing a sheet by the code name is a good idea.
Following Storax's excellent suggestion above, here is the fix that I implemented:
In the first worksheet (which can be renamed at will):
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If (Target.Address = Range("INPUT_A_1").Address) Then
SheetFromCodeName("Sheet2").Range("INPUT_A_2") = Target.Value
End If
Application.EnableEvents = True
End Sub
and in the Second worksheet (which can also be renamed at will):
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If (Target.Address = Range("INPUT_A_2").Address) Then
SheetFromCodeName("Sheet1").Range("INPUT_A_1") = Target.Value
End If
Application.EnableEvents = True
End Sub
And finally, in any module:
Public Function SheetFromCodeName(CodeName$) As Worksheet
Dim sh As Worksheet
For Each sh In ThisWorkbook.Sheets
If sh.CodeName = CodeName Then
Set SheetFromCodeName = sh
Exit For
End If
Next sh
End Function
The SheetName and CodeName association is according to:
If one has multiple sheets with linked cells, and any of the sheets is deleted, an On Error Resume Next should work.
In fact, the Sheet Index could be used instead thereby obviating the need for the SheetFromCodeName routine altogether.
The syntax in this case in the first and second sheets would be
Worksheets(2).Range("INPUT_A_2") = Target.Value
and
Worksheets(1).Range("INPUT_A_1") = Target.Value
Hej,
I've created a small VBA code to dynamically rename a worksheet.
It's working perfectly when the cell is just manually typed.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("C9")) Is Nothing Then
ActiveSheet.Name = ActiveSheet.Range("C9")
End If
End Sub
But then as soon as I will put a formula concatenating 2 cells values within C9 cell it will not update it automatically.
To make it work I need to enter the cell and type ENTER again and it works.
I have to do same manipulation each time I change a value in on of the 2 cell concatenated.
THANKS for your help guys
You need to capture a different event:
Private Sub Worksheet_Calculate()
Application.EnableEvents = False
ActiveSheet.Name = ActiveSheet.Range("C9")
Application.EnableEvents = True
End Sub
NOTE:
We disable events during the name change in case the worksheet contains a formula referencing the tab-name.
this should work:
replace
ActiveSheet.Name = ActiveSheet.Range("C9")
by
ActiveSheet.Name = ActiveSheet.Range("C9").Value
This is an alternate answer if someone still wants to execute this on worksheet change event
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Dim formulacell As Range
Set formulacell = Range("C9")
Set formulacell = Application.Union(formulacell, formulacell.Precedents)
If Not Intersect(Target, formulacell) Is Nothing Then
ActiveSheet.Name = ActiveSheet.Range("C9").Value
End If
Application.EnableEvents = True
End Sub