excel vba userform enableevents - vba

I'm having a problem with Excel VBA UserForm Events in Office Excel 2013 as follows
Simple userform with three check boxes (CB1,2,3) and two buttons Cancel and OK
When checking CB1 set CB3 = false
When checking CB2 set CB3 = false
When checking CB3 set CB1 = false and CB2 = false
I have read and understood http://www.cpearson.com/excel/SuppressChangeInForms.htm regarding the suppression of UserForm Events and to part it works...
In the list above 2. and 3. above work correctly in code (shown below) and no-events are fired for CB3. However when I do 4. Check CB3 - it fires events for CB1 and CB2, even though I have set it to not fire events.
Any help gratefully received,
Best regards
Seán
Code:
Public EnableEvents As Boolean
Private Sub UserForm_Initialize()
Me.EnableEvents = True
End Sub
Private Sub vboInputsSelected_Click()
Me.EnableEvents = False
vboPracticesSelected.value = False 'this line does NOT fire an event
Me.EnableEvents = True
End Sub
Private Sub vboOutputsSelected_Click()
Me.EnableEvents = False
vboPracticesSelected.value = False 'this line does NOT fire an event
Me.EnableEvents = True
End Sub
Private Sub vboPracticesSelected_Click()
Me.EnableEvents = False
vboInputsSelected.value = False 'this line DOES fire an event
vboOutputsSelected.value = False 'this line DOES fire an event
Me.EnableEvents = True
End Sub

This works well for me. The If bails out when an event is in progress. Realize that the EnableEvents variable does nothing on its own to prevent events. It is only a boolean you created. You need to check it, before allowing an event to occur, for it to do anything.
Public EnableEvents As Boolean
Private Sub vboInputsSelected_Click()
If Not EnableEvents Then Exit Sub
Me.EnableEvents = False
vboPracticesSelected.Value = False
Me.EnableEvents = True
End Sub
Private Sub vboOutputsSelected_Click()
If Not EnableEvents Then Exit Sub
Me.EnableEvents = False
vboPracticesSelected.Value = False
Me.EnableEvents = True
End Sub
Private Sub vboPracticesSelected_Click()
If Not EnableEvents Then Exit Sub
Me.EnableEvents = False
vboInputsSelected.Value = False
vboOutputsSelected.Value = False
Me.EnableEvents = True
End Sub

According to this reference:
it's a better practice to work with a new instance of the class
Below trying to adapt the code:
'http://www.cpearson.com/excel/SuppressChangeInForms.htm
'https://riptutorial.com/vba/example/19036/best-practices
Private Type TView
IsCancelled As Boolean
EnableEvents As Boolean
End Type
Private this As TView
Public Property Get IsCancelled() As Boolean
IsCancelled = this.IsCancelled
End Property
Public Property Get EnableEvents() As Boolean
EnableEvents = this.EnableEvents
End Property
Private Sub UserForm_Initialize()
'...
this.EnableEvents = True
End Sub
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
On Error GoTo ExceptionHandling
this.EnableEvents = False
'some code that would cause an event to run
CleanUp:
On Error Resume Next
this.EnableEvents = True
Exit Sub
ExceptionHandling:
MsgBox "Error: " & Err.description & vbLf & Err.Number
Resume CleanUp
Resume 'for debugging
End Sub
Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
'check example
If this.EnableEvents = False Then Cancel = True
'some code to run
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
this.IsCancelled = True
Me.Hide
End If
End Sub
See Also
VBA UserForm – A Guide for Everyone, Paul Kelly

Related

How to call a userform's subroutine within a a separate module's subroutine with VBA

I am wondering how I can call a public subroutine that resides within a userform of two option buttons. Specifically if that user selections optionbutton1 from that userform is selected, then run some code from a sub routine within a module.
In the UserForm code:
Public Sub OptionButton1_Click()
Optionbutton1 = True
Optionbutton2 = False
End Sub
Public Sub OptionButton2_Click()
Optionbutton1 = False
Optionbutton2 = True
End Sub
Public Sub TextBox1_Change()
End Sub
In Module:
Global Optionbutton1 As Integer
Global Optionbutton2 As Integer
-------------------------------------------------------------
Sub ProjectSetup(Optionbutton1. Optionbutton2)
Call UserForm1.OptionButton1_Click
Call UserForm1.OptionButton2_Click
If OptionButton1 = True then
[do some action]
If OptionButton2 = True then
[do some action]
I think my issue is based on how I am trying to call in the subroutines "OptionButton1_Click" and "OptionButton2_Click" from UserForm1. When I run the code above I get a compiling error that states the function or sub not defined.
Thanks for any help!
This is not the right way to do whatever it is you're doing, but this would work.
In UserForm1:
Public Sub OptionButton1_Click()
gOpt1 = True 'setting the public globals declared in the calling module
gOpt2 = False
End Sub
Public Sub OptionButton2_Click()
gOpt1 = False
gOpt2 = True
End Sub
In a regular module:
Option Explicit
Public gOpt1 As Boolean
Public gOpt2 As Boolean
Sub Tester()
Dim frm As UserForm1
Set frm = New UserForm1
gOpt1 = False 'reset globals
gOpt2 = False
frm.Show vbModeless 'Must be modeless, or the code stops here
' until the form is closed
Debug.Print gOpt1, gOpt2 '> False, False
frm.OptionButton1_Click
Debug.Print gOpt1, gOpt2 '> True, False
frm.OptionButton2_Click
Debug.Print gOpt1, gOpt2 '> False, True
Unload frm
End Sub

Using VBA code to modify OptionButton.value is activating the control.Click() Sub

I have a userform with 2 OptionButton choices, and I'm modifying the form (hiding labels and controls, and resizing frame) for the default Option (name = BwaIsNew), but then restoring the full userform when Option #2 (name = BwaIsOld) is selected. (see separate question for background).
When Option #2 is selected I'm calling a fresh userform, and coding the change in value. But this coding of the value dlgInformation.BwaIsOld.Value = True then triggers an event (?) that calls the Sub BwaIsOld_Click() code to run. This then sets up a perpetual loop.
What's the best way to solve this?
Problem code (the one looping) is:
Private Sub BwaIsOld_Click()
Unload Me
dlgInformation.BwaIsNew.Value = False
dlgInformation.BwaIsOld.Value = True
dlgInformation.Show
End Sub
Update:
Thanks #Tim & #CommonSense. I'm still not quite there yet. What am I doing wrong? Here is the code
Public EnableEvents As Boolean
Private Sub UserForm_Initialize()
Me.EnableEvents = True
End Sub
Private Sub BwaIsNew_Click()
Call changeform(280)
End Sub
Private Sub BwaIsOld_Click()
Unload Me
Me.EnableEvents = False
dlgInformation.BwaIsNew.Value = False
dlgInformation.BwaIsOld.Value = True
Me.EnableEvents = True
dlgInformation.Show
End Sub
You need to actually use that EnableEvents in the rest of your code.
BTW I would choose a different name from the built-in Application.EnableEvents property just for clarity.
Public EnableEvents As Boolean
Private Sub UserForm_Initialize()
Me.EnableEvents = True
End Sub
Private Sub BwaIsNew_Click()
'don't respond to events triggered by BwaIsOld_Click
If Me.EnableEvents Then
Call changeform(280)
End If
End Sub
Private Sub BwaIsOld_Click()
Unload Me '<< why do this here?
Me.EnableEvents = False
dlgInformation.BwaIsNew.Value = False
dlgInformation.BwaIsOld.Value = True
Me.EnableEvents = True
dlgInformation.Show
End Sub

Replace auto filled text via userform

I've developed a user form for the letters we use at work that auto fill the document after required data has been entered.
At this current point in time - when you hit OK the data will be entered and the data will fill the form. Some users are just trying to keep entering information over the top of the already filled form and stacking previously entered data into the letter.
Question: How do I get the user form to replace entered data rather than add entered data.
So if I enter the name as John Wayne, complete my letter and decide to write another letter on the same open document - how do I reopen my macro, populate the data and then overwrite all the previous information of the previous letter.
Option Explicit
Private Sub CheckBox1_Click()
Dim en As Boolean
en = Not CheckBox1.Value
EnableControls Array(TBLPGN, TBLPFN), en
If CheckBox1.Value = True Then ComboBoxLodge.Value = "Applicant"
If CheckBox1.Value = False Then ComboBoxLodge.Value = "Lodging parent"
End Sub
'utility sub: enable/disable controls
Private Sub EnableControls(cons, bEnable As Boolean)
Dim con
For Each con In cons
With con
.Enabled = bEnable
.BackColor = IIf(bEnable, vbWhite, RGB(200, 200, 200))
End With
Next con
End Sub
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdClear_Click()
tbForm.Value = Null
tbFN.Value = Null
tbGN.Value = Null
tbDOB.Value = Null
cbLT.Value = Null
tbPN.Value = Null
tbissue.Value = Null
tbexpiry.Value = Null
tbLTD.Value = Null
tbNarrative.Value = Null
tbPRR.Value = Null
cbRecommendation.Value = Null
CheckBox1.Value = False
ComboBoxLodge.Value = Null
End Sub
Private Sub cmdOk_Click()
Dim useAforB As Boolean
useAforB = CheckBox1.Value
Application.ScreenUpdating = False
With ActiveDocument
.Bookmarks("Lodge").Range.Text = ComboBoxLodge.Value
.Bookmarks("Form").Range.Text = tbForm.Value
.Bookmarks("Form2").Range.Text = tbForm.Value
.Bookmarks("AGN").Range.Text = tbGN.Value
.Bookmarks("AFN").Range.Text = tbFN.Value
.Bookmarks("LGN").Range.Text = IIf(useAforB, _
tbGN.Value, TBLPGN.Value)
.Bookmarks("RGN").Range.Text = IIf(useAforB, _
tbGN.Value, TBLPGN.Value)
.Bookmarks("LFN").Range.Text = IIf(useAforB, _
tbFN.Value, TBLPFN.Value)
.Bookmarks("RFN").Range.Text = IIf(useAforB, _
tbFN.Value, TBLPFN.Value)
.Bookmarks("DOB").Range.Text = tbDOB.Value
.Bookmarks("LT").Range.Text = cbLT.Value
.Bookmarks("PN").Range.Text = tbPN.Value
.Bookmarks("PN2").Range.Text = tbPN.Value
.Bookmarks("PN3").Range.Text = tbPN.Value
.Bookmarks("PN4").Range.Text = tbPN.Value
.Bookmarks("Issued").Range.Text = tbissue.Value
.Bookmarks("Expiry").Range.Text = tbexpiry.Value
.Bookmarks("LTD").Range.Text = tbLTD.Value
.Bookmarks("LTD2").Range.Text = tbLTD.Value
.Bookmarks("Narrative").Range.Text = tbNarrative.Value
.Bookmarks("PRR").Range.Text = tbPRR.Value
.Bookmarks("Recommendation").Range.Text = cbRecommendation.Value
End With
Application.ScreenUpdating = True
Unload Me
End Sub
Private Sub Tbform_Change()
tbForm = UCase(tbForm)
End Sub
Private Sub Tbfn_Change()
tbFN = UCase(tbFN)
End Sub
Private Sub Tblpfn_Change()
TBLPFN = UCase(TBLPFN)
End Sub
Private Sub Tbpn_Change()
tbPN = UCase(tbPN)
End Sub
Private Sub UserForm_Initialize()
With cbLT
.AddItem "lost"
.AddItem "stolen"
End With
With cbRecommendation
.AddItem "I believe there is an entitlement to have the l/t flag turned off as the applicant has not contributed to the loss of Passport number: "
.AddItem "I believe there is no entitlement to have the l/t flag turned off as the applicant has contributed to the loss of Passport number: "
End With
With ComboBoxLodge
.AddItem "Lodging parent"
.AddItem "Applicant"
End With
With CheckBox1
CheckBox1.Value = True
End With
lbl_Exit:
Exit Sub
End Sub
Public Sub AutoOpen()
frmminute.Show
End Sub
Sub CallUF()
Dim oFrm As frmminute
Set oFrm = New frmminute
oFrm.Show
Unload oFrm
Set oFrm = Nothing
lbl_Exit:
Exit Sub
End Sub
Sub AutoNew()
CallUF
lbl_Exit:
Exit Sub
End Sub
new code currently getting a runtime error:
Private Sub CommandButtonOk_Click()
Dim useAforB As Boolean
useAforB = CheckBox1.Value
Application.ScreenUpdating = False
With ActiveDocument
Call UpdateBookmark("Title", ComboBoxTitle.Value)
Call UpdateBookmark("GN", TextBoxGN.Value)
Call UpdateBookmark("FN", TextBoxFN.Value)
Call UpdateBookmark("FN2", TextBoxFN.Value)
Call UpdateBookmark("Street", TextBoxStreet.Value)
Call UpdateBookmark("suburb", TextBoxSuburb.Value)
Call UpdateBookmark("postcode", TextBoxpostcode.Value)
Call UpdateBookmark("state", ComboBoxState.Value)
Call UpdateBookmark("street2", .Range.Text = IIf(useAforB, _
TextBoxStreet.Value, TextBoxStreet2.Value))
Call UpdateBookmark("Suburb2", .Range.Text = IIf(useAforB, _
TextBoxSuburb.Value, TextBoxSuburb2.Value))
Call UpdateBookmark("State2", .Range.Text = IIf(useAforB, _
ComboBoxState.Value, ComboBoxState2.Value))
Call UpdateBookmark("PostCode2", .Range.Text = IIf(useAforB, _
TextBoxpostcode.Value, TextBoxPostcode2.Value))
Call UpdateBookmark("CD", TextBoxCD.Value)
Call UpdateBookmark("MPN", TextboxMPN.Value)
Call UpdateBookmark("MPN2", TextboxMPN.Value)
Call UpdateBookmark("MPN3", TextboxMPN.Value)
Call UpdateBookmark("MPN4", TextboxMPN.Value)
Call UpdateBookmark("MPN5", TextboxMPN.Value)
Call UpdateBookmark("MPDD", TextBoxMPDD.Value)
Call UpdateBookmark("NPN", TextBoxNPN.Value)
Call UpdateBookmark("NPDD", TextBoxNPDD.Value)
End With
Application.ScreenUpdating = True
Unload Me
End Sub
Sub UpdateBookmark(BookmarkToUpdate As String, TextAtBookmark As String)
Dim BookmarkRange As Range
Set BookmarkRange = ActiveDocument.Bookmarks(BookmarkToUpdate).Range
BookmarkRange.Text = TextAtBookmark
ActiveDocument.Bookmarks.Add BookmarkToUpdate, BookmarkRange
After reading through your question, I realised what you wanted to do was updating the bookmark at the word document.
Private Sub cmdOk_Click()
Dim useAforB As Boolean
useAforB = CheckBox1.Value
Application.ScreenUpdating = False
Call UpdateBookmark("Lodge", ComboBoxLodge.Value)
Call UpdateBookmark("Form", tbForm.Value)
'Do for the rest.....
Application.ScreenUpdating = True
Unload Me
End Sub
Sub UpdateBookmark(BookmarkToUpdate As String, TextAtBookmark as string)
Dim BookmarkRange As Range
Set BookmarkRange = ActiveDocument.Bookmarks(BookmarkToUpdate).Range
BookmarkRange.Text = TextAtBookmark
ActiveDocument.Bookmarks.Add BookmarkToUpdate, BookmarkRange
End Sub

Show/hide control textbox

I am new to Visual Basic and I don't understand what object I need for this task.
I have 5 "control text boxes" that I want to hide show in Powerpoint. I have the following code and receive a 424 error:
Private Sub CommandButton1_Click()
Activesheet.oleobjects("TextBox2").Visible = False
Activesheet.oleobjects("TextBox9").Visible = False
Activesheet.oleobjects("TextBox8").Visible = False
Activesheet.oleobjects("TextBox7").Visible = False
Activesheet.oleobjects("TextBox6").Visible = False
End Sub
Private Sub CommandButton2_Click()
Activesheet.oleobjects("TextBox2").Visible = True
Activesheet.oleobjects("TextBox9").Visible = True
Activesheet.oleobjects("TextBox8").Visible = True
Activesheet.oleobjects("TextBox7").Visible = True
Activesheet.oleobjects("TextBox6").Visible = True
End Sub
PowerPoint doesn't have worksheets, so there's no Activesheet object. That'll trigger an error right off the bat. To simply toggle visibility, you can do this:
Sub ToggleVisibility()
With ActivePresentation.Slides(1)
.Shapes("TextBox1").Visible = Not .Shapes("TextBox1").Visible
.Shapes("TextBox2").Visible = Not .Shapes("TextBox2").Visible
' and so on
End With
End Sub

How to disable the save function

I currently have a macro which does data mining and saves the workbook in the end. I intend to disable to the save function of the workbook and force the user to use the macro everytime the workbook needs to be saved. This is what I have so far but it does not seem to work. When I do this, my macro and this sub described below are both running in a loop. every time my macro tries to save the workbook, this sub is not allowing it. I basically want to force the user to use the macro to save the workbook.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim NoSave
NoSave = MsgBox("Changes have to be submitted before the workbook can be saved, Proceed and submit ?", vbYesNo, "Continue?")
If NoSave = vbNo Then
Cancel = True
Else
Main
End If
End Sub
Here is an Example. Paste this in ThisWorkbook. This will not let you use the Save or the SaveAs. You can however use the macro SaveThisFile to save the workbook. Please amend it to suit your needs.
Option Explicit
Dim SaveByCode As Boolean
Const msg As String = "Please use the macro to save the file"
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Me.Saved = False And SaveByCode = False Then
MsgBox msg, vbExclamation, "Unable to save"
Cancel = True
End If
End Sub
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Application.EnableEvents = False
If SaveByCode = True Then
SaveThisFile
Else
MsgBox msg, vbExclamation, "Unable to save"
Cancel = True
End If
Application.EnableEvents = True
End Sub
'~~> Your macro to save the file
Sub SaveThisFile()
SaveByCode = True
ThisWorkbook.Save
End Sub
NOTE: If your Save macro is in a module then remove this Dim SaveByCode As Boolean from ThisWorkbook and place Public SaveByCode As Boolean in a module.
Alternative, how about this (I misunderstood the question at first, but also wanted to give it a try since it's interesting):
Declare public boolean (exceptional) in the thisworkbook module:
Option Explicit
Public bSave As Boolean
In the event BeforeSave event:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim sNoSave As String
If bSave = True Then
bSave = False
Exit Sub
End If
sNoSave = MsgBox("Changes have to be submitted before the workbook can be saved, Proceed and submit ?", vbYesNo, "Continue?")
If sNoSave = vbNo Then
bSave = False
Cancel = True
Exit Sub
Else
bSave = True
Call Main(bSave)
End If
End Sub
In Main:
Option Explicit
Sub Main(bSave)
If bSave = True Then
ThisWorkbook.SaveAs Filename:="U:\Book1.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
MsgBox "Main method called"
End If
End Sub