Pausing VBA Code - vba

How can you pause a code from running and then allow it to continue again.

Using a ToggleButton in a Userform (which initiates your code and Modal = True)
You can successfully pause the code. With this you can then work in an additional selection to change the operation or function of the code via an addiotn button.
You will need to use public/global variables.
Comments Welcome.
Userform:
Public Sub ToggleButton1_AfterUpdate()
'Program is Paused / Selected to Pause
If ProgBar.ToggleButton1.Value = True Then
'Changing the Text of the Toggle button once the program is
'selected to Pause
'If program paused then button will display continue
ProgBar.ToggleButton1.Caption = "Continue"
'For Sending to Loop Code
ProgramStatus = "0"
Call LoopCode.PrgStat(ProgramStatus)
End If
'Program is running / Selected to run
If ProgBar.ToggleButton1.Value = False Then
'Changing the Text of the Toggle button once the program is selected to continue
'If program running then button will display pause
ProgBar.ToggleButton1.Caption = "Pause"
'For Sending to Loop Code
ProgramStatus = "1"
Call LoopCode.PrgStat(ProgramStatus)
End If
End Sub
In your Module
Public Status As String
Public Sub PrgStat(ByVal ProgStatus As String)
Status = ProgStatus
End Sub
Sub SomeSub()
Do While
' Some Loop Code Running
If Status = "1" Then
'Toggle Not Pressed
End If
If Status = "0" Then
'Toggle Button Pressed
Do While Status = "0"
'Program will stop here until the togglebutton on the
'userform is pressed again which changes Status = 1
'This is where you can make another selection on the
'userform
DoEvents
Loop
End If
Loop
End Sub

Related

Macro Freezes when ListBox is clicked

I'm using Office Professional Plus 2019. I have a ListBox that sometimes freezes the macro. The UserForm (AffDateSelector) has a ListBox (DateSelectionList) and a Button (Continue). The UserForm is called from the driving Sub with AffDateSelector.show. The code for the form is below:
Option Explicit
Private Sub Continue_Click()
Dim lngCurrItem As Long
'Assign the selected value to the public variable strClassDate.
For lngCurrItem = 0 To DateSelectionList.ListCount - 1
If DateSelectionList.Selected(lngCurrItem) = True Then
strClassDate = DateSelectionList.List(lngCurrItem)
End If
Next lngCurrItem
'Unload the form and return to the calling Sub.
Unload Me
End Sub
Private Sub DateSelectionList_Click()
End Sub
Private Sub UserForm_Click()
End Sub
Private Sub UserForm_initialize()
'Load ListBoxAccounts with the public variable strDateArray
With DateSelectionList
.List = strDateArray
End With
'Default the first row in DateSelectionList to be selected.
DateSelectionList.Selected(0) = True
End Sub
I've been using F8 to step through the code. When the form is shown, the UserForm_initialize() sub is executed and the data display properly. If the user does nothing else except click the Continue button, the Continue_Click() sub gets executed, the variable strClassDate is populated, control is returned to the calling sub and all is well.
The problem comes when the user selects an item other than the one defaulted in the list. Once the user clicks on the ListForm, the sub DateSelectionList_Click() is executed, but there's nothing in that sub, so the macro freezes. If I put in "dummy code" into DateSelectionlist_Click() (e.g. strClassDate = strClassDate) that line is executed and then the macro freezes when the End Sub statement is executed.
How can I allow the user to click on a non-defaulted item in the list, keep the form displayed, and wait for the Continue button to be pressed?
The code was fine. I had a lot of windows open and the pop-up didn't appear I was running the code from the VB editor but the pop-up never appeared. When I pressed Alt + Tab it didn't appear in that list either.

VBA loop through buttons on UserForm

I have not used VBA so quite new - but all searches have not given me the answer
its a simple question really. I have a group of buttons in an Excel Form.
The code is very similar when each one is pressed, and for each pressed button, I would like the colour of the button to change. So in reality, I have something like this for each button
UserForm2.CommandButton17.BackColor = RGB(255,255,0)
I would like to go through each button. Check if it is pressed, and then set the colour accordingly.
I actually want to say something like
for counter in 1 to 100
if (ispressed((CommandButton & counter )) then
I have found the following construct:
Dim ctrl as Control
For Each ctrl in UserForm1.Controls
ctrl.BackColor = RGB(255,0,0)
end for
this construct works - but I cant figure out how to check if the button is pressed.
Some of the answers show the above construct, with ctrl.Value = True
but those are for checkboxes and radio buttons. I don't even get the ctrl.Value option with buttons, so I can't use it anyway
Every example of code I have found glosses over this requirement.
Can someone help
Use a ToggleButton instead of a CommandButton if you want it to represent a state.
To initialize a state for each toggle button you can loop through the control.
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeName(ctrl) = "ToggleButton" Then
ctrl.Value = True 'set button state to pressed
End If
Next ctrl
This sets the state as pressed for every toggle button on the form.
Note that the .Value does not show up in the IntelliSense box because ctrl is of type Control which doesn't have a .Value. If you need IntelliSense then you could workaround like that:
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeName(ctrl) = "ToggleButton" Then
Dim tggl As ToggleButton
Set tggl = ctrl
tggl.Value = True
End If
Next ctrl
// Edit
Everytime a toggle button gets clicked it triggers a _Click event for that button. So you will need such an event for each button.
Private Sub ToggleButton1_Click()
With Me.ToggleButton1
If .Value = True Then
.BackColor = RGB(255, 0, 0)
Else
.BackColor = -2147483633 'switch to original color
End If
End With
End Sub
Or if you have many buttons, do it more efficiently
'this procedure handles all buttons
Private Sub ToggleButtonClick(ByRef tggl As ToggleButton)
With tggl
If .Value = True Then
.BackColor = RGB(255, 0, 0)
Else
.BackColor = -2147483633 'switch to original color
End If
End With
End Sub
'so you just need to call that function on every _Click event
Private Sub ToggleButton1_Click()
ToggleButtonClick Me.ToggleButton1
End Sub
Private Sub ToggleButton2_Click()
ToggleButtonClick Me.ToggleButton2
End Sub
But you still need a _Click() event for every button to call that procedure.
You can also evaluate the .Value state of each button in the _Click() event to set/unset your asterisk.
I think that the best thing is to work with event and to intercept Press Button
in defining Click() event for all buttons like this
'Form variable to define at begin on code
Dim pbPressed as Control
Dim pbLastPressed as Control
Private Sub pbButton(X)_Click()
'restore previous color only to last pressed
Set pbLastPressed.BackColor = RGB(0,0,155)
Set pbPressed = pbButton(X)
'assign color-pressed to button pressed
pbPressed = RGB(255,0,0)
End sub
where (X) must be replaced by a number as 1 or 2 or 10 !
You can make a fonction, and you obtain
Private Sub pbButton1_Click()
Call ChangeButtonsColor(pbButton1)
End Sub
Private Sub pbButton2_Click()
Call ChangeButtonsColor(pbButton2)
End Sub
Private Sub pbButton3_Click()
Call ChangeButtonsColor(pbButton3)
End Sub
Private Sub ChangeButtonsColor(pb as Button)
'restore previous color only to last pressed
Set pbLastPressed.BackColor = RGB(0,0,155)
Set pbPressed = pb
'assign color-pressed to button pressed
pbPressed = RGB(255,0,0)
End sub
Don't forget to add other event as KeyPress() that can make same action than clicking the Button.
If you have more than 10 buttons, you can perhaps create the buttons dynamically.
I would suggest to implement a class named TglBtn like that
Option Explicit
Private WithEvents m_ToggleButton As MSForms.ToggleButton
Private Sub m_ToggleButton_Click()
With m_ToggleButton
If .Value Then
.BackColor = RGB(255, 255, 0)
Else
.BackColor = &H8000000F
End If
End With
End Sub
Public Property Set Btn(tb As MSForms.ToggleButton)
Set m_ToggleButton = tb
End Property
In the Userform you can use the following code
Option Explicit
Dim mTgBtns As Collection
Private Sub UserForm_Initialize()
Dim sngControl As MSForms.Control
Dim mTglBtn As tglBtn
Set mTgBtns = New Collection
For Each sngControl In Me.Controls
If TypeName(sngControl) = "ToggleButton" Then
Set mTglBtn = New tglBtn
Set mTglBtn.Btn = sngControl
mTgBtns.Add mTglBtn
End If
Next sngControl
End Sub
When you click on one of togglebuttons on your userform the class will take care of the background color.
EDIT
If you want to access the caption of the Togglebutton you could add the following property to the class
Public Property Get Caption() As String
Caption = m_ToggleButton.Caption
End Property
EDIT2
Just as an example of using the property, you could change the Click event as below and everytime you click a MsgBox with the caption of the button will appear
Private Sub m_ToggleButton_Click()
With m_ToggleButton
If .Value Then
.BackColor = RGB(255, 255, 0)
Else
.BackColor = &H8000000F
End If
End With
MsgBox "You pressed the button with the caption " & Me.Caption
End Sub

Open UserForm, hide some command buttons in 1st page of multipages

I have a command button in excel that will open the userform
Sub openfile ()
UserForms1.Show
End Sub
Now, how do I hide the command button on first page of the form then unhide it when the next page is selected?
Place the following into your UserForm_Initialize....
Me.CommandButton1.Visible = False. Alternatively you can set the visible value of the button to false in properties window!
Then add this to the code for your UserForm
Private Sub MultiPage1_Change()
If MultiPage1.Value = 1 Then 'page values start with 0 as the first page
Me.CommandButton1.Visible = True
Else
Me.CommandButton1.Visible = False
End If
End Sub

Disable _Exit event when quitting userform using "Cancel" or "X-button"

I've got a code in a dropdown box on my userform. Every time the user moves away from the drop down box, the code checks whether the value put by the user is correct (i.e. matches a list). If it doesn't, it triggers a message box. Here is my code:
Private Sub CmboxModifyRoute_Exit(ByVal Cancel As MSForms.ReturnBoolean)
UserValue = CmboxModifyRoute.Value
counter = 0
Cell = Range("C15").Value
If UserValue = "" Then Exit Sub
Do While (counter < 35 And Cell <> UserValue) 'checking if UserValue is valid
counter = counter + 1
Cell = Range("C15").Offset(counter, 0).Value
Loop
If counter > 34 Then 'if invalid, then display message box
MsgBox "Invalid", vbExclamation
End If
End Sub
The problem occurs when I quit the userform with the "X" button or "Cancel" button. If the UserValue is invalid, it still shows me the "Invalid" message box after I have already quit the userform. I don't want it, I just want the userform to unload. How can I deal with this? Many thanks!
Change your condition to this:
If Me.Visible And counter > 34 Then
MsgBox "Invalid", vbExclamation
End If
Then the message will not be displayed if the form isn't visible.
Data Validation should go in the BeforeUpdate event of the combo box. Before Update won't trigger prior to the User Form's Terminate event. Add UserForm_Terminate and CmboxModifyRoute_BeforeUpdate events to your code, set breakpoints on the declaration of each, and watch the order of events happen in debug mode.
Private Sub CmboxModifyRoute_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
'data validation goes here
'doesn't fire when the form is closed
End Sub
Private Sub CmboxModifyRoute_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'this triggers before Terminate
End Sub
Private Sub UserForm_Terminate()
End Sub

Press other button2 when button 1 is pressed EXCEL VBA

I have 3 toggle buttons as shown in Excel VBA. First I press continuous then it will be pressed and start running macro. During that if I need to press Emergency button I need to do :
step1: Switch off Continuous button
step2 : Switch on Emergency Button
( manual is irrelevent here)
Currently when I try to do this, Emergency Stop cannot be pressed until macro of continuous ends.
I use this most of the time when I trying to say, scrape data from the net.
Option Explicit
Dim boolStop As Boolean
'~~> Continuous button
Private Sub CommandButton1_Click()
CommandButton1.Enabled = False
boolStop = False
For i = 1 To 1000000000
For j = 1 To 1000000000
Debug.Print i
DoEvents
If boolStop = True Then
Msgbox "Operation Paused by the User"
CommandButton1.Enabled = True
Exit Sub
End If
Next j
Next i
End Sub
'~~> Emergency button
Private Sub CommandButton3_Click()
boolStop = True
End Sub