Access to event command button event handlers in modules - vba

I have a work book with about 20 different work sheets, each sheet structurally identical to each other. Now, I've added a command button in each of the sheets and I am calling a sub on each of the different sheets when the respective button is clicked.
It works fine, but it's obviously terrible programming practice as I have 20 different sheets containing the following code:
Private Sub CommandButton1_Click()
If ActiveSheet.FilterMode <> True Then
Call AddEntry
Else
MsgBox "bla bla."
End If
End Sub
So my question, as an inexperienced VBA dev - what is the most elegant solution to call my sub on a button click? Ideally writing the code once in a module e.g.

instead of putting a command button in every sheet, just put only one button on the toolbar of excel

Related

Pause VBA Word macro, allow user to make a selection, and restart where it left off

I have a requirement for VBA script in Microsoft Word to pause so that the user can select text that will be copied to the clipboard so that it can exported to an Excel file. The user will make a number of selections and finally indicate he/she is done when the contents of the clipboard will be copied to a template Excel file.
I have the code working to copy each selection to the clipboard and then all rows to the Excel file. But I need assistence in figuring out how to pause the code to allow the user to make the selection and then restart the code to copy the selection to the clipboard. I am able to get the userform with toggle switch to switch states and labels when pressed. But have not figured out how to pause the VBA code to allow the user to navigate to the next section of the Word document for the next selection.
The Stakeoverflow question/answer below appears to address this requirement but I have not been able to get it to work. It appears that the code is incomplete.
Pause VBA macro, allow user to make a selection, and restart where it left off
Can someone provide example VBA code that accomplishes this?
Your assistence is much appreciated as I have been beating my head against the wall and it is starting to hurt!
There's no way in VBA to "pause" a macro. Code must run to completion... Unless there's a command for user input.
Input can be requested via the InputBox and MsgBox methods, but those block access to the document because they're modal. A UserForm, however, can be set to display as non-modal, meaning it stays on top, but doesn't block access to the document or the application features. Since you're already working with a UserForm, this can be implemented relatively easily.
In the small example below, the Continue button runs the code to perform an action on the user selection. When Done is clicked the entire code is exited and the form unloaded.
Code behind the user form
Option Explicit
Private Sub cmdContinue_Click()
Debug.Print Selection.Range.Text
End Sub
Private Sub cmdDone_Click()
Me.Hide
End Sub
Private Sub UserForm_Activate()
'Position the form near the top-left of the window
'So that the user can work with the document
Me.Top = Application.ActiveWindow.Top + 50
Me.Left = Application.ActiveWindow.Left + 50
End Sub
Code in a regular module
Option Explicit
Sub DisplayModeless()
Dim frm As frmModelessForInput
Set frm = New frmModelessForInput
frm.Show False 'Display as non-modal
Set frm = Nothing
End Sub

Excel VBA that reacts to an OLE Checkbox object being clicked also locks the keyboard - but why?

I have a checkbox "Check_Group" in a worksheet "FA 2.0 Pricing Worksheet". I have a subroutine defined in said worksheet that changes some values elsewhere when the user clicks on it:
Private Sub Check_Group_Click()
Active = ActiveSheet.Name
Sheets("FA 2.0 Pricing Worksheet").Activate 'This activate has to happen here because there are some steps in a different routine where this checkbox has to be clicked programmatically
If ActiveSheet.OLEObjects("Check_Group").Object.Value = True Then
Sheets("FA 2.0 Risk Checklist").Range("UI_GROUP_RISK").Value = "No"
Else
Sheets("FA 2.0 Risk Checklist").Range("UI_GROUP_RISK").Value = "Yes"
End If
Sheets(Active).Select
End Sub
This works like a charm, except I've noticed a particularly annoying side-effect - the keyboard seems to lock after you click on it!
I can click into cells and navigate around the sheet with no problem, but when I try to type into (an unprotected) cell it doesn't react to my key presses at all.
I have confirmed with the debugger that EnableEvents and ScreenUpdating are both on.
I can skirt around the issue by clicking to another tab and back - typing works as normal then... in the exact same cells where it failed to type before! I'd still like to find a solution rather than just this cheap workaround though.
This is in Excel 2016.
Why does my subroutine lock the keyboard?
There's no need to activate the sheet for your code to execute.
And, when you're in a sheet code module you can refer to the sheet using Me
Private Sub Check_Group_Click()
Me.Range("UI_GROUP_RISK").Value = IIf(Me.Check_Group.Value, "No", "Yes")
End Sub

Stop a do loop with a command button

I have a VBA excel userform that is misbehaving. Basically I want my code to pause until a command button on a userform is pressed. Any ideas?
In a module:
Public okayclicked as boolean
Sub MyThing
UserForm1.Show
Do Until okayclicked
DoEvents
Loop
UserForm1.Hide
End Sub
In my userform:
Sub CommandButton1_Click()
okayclicked = True
End Sub
Not sure what else to try to make this work. Any help is appreciated! Thanks!
'module
Sub MyThing1
UserForm1.Show
End Sub
Public Sub MyThing2
'....rest of code
End Sub
'userform
Sub CommandButton1_Click()
MyThing2
Me.Hide
End Sub
Either use a MsgBox to ask for the user input, or set your form to be Modal (MSDN link).
A Modal form will allow you to continue to work in the form, and any code underlying the form will continue to run, but the main code that calls the form will be 'blocked'.
Should the underlying Excel sheets be modified during the period of pause, you can add code when the button press is detected (i.e. when the Form is closed or then the MsgBox OK button is pressed) to update the relevant parts of the Form.
But we have digressed from the original simple question and many other factors (such as how the underlying sheets will be modified when the form is open) come into play.
Consider if a change in the underlying sheet has to change the form immediately or if it can occur when the user resumes the form/code.
Consider if the functions you want can be done natively in the spreadsheet and minimise the use/functionality of the form.
Consider other event driven options where the code is broken into natural sections, functions, subroutines or modules and each section only runs when triggered by the right event (sheet change, user input, subroutine finished, form exit etc.)

Running Macros from Toolbar/Running one macro from another

I am trying to develop a macro for a publisher document. This macro will, when run, show a pop-up allowing the user to select one of three types of clients, and add different bullet points to a text box depending on which option was selected. I'm having two different problems which I suspect are coming from the same source. Problem number one is that I can't get the button on my User Form to run a different macro when the button is clicked. Problem two is that I've added my macros to one of the toolbars, and nothing happens when I click on them. In both cases, it's simply not running the macro. What am I doing wrong?
UserForm1
Private Sub CommandButton1_Click()
Application.Run ("ShapeTest")
End Sub
Private Sub UserForm_Initialize()
With ListBox1
.AddItem ("Federal")
.AddItem ("State")
.AddItem ("Local")
End With
End Sub
ThisDocument
Private Sub GenerateStatement()
UserForm1.Show
End Sub
Private Sub ShapeTest()
MsgBox ("Hello!")
Application.ActiveDocument.Pages(1).Shapes(1).TextFrame.TextRange.InsertAfter`enter code here`(Chr(13) & "My Text")
End Sub
Why are you using Application.Run("ShapeTest") rather than simply ShapeTest?
I don't have enough information to be 100% sure, but the following should work: To make ShapeTest callable from the userform you do two things:
1) Move it from ThisDocument to a general code module (first Insert/Module in the editor).
2) Eliminate the word Private in front of Sub ShapeTest()-- you don't want this to be a private sub since you want code outside of the module to be able to use it.
On edit: Alternatively -- you could keep ShapeTest() where it is in ThisDocument, get rid of the Private qualifier and in the userform code refer to ShapeTest as ThisDocument.ShapeTest. I prefer using the first method since I tend to like to keep as much code as possible in general code modules (reserving things like ThisDocument for event handlers) but OTOH my VBA experience is mostly Excel with a smattering of Word and there might be reasons to keep the code in ThisDocument in Publisher. I don't know Publisher, but a problem that I have run into in Word at times is I have sometimes accidentally put code in the Normal template that I wanted to go in the document's project. If something similar is possible in Publisher you should double check where your code is living.

Userform.Show on a form button will not recognize userform, getting Error 424

I know very little about VBA, but I'm trying to design a userform for an excel workbook. The idea is click the button, bring up the userform, enter info, hit OK, and your info is formatted correctly and inserted into the worksheet.
I have 3 userforms that all work fine, but any macro I create that references one of them just does not recognize that that particular userform exists.
The code I'm having a problem with is pretty straightforward:
Private Sub LiquidFormButton_Click()
LiquidEntryUserform.Show
End Sub
Edit (Update): So I tried making a new userform, with a different name. I copied and pasted all of the controls from the object over to the new userform, changed the name of the macro to bring up the userform, and voila, it works. However, now the userform itself doesn't do anything because none of the controls actually have any codes behind them telling them what to do. That's fine, I'll just copy over the codes from the broken form and BOOM now it doesn't work. Soooo something in the very very simple coding within the userform itself is preventing it from being shown, even though the new userform AND the broken one both, in fact, do everything else they need to do besides show up. I'll post the full userform code up later on after some dabbling. Thank you!
You should 'instantiate' the form like so
Private Sub LiquidFormButton_Click()
Dim liquid as LiquidEntryUserform ' define a liquid var of the correct type
Set liquid = new LiquidEntryUserform ' create the Form
liquid.Show 'show it
' here you can still access variables
' on the form
If liquid.TextBox1.Text = "700" Then
'do things
End if
End Sub
My project looks like this:
You can use the Object Browser (View|Object Browser or hit F2) to find the Forms and Classes you have in your project:
I had a similar experience after making some changes to a UserForm. I noticed something was actually working immediately prior to the 424 error occurring. Using F8 to step thru my code, it turned out I was asking a control to be configured - that I had deleted!!
I was using this code in the MS XL Objects worksheet (the button is on the associated worksheet)...
Private Sub cmdTransactions_Click()
frmTransactions.Show
End Sub
to bring up the UserForm and this code in the Forms module...
Private Sub UserForm_Initialize()
: : :
Row_Number = [mostrecent].Value
Cells(Row_Number + 1, 2).Select <<< this bit was happening (.Select works for me!!)
: : :
cmdReset.Enabled = False <<< a control in the UserForm
chkDeposit.Enabled = False <<< this control had been deleted!! Remarked out but un-Remarked for clarity
: : :
End Sub
Hope that might help someone.