VBA userform listbox right click menu? - excel

I'm creating a userform in excel. I've created the form, I've populated it with data using a Listbox that reads from a range in excel.
Now I'm trying to add the ability to right click on a row in the Listbox and then perform an action on that line of data form there. Is this possible? I had assumed it was so I was planning on:
Creating a custom popup menu
Working on setting up some sort of event in the userform on right click
Everything else.
I'm stuck on step 1 above. I started by trying to create a custom right-click menu by using the code from Microsoft's website on "showpopup".
https://learn.microsoft.com/en-us/office/vba/api/office.commandbar.showpopup
Private Sub UserForm_Initialize()
Set myBar = CommandBars _
.Add(Name:="Custom", Position:=msoBarPopup, Temporary:=False)
With myBar
.Controls.Add Type:=msoControlButton, ID:=3
.Controls.Add Type:=msoControlComboBox
End With
myBar.ShowPopup
End Sub
This is my code currently, I created a new userform and just pasted the code verbatim from MS's website. When I run the code I get this error:
"Run-time error: '5': Invalid procedure call or argument"
This is the line that's causing the error:
Set myBar = CommandBars _
.Add(Name:="Custom", Position:=msoBarPopup, Temporary:=False)
I'm at a loss on what the error is. Am I on the wrong track here? Am I just doing this whole thing completely wrong?

The reason for the error is that the CommandBar already exists ... before the line that is erroring, add:
On Error Resume Next
CommandBars.Item("Custom").Delete
On Error GoTo 0
... you should also really run the same lines to delete the CommandBar when your UserForm is no longer in use, maybe in the Terminate event
... also your code, as it stands, shows the CommandBar immediately, you likely want to move the myBar.ShowPopup line elsewhere (eg to the appropriate event handler for the ListBox)

Related

Attempting to redraw Treeview, but Userform after Unload statement

I have a Userform setup to collect user input on creating a directory with subfolders and files. The input is through the use of a Treeview, and the file structure is predetermined with default selections Checked on or off. The user can toggle the creation of these subfolders and files to suit their needs. I added the options to "Select All" and "Clear All", something easy to do with Treeview Nodes.I also wanted to give users the option to restore the default selections. To that end, I added a "Default Selection" CommandButton that unloads the Userform and then load a fresh instance.
During testing, I noticed a strange bug in my code. There is a Msgbox that pops up to tell me that the script has worked without any errors. However, for every instance the user clicks "Default Selection", the Msgbox pops up that many more times. For example, if the user clicked "Default Selection" 3 times (I don't know why they would, other than being click happy and accident prone...), the Msgbox pops up 4 times; once for the successful test, and 3 more times for each time the button was clicked.
This is the Userform code stripped down to just a single CommandButton cmdDefaultSelect:
Option Explicit
Private Sub cmdDefaultSelect_Click()
'Reset default node checked values by reloading form
Unload Me
Call TestUnloadUserform
End Sub
...and here is the test module with the same symptoms:
Option Explicit
Public Sub TestUnloadUserform()
Dim frM As frmTest
Set frM = SetupTestFrm()
frM.Show vbModal
'Unload userform if it's already loaded
'This sub first loads the form
'Once the form is unloaded by cmdDefaultSelect_Click,
'the script continues to run from here, immediately
'after frM.Show
'If it's not unloaded here, then there is usually an error
If Not frM Is Nothing Then
Set frM = Nothing
End If
MsgBox _
Prompt:="Test complete.", _
Buttons:=vbOKOnly + vbInformation, _
Title:="Great Job"
End Sub
Public Function SetupTestFrm() As frmTest
Set SetupTestFrm = New frmTest
'In actual form, this is where the Treeview and Node properties are set
End Function
For a first draft, it works. The extra code is not included in this example, but the subfolder and files are created without an error. This was also the simplest solution I could come up with to essentially redraw the Treeview. However, I know I'm not loading/unloading my Userform correctly, and I'm probably going to run into trouble later on as I add more features. I don't want the script to end everytime the Userform is unloaded, but I'm unsure on how to structure the code between the Userform and standard modules.

Excel Crashes Intermittently When Clicking Macro Button in Rapid Succession

When a VBA macro button (not AcitveX button) is clicked in rapid succession Excel "sometimes" crashes.
The VBA code makes heavy use of object modules, so I was thinking it was a garbage collection issue. I explicitly set the top level object to nothing before exiting the button click macro thinking it would force a garbage collection. That did not work.
It is super frustrating because it is intermittent. Maybe 1 out of 10 to 20 times.
The code shown is just the button click handler. There is about 10,000 lines of code called from this handler, which I did not show. The VBA code reads information from the sheet, does some calculations, updates an excel chart on the sheet, and writes some data back to the worksheet. I do the usual turning off events and screen updates.
I am just hoping someone else has come up against the rapid macro execution causing excel to crash. Again, the VBA code runs fine, it appears to be a higher level excel issue?
Public Sub Clicked_UpdateWall_C()
Dim Wall As New CWall_C
Dim ExecutionSuccess As Boolean
Dim errstr As String
ExecutionSuccess = CheckUnits(ActiveSheet.Name, errstr)
If ExecutionSuccess Then ExecutionSuccess = Wall.UpdateWall(ActiveSheet.Name, errstr)
Call CheckError(ExecutionSuccess, errstr)
' This is an attempt to force excel to do garbage collection
Set Wall = Nothing
End Sub
The error message is "Excel has stopped working" not a VBA runtime error. One can click the "restart excel" button in the error dialog, and excel restarts and generally most of the time one does not lose work.
Since it is intermittent, I cannot post the exact excel crash dialog box text.
When a VBA macro button (not AcitveX button) is clicked in rapid succession Excel "sometimes" crashes.
A shot in the dark. Try this. Put your code in lieu of '~~> Rest of your code. Now no matter how many times you click in succession, nothing will happen.
Option Explicit
Dim DoNotRunProc As Boolean
Public Sub Clicked_UpdateWall_C()
If DoNotRunProc = True Then Exit Sub
DoNotRunProc = True
On Error GoTo Whoa
'
'~~> Rest of your code
'
Whoa:
DoNotRunProc = False
End Sub
Note: If you have a separate error handler in your code then adjust the above code accordingly.
I was able to resolve the issue by doing two things:
Switched from a "Button Form Control" to an "Command Button ActiveX Control." My hunch was that the ActiveX control is more robust in terms of handling rapid clicks. Turned out to be true.
Added the DoEvents function to the end of the Command Button ActiveX Control event handler. This pretty much eliminated the issue 99.9% unless someone is just being ridiculous clicking the button. The hunch here is that it gave Excel time to handle any outstanding events that perhaps were not handled properly due to rapid button clicks.
Thanks to all of you who responded with positive comments and suggestions.

UserForm error: Method 'Properties' of object '_VBComponent' failed

I want to edit my UserForm object in VBE with code.
When I use the following, I get an error as in post title:
Sub myTest()
ThisWorkbook.VBProject.VBComponents("UserForm1").Properties("Caption") = "myCaption"
End Sub
I tried changing "Caption" to "caption", the same error. Also this error happens when I try to set Width or Height properties, not always at first time, but when I run the code again to resize.
Edit 1:
"Trust access to the VBA project object model" in macro settings is enabled.
Edit 2:
Error does not happen when new workbook and UserForm are created. It does happen when UserForm is recreated in workbook in which an error already happened.
Edit 3:
Adding Unload UserForm1 or Set UserForm1 = Nothing before doesn't help.
Edit 4:
For new workbook, if I create UserForm and run this code from a module, but after right clicking on UserForm -> View Object, then I get an error: "Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus." When I confirm, on consecutive macro runs I'm getting an error as in post title.
Edit 5:
The same happens on Excel 2010 and 2016.
May simply try this
Sub myTest()
ThisWorkbook.VBProject.VBComponents("UserForm1").Activate
ThisWorkbook.VBProject.VBComponents("UserForm1").Properties("Caption") = "myCaption"
End Sub
It is working in Excel 2007 and expect to work in any version.
May Please refer my Answer to Post After Import of a Userform into VBComponents Properties cannot be read

Store location of command button cell address to variable in VBA

Okay so I'm using Excel and trying to get a cell address based off the location of the command button I'm clicking. I want to store that cell address in a variable as I click the button to be used in the next code for the user form that pops up as a result of clicking that button. Ive looked at this link: Store location of cell address to variable in VBA , which is similar to what I'm trying to do but I cant seem to get it to work with the ActiveSheet.Shapes(Application.Caller).TopLeftCell.Address that gives an address based off the top left corner of the command button. I'm trying to do it this way so I can use the same code from the next part for every similar button I add without having to manually change the code based off where the button is.
I'm pretty new when it comes to Excel and VBA so any help would be appreciated.
Edit:
I tried adding the code but I'm getting a Runtime error '1004' Unable to get Buttons property of the Worksheet class. I have this
Sub Button2_Click()
Dim BtRng As Range
Set Btnrng = ActiveSheet.Buttons(Application.Caller).TopLeftCell
MsgBox Btnrng.Address
Btnrng.Offset(3, 3) = "Hello"
formAddBill.Show
End Sub
This button is also popping up a userform for information input. the error is happening on Set Btnrng = ActiveSheet.Buttons(Application.Caller).TopLeftCell
If you are using application.caller then I assume your buttons are from the forms.control toolbox. This makes life a lot easier.
Assign each button with this code example:
Sub Rng_Butn_Clicked()
Dim BtRng As Range
Set Btnrng = ActiveSheet.Buttons(Application.Caller).TopLeftCell
MsgBox Btnrng.Address
Btnrng.Offset(3, 3) = "Hello"
End Sub
If you are using command buttons from the activex toolbar, it can get a bit confusing. Doing it one at a time is easy enough
Private Sub CommandButton1_Click()
Me.CommandButton1.TopLeftCell.Offset(0, 1) = "Hi"
Me.CommandButton1.TopLeftCell.Offset(, 2).Interior.Color = vbBlue
MsgBox Me.CommandButton1.TopLeftCell.Address
End Sub
But assigning one code to many activex command buttons is not as easy, I would prefer to use the Forms Buttons if you want to assign one code to many buttons.
Edit: If you are getting this error
You probably put the code in a command button. Please reread my answer.
This is what I am referring to:Form Controls & ActiveX Controls

Closing a form on initialize throws error

I'm trying to make a standardized process for updating a particular worksheet. I want no user control except for the functions I give them. To do that I have locked sheets and then forms that load with certain macros. One form is designed to remove data from the sheet. It works fine as written and tested, but I've tried to update it so that if you open it without any relevant data to remove, it spits out a dialogue box and then uses Unload Me to close the form. This closes the form but then excel throws an error:
Run-time error '91': Object variable or With block variable not set
The form is loaded from a module that only has the one line:
MyForm.Show
This is where excel is throwing the error from. On initialization of the form, a combobox is filled with values based on the data in the sheet. If the combobox is empty after loading, the form is supposed to throw the dialogue box and then close.
If ComboBox.ListCount = 0 Then
MsgBox "No Data"
Unload Me
End If
How can I perform the check on load without having the error thrown from the Module?
This doesn't actually answer your question. But what I suggest is do the checking in your module code before you actually load the form. Something like:
Sub LoadForm()
If Sheets("Sheet1").Range("A1") = "" Then '<~~ your condition here
MsgBox "No Data"
Else
MyForm.Show
End If
End Sub
Another way would be to place the Unload Me in the Activate event:
Private Sub UserForm_Activate()
...
If ComboBox.ListCount = 0 Then
MsgBox "No Data"
Unload Me
End If
End Sub
The problem happens when you try and unload the userform from within it's initialize event. Because the object hasn't finished initialization yet, it cant be unloaded. The best ways to get around this are either to check conditions before you try to initialize the form, or put your checks and subsequent unload statements into the activate event of the userform. Activate is called whenever the form goes from being hidden to visible, which happens after the form has been completely initialized.
Sub RunForm()
On Error GoTo error
UserForm1.Show
error:
End Sub

Resources