I'm having trouble adding another function in that macro I used to activate or deactivate columns in a Excel Workbook we are using at work. I'm getting the Out of stack space error when running it just adding one of the following function.
Mostly, I've used an If( ;1;0) to manage the activation part and an If(;TRUE;FALSE) for the locked/unlocked part. The function I want to had is based on the same idea using a verification code to Clearcontents of a cell and locked it. If the verification code is false, then, I want the cell to be unlocked so the user can write the value. Here is the code line I want to had times 15 as already done for the locked, unlocked function.
If Range("AS16") = "Vrai" Then
Range("AA16").ClearContents
Range("AA16").Locked = True
Else:
Range("AA16").Locked = False
End If
Here is the code I'm using right now.
Private Sub Worksheet_Change(ByVal Target As Range)
ActiveSheet.Unprotect ("Francis")
Dim Cell As Range
Set Cell = ActiveCell
Application.ScreenUpdating = False
For Each cellule In Range("S50:X50")
If cellule.Value = "1" Then cellule.EntireColumn.Hidden = False
Next cellule
For Each cellule In Range("S50:X50")
If cellule.Value = "0" Then cellule.EntireColumn.Hidden = True
Next cellule
For Each cellule In Range("I50:J50")
If cellule.Value = "1" Then cellule.EntireColumn.Hidden = False
Next cellule
For Each cellule In Range("I50:J50")
If cellule.Value = "0" Then cellule.EntireColumn.Hidden = True
Next cellule
If Range("AR16") = "Vrai" Then
Range("K16").Locked = False
Range("O16").Locked = False
Else:
Range("K16").Locked = True
Range("O16").Locked = True
End If
If Range("AR18") = "Vrai" Then
Range("K18").Locked = False
Range("O18").Locked = False
Else:
Range("K18").Locked = True
Range("O18").Locked = True
End If
If Range("AR20") = "Vrai" Then
Range("K20").Locked = False
Range("O20").Locked = False
Else:
Range("K20").Locked = True
Range("O20").Locked = True
End If
If Range("AR22") = "Vrai" Then
Range("K22").Locked = False
Range("O22").Locked = False
Else:
Range("K22").Locked = True
Range("O22").Locked = True
End If
If Range("AR24") = "Vrai" Then
Range("K24").Locked = False
Range("O24").Locked = False
Else:
Range("K24").Locked = True
Range("O24").Locked = True
End If
If Range("AR26") = "Vrai" Then
Range("K26").Locked = False
Range("O26").Locked = False
Else:
Range("K26").Locked = True
Range("O26").Locked = True
End If
If Range("AR28") = "Vrai" Then
Range("K28").Locked = False
Range("O28").Locked = False
Else:
Range("K28").Locked = True
Range("O28").Locked = True
End If
If Range("AR30") = "Vrai" Then
Range("K30").Locked = False
Range("O30").Locked = False
Else:
Range("K30").Locked = True
Range("O30").Locked = True
End If
If Range("AR32") = "Vrai" Then
Range("K32").Locked = False
Range("O32").Locked = False
Else:
Range("K32").Locked = True
Range("O32").Locked = True
End If
If Range("AR34") = "Vrai" Then
Range("K34").Locked = False
Range("O34").Locked = False
Else:
Range("K34").Locked = True
Range("O34").Locked = True
End If
If Range("AR36") = "Vrai" Then
Range("K36").Locked = False
Range("O36").Locked = False
Else:
Range("K36").Locked = True
Range("O36").Locked = True
End If
If Range("AR38") = "Vrai" Then
Range("K38").Locked = False
Range("O38").Locked = False
Else:
Range("K38").Locked = True
Range("O38").Locked = True
End If
If Range("AR40") = "Vrai" Then
Range("K40").Locked = False
Range("O40").Locked = False
Else:
Range("K40").Locked = True
Range("O40").Locked = True
End If
If Range("AR42") = "Vrai" Then
Range("K42").Locked = False
Range("O42").Locked = False
Else:
Range("K42").Locked = True
Range("O42").Locked = True
End If
If Range("AR44") = "Vrai" Then
Range("K44").Locked = False
Range("O44").Locked = False
Else:
Range("K44").Locked = True
Range("O44").Locked = True
End If
Application.ScreenUpdating = True
Application.Goto Cell
'ActiveSheet.Protect Password:="Francis"
End Sub
Thanks a lot for your help.
Have a nice day!
You typically don't want to have performance-expensive code running in that specific handler. Worksheet_Change gets invoked every time a cell changes... and that includes changing a cell's Locked property value.
So that's how you run out of stack space: your handler is modifying cells' Locked state, which triggers the Worksheet_Change event, which modifies cells' Locked state, which triggers the Worksheet_Change event, which modifies cells' Locked state, which triggers the Worksheet_Change event, which... which eventually blows the call stack.
So prevent this accidental recursion, you need to prevent Excel from firing worksheet events when you're handling one:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo CleanFail
Application.EnableEvents = False
'do stuff
CleanExit:
Application.EnableEvents = True
Exit Sub
CleanFail:
'handle errors here...
Resume CleanExit
End Sub
As for simplifying the code, that's more of a mandate for Code Review Stack Exchange, once your code works as intended.
If any C# dev is reading this, this particular situation now has an up-for-grabs issue on Rubberduck's GitHub repository: #3109 Prevent accidental recursion in Worksheet_Change and Workbook_SheetChange handlers; once that inspection is implemented, Rubberduck will be able to warn you when you handle Worksheet_Change without disabling application events.
The Out of stack error is caused by the Change event, as noted by #Mat
Try this version which also turns the events off and on
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cellule As Range, r As Long, isVrai As Boolean
ActiveSheet.Unprotect "Francis"
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
For Each cellule In Union(Range("I50:J50"), Range("S50:X50"))
With cellule
Select Case .Value2
Case "1": .EntireColumn.Hidden = False
Case "0": .EntireColumn.Hidden = True
End Select
End With
Next
For r = 16 To 44 Step 2
isVrai = (Range("AR" & r).Value2 = "Vrai")
Range("K" & r).Locked = Not isVrai
Range("O" & r).Locked = Not isVrai
If isVrai Then Range("AR" & r).ClearContents
Next
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
'ActiveSheet.Protect Password:="Francis"
End Sub
This section can be simplified:
For Each cellule In Range("S50:X50")
If cellule.Value = "1" Then cellule.EntireColumn.Hidden = False
Next cellule
For Each cellule In Range("S50:X50")
If cellule.Value = "0" Then cellule.EntireColumn.Hidden = True
Next cellule
For Each cellule In Range("I50:J50")
If cellule.Value = "1" Then cellule.EntireColumn.Hidden = False
Next cellule
For Each cellule In Range("I50:J50")
If cellule.Value = "0" Then cellule.EntireColumn.Hidden = True
Next cellule
To the following (however, note that this will unhide any non-zero values).
For Each cellule in Range("S50:X50")
cellule.EntireColumn.Hidden = (cellule.Value = "0")
Next
For Each cellule in Range("I50:J50")
cellule.EntireColumn.Hidden = (cellule.Value = "0")
Next
And this section:
If Range("AR16") = "Vrai" Then
Range("K16").Locked = False
Range("O16").Locked = False
Else:
Range("K16").Locked = True
Range("O16").Locked = True
End If
If Range("AR18") = "Vrai" Then
Range("K18").Locked = False
Range("O18").Locked = False
Else:
Range("K18").Locked = True
Range("O18").Locked = True
End If
....
Can be simplified using a loop over Range("AR16:AR44")
For Each cellule in Range("AR16:AR44") Step 2
cellule.Offset(,-33).Locked = (cellule.Value = "Vrai")
cellule.Offset(,-29).Locked = (cellule.Value = "Vrai")
Next
Related
I've written a pretty simple Word macro to hide different parts of a form based on a checkbox made at the beginning of the form. It's only working on some people's computers but not others - it's uploaded to our document server and then users download it out.
Specifically, affected users are able to click a checkbox and the macro will disable the other checkboxes, but the bookmarks remain visible. No error shows up, it just doesn't happen.
The file is downloaded correctly (.docm) and when I poke around in affected users' VBA code, nothing seems to be amiss. I haven't been able to replicate the error myself.
Below is the macro. Any help would be appreciated, as this supports a fairly important business process.
'Plan
Private Sub CheckBox1_Click()
If CheckBox2.Enabled = True Then
CheckBox2.Enabled = False
CheckBox3.Enabled = False
CheckBox4.Enabled = False
CheckBox5.Enabled = False
Else:
CheckBox2.Enabled = True
CheckBox3.Enabled = True
CheckBox4.Enabled = True
CheckBox5.Enabled = True
End If
Bookmarks("CAPA_Plan_And_Add").Range.Font.Hidden = CheckBox1.Value
End Sub
'Plan Addendum
Private Sub CheckBox2_Click()
If CheckBox1.Enabled = True Then
CheckBox1.Enabled = False
CheckBox3.Enabled = False
CheckBox4.Enabled = False
CheckBox5.Enabled = False
Else:
CheckBox1.Enabled = True
CheckBox3.Enabled = True
CheckBox4.Enabled = True
CheckBox5.Enabled = True
End If
Bookmarks("CAPA_Plan_And_Add").Range.Font.Hidden = CheckBox2.Value
End Sub
'Execution
Private Sub CheckBox3_Click()
If CheckBox2.Enabled = True Then
CheckBox1.Enabled = False
CheckBox2.Enabled = False
CheckBox4.Enabled = False
CheckBox5.Enabled = False
Else:
CheckBox1.Enabled = True
CheckBox2.Enabled = True
CheckBox4.Enabled = True
CheckBox5.Enabled = True
End If
Bookmarks("CAPA_Execution").Range.Font.Hidden = CheckBox3.Value
End Sub
'Extension
Private Sub CheckBox4_Click()
If CheckBox3.Enabled = True Then
CheckBox1.Enabled = False
CheckBox2.Enabled = False
CheckBox3.Enabled = False
CheckBox5.Enabled = False
Else:
CheckBox1.Enabled = True
CheckBox2.Enabled = True
CheckBox3.Enabled = True
CheckBox5.Enabled = True
End If
Bookmarks("CAPA_Extension").Range.Font.Hidden = CheckBox4.Value
Bookmarks("CAPA_Extension_2").Range.Font.Hidden = CheckBox4.Value
End Sub
'Cancellation
Private Sub CheckBox5_Click()
If CheckBox4.Enabled = True Then
CheckBox1.Enabled = False
CheckBox2.Enabled = False
CheckBox3.Enabled = False
CheckBox4.Enabled = False
Else:
CheckBox1.Enabled = True
CheckBox2.Enabled = True
CheckBox3.Enabled = True
CheckBox4.Enabled = True
End If
Bookmarks("CAPA_Cancellation").Range.Font.Hidden = CheckBox5.Value
Bookmarks("CAPA_Cancellation_2").Range.Font.Hidden = CheckBox5.Value
End Sub
'Effectiveness Check Yes
Private Sub CheckBox6_Click()
If CheckBox7.Enabled = True Then
CheckBox7.Enabled = False
Else:
CheckBox7.Enabled = True
End If
End Sub
'Effectiveness Check No
Private Sub CheckBox7_Click()
If CheckBox6.Enabled = True Then
CheckBox6.Enabled = False
Else:
CheckBox6.Enabled = True
End If
Bookmarks("Effectiveness_Check").Range.Font.Hidden = CheckBox7.Value
End Sub
Private Sub CheckBox9_Click()
End Sub
There are a few things wrong with this code logical & syntax wise.
Logical
Private Sub CheckBox1_Click()
If CheckBox2.Enabled = True Then
It doesn't make any sense to me why you are basing what checkboxes are Enabled based on a different checkbox than the one which was clicked; specifically without regard to the state of the checkbox that was clicked. This looks like an ugly work around for not understanding how to initialize and properly control event clicks.
Syntactically
An If Statement looks like this:
If condition Then
' Do something if true
End If
An If-Else statement is formatted like this:
If condition Then
' Do something if true
Else
' Do something else
End if
Labels, used in {On Error} Goto Label statements are formatted with a colon after a name
On Error GoTo ErrorHandler
' Some code that might produce an error
ErrorHandler:
' More code (to deal with errors)
So what you have is a normal If-Statement (without an Else component, since it has a colon after it Else:) which should enable all checkboxes.
If CheckBox2.Enabled = True Then
CheckBox2.Enabled = False
CheckBox3.Enabled = False
CheckBox4.Enabled = False
CheckBox5.Enabled = False
Else:
CheckBox2.Enabled = True
CheckBox3.Enabled = True
CheckBox4.Enabled = True
CheckBox5.Enabled = True
End If
[TL;DR]
Just remove the colon after the Else statements
I've created a yes no button that hides a bookmark, how can i add a second bookmark to the same yes no button. My Bookmarks name is TextToShow. i just want to add another bookmark to the same field.
Private Sub CheckBoxNo_Change()
Call ShowHideBookmark
End Sub
Sub ShowHideBookmark()
Dim Sterilisation As Range
Set Sterilisation = ActiveDocument.Bookmarks("TextToShow").Range
If CheckBoxNo.Value = True Then
With Sterilisation.Font
.Hidden = True
End With
With ActiveWindow.View
.ShowHiddenText = False
.ShowAll = False
End With
Else
With Sterilisation.Font
.Hidden = False
End With
With ActiveWindow.View
.ShowHiddenText = True
.ShowAll = True
End With
End If
End Sub
Sub ShowHideBookmark()
Dim Sterilisation As Range, Sterilisation2 As Range
Set Sterilisation = ActiveDocument.Bookmarks("TextToShow").Range
Set Sterilisation2 = ActiveDocument.Bookmarks("TextToShow2").Range
If CheckBoxNo.value = True Then
Sterilisation.Font.Hidden = True
Sterilisation2.Font.Hidden = True
With ActiveWindow.View
.ShowHiddenText = False
.ShowAll = False
End With
Else
Sterilisation.Font.Hidden = False
Sterilisation2.Font.Hidden = False
With ActiveWindow.View
.ShowHiddenText = True
.ShowAll = True
End With
End If
End Sub
Assuming (as per JK's approach) your second bookmarked range is named 'TextToShow2', try:
Private Sub CheckBoxNo_Change()
Application.ScreenUpdating = False
Dim bVal As Boolean: bVal = CheckBoxNo.Value
ActiveDocument.Bookmarks("TextToShow").Range.Font.Hidden = bVal
ActiveDocument.Bookmarks("TextToShow2").Range.Font.Hidden = bVal
ActiveWindow.View.ShowHiddenText = Not bVal
ActiveWindow.View.ShowAll = Not bVal
Application.ScreenUpdating = True
End Sub
I have a problem that is driving me nuts. It should be straightforward, because I have done it many times before, but for some odd reason it is not working now...
Background
I am doing a few checks on some columns. If a value in each of the columns is found to be True, then boolean markers will be switched to False.
There are 3x columns to check and 3x boolean markers.
At the end, I check status of these boolean markers and get an output.
Code
Dim TfPCheck as boolean
Dim CentreV as boolean
Dim FlaggedTasks as boolean
Dim AddtionalInfoCheck As Boolean
TfPCheck= True
CentreV = True
FlaggedTasks = True
AdditionalInfoCheck = True
With Worksheets("Admin")
For i = 7 To LR
If .Cells(i, 12) = "True" Then
TfPCheck = False
Exit For
End If
Next i
End With
With Worksheets("Admin")
For i = 7 To LR
If .Cells(i, 14) = "True" Then
CentreV = False
Exit For
End If
Next i
End With
With Worksheets("Admin")
For i = 7 To LR
If .Cells(i, 16) = "True" Then
FlaggedTasks = False
Exit For
End If
Next i
End With
If TfPCheck = True And CentreV = True And FlaggedTasks = True Then
AdditionalInfoCheck = True
ElseIf TfPCheck = False And CentreV = True And FlaggedTasks = True Then
addtionalInfoCheck = False
ElseIf TfPCheck = True And CentreV = False And FlaggedTasks = True Then
addtionalInfoCheck = False
ElseIf TfPCheck = True And CentreV = True And FlaggedTasks = False Then
addtionalInfoCheck = False
ElseIf TfPCheck = False And CentreV = True And FlaggedTasks = False Then
addtionalInfoCheck = False
ElseIf TfPCheck = False And CentreV = False And FlaggedTasks = True Then
addtionalInfoCheck = False
ElseIf TfPCheck = True And CentreV = False And FlaggedTasks = False Then
addtionalInfoCheck = False
ElseIf TfPCheck = False And CentreV = False And FlaggedTasks = False Then
addtionalInfoCheck = False
End If
MsgBox (AdditionalInfoCheck)
Am I doing something wrong? Because AddtionalInfoCheck comes back as True, when it shouldn't.
Thanks
I don't know if this is going to resolve your issue but it seems that all of your code can be boiled down to the following.
Dim TfPCheck As Boolean, CentreV As Boolean, FlaggedTasks As Boolean
Dim LR As Long, AdditionalInfoCheck As Boolean
With Worksheets("Admin")
LR = Application.Max(.Cells(.Rows.Count, "L").End(xlUp).Row, _
.Cells(.Rows.Count, "N").End(xlUp).Row, _
.Cells(.Rows.Count, "P").End(xlUp).Row)
TfPCheck = IsError(Application.Match(True, .Range(.Cells(7, "L"), .Cells(LR, "L")), 0))
CentreV = IsError(Application.Match(True, .Range(.Cells(7, "N"), .Cells(LR, "N")), 0))
FlaggedTasks = IsError(Application.Match(True, .Range(.Cells(7, "P"), .Cells(LR, "P")), 0))
End With
AdditionalInfoCheck = CBool(TfPCheck And CentreV And FlaggedTasks)
Use Option Explicit. AdditionalInfoCheck was spelled two different ways.
I was wondering if there was a way to optimize this set of code
Sub BBG_Transmital()
'Hides Sections Not Used in Expanded Form
Dim CollapseRange1 As Range
Dim CollapseRange2 As Range
'Set Which Range/Cell to Associate with Marked CheckBox
With ActiveDocument.Tables(3)
Set CollapseRange1 = .Rows(10).Range
CollapseRange1.End = .Rows(13).Range.End
End With
With ActiveDocument.Tables(3)
Set CollapseRange2 = .Rows(16).Range
CollapseRange2.End = .Rows(21).Range.End
End With
'If Box is Checked then CollapseRanges
If CheckBox1.Value = True Then
CollapseRange1.Font.Hidden = True
'If Box is Not Checked then UncollapseRange
Else
CollapseRange1.Font.Hidden = False
End If
'If Box is Checked then CollapseRanges
If CheckBox1.Value = True Then
CollapseRange2.Font.Hidden = True
'If Box is Not Checked then UncollapseRange
Else
CollapseRange2.Font.Hidden = False
End If
End Sub
I tried using
If CheckBox1.Value = True Then
CollapseRange1.Font.Hidden = True AND CollapseRange2.Font.Hidden = True
Else
CollapseRange1.Font.Hidden = False And CollapseRange2.Font.Hidden = False
But it didn't work. I was just wondering if I can shorten my IF statement into one rather then two.
Thanks!
Here is your same code... just condensed to remove unnecessary checks
Sub BBG_Transmital()
'Hides Sections Not Used in Expanded Form
Dim CollapseRange1 As Range
Dim CollapseRange2 As Range
'Set Which Range/Cell to Associate with Marked CheckBox
With ActiveDocument.Tables(3)
Set CollapseRange1 = .rows(10).Range
CollapseRange1.End = .rows(13).Range.End
Set CollapseRange2 = .rows(16).Range
CollapseRange2.End = .rows(21).Range.End
End With
'If Box is Checked then CollapseRanges
If CheckBox1.Value = True Then
CollapseRange1.Font.Hidden = True
CollapseRange2.Font.Hidden = True
Else 'If Box is Not Checked then UncollapseRange
CollapseRange1.Font.Hidden = False
CollapseRange2.Font.Hidden = False
End If
End Sub
Further condensing Wayne's answer:
This part:
'If Box is Checked then CollapseRanges
If CheckBox1.Value = True Then
CollapseRange1.Font.Hidden = True
CollapseRange2.Font.Hidden = True
Else 'If Box is Not Checked then UncollapseRange
CollapseRange1.Font.Hidden = False
CollapseRange2.Font.Hidden = False
End If
Can be written as:
CollapseRange1.Font.Hidden = CheckBox1.Value
CollapseRange2.Font.Hidden = CheckBox1.Value
Also note, If {boolean-expression} = True can always be rewritten as If {boolean-expression}, and If {boolean-expression} = False can always be rewritten as If Not {boolean-expression}.
I have written the below code to cycle through my worksheets as a kind of slideshow to use in a sales department. The code works perfectly when I step through in debug mode, however when I run the macro it only works intermittently, occasionally getting to the selecting of the worksheets without having reactivated the screen updating application function.
Here is the code I have created so far:
Sub Runshow()
Dim ws As Worksheet
On Error GoTo exit_
Application.EnableCancelKey = xlErrorHandler
For Each ws In ThisWorkbook.Worksheets
ws.Protect
Next
Application.DisplayFullScreen = True
Application.DisplayFormulaBar = False
ActiveWindow.DisplayWorkbookTabs = False
ActiveWindow.DisplayHeadings = False
ActiveWindow.DisplayGridlines = False
ActiveWindow.DisplayHorizontalScrollBar = False
ActiveWindow.DisplayVerticalScrollBar = False
Application.Calculation = xlManual
Let y = 0
Do Until y = 80
Application.ScreenUpdating = False
Workbooks.Open("c:\users\admin\downloads\crm.xlsx").Activate
Application.Calculate
ActiveWorkbook.Close savechanges = False
Application.ScreenUpdating = True
ThisWorkbook.Activate
Let x = 0
Do Until x = 23
For Each ws In ActiveWorkbook.Worksheets
ws.Select
Application.Wait (Now + TimeValue("00:00:10"))
x = x + 1
Next
Loop
y = y + 1
Loop
exit_:
For Each ws In ThisWorkbook.Worksheets
ws.Unprotect
Next
Application.DisplayFullScreen = False
Application.DisplayFormulaBar = True
ActiveWindow.DisplayWorkbookTabs = True
ActiveWindow.DisplayGridlines = True
ActiveWindow.DisplayHorizontalScrollBar = True
ActiveWindow.DisplayVerticalScrollBar = True
Application.Calculation = xlAutomatic
End Sub
I put together some simple code that does something similar, and works well. You can build out from here - ask any questions if there's anything you don't understand.
Sub Slideshow()
Dim ws As Worksheet
PrepareView True
For Each ws In ThisWorkbook.Worksheets
ws.Activate
Application.Wait (Now + TimeValue("00:00:10"))
Next ws
PrepareView False
End Sub
Function PrepareView(status As Boolean)
If status = True Then
ActiveWindow.DisplayWorkbookTabs = False
ActiveWindow.DisplayHeadings = False
ActiveWindow.DisplayGridlines = False
ActiveWindow.DisplayHorizontalScrollBar = False
ActiveWindow.DisplayVerticalScrollBar = False
ElseIf status = False Then
Application.DisplayFullScreen = False
Application.DisplayFormulaBar = True
ActiveWindow.DisplayWorkbookTabs = True
ActiveWindow.DisplayGridlines = True
ActiveWindow.DisplayHorizontalScrollBar = True
ActiveWindow.DisplayVerticalScrollBar = True
End If
End Function