Selection.ShapeRange isn't working with ActiveX CommandButton - vba

Sub sampleButton_Click()
On Error GoTo ErrorHandler
With Selection.ShapeRange
If .Type = msoGroup Then
Call setStyleTest(.GroupItems(.GroupItems.Count))
Else
For Each shp In ActiveWindow.Selection.ShapeRange
Call setStyleTest(shp)
Next shp
End If
End With
Exit Sub
ErrorHandler:
MsgBox "Error", vbExclamation
End Sub
I use ActiveX CommandButton and have a problem with a testing selection of ShapeRange. What should I change/fix?
Thanks in advance

Problem Explanation
The CommandButton does not have the property ShapeRange
Hence, the error will always arise
In the other hand, if you change the object for a button -the one under form collection- you will not have that problem because that property exists in that object
Note that, even if they resemble in appearance, they are totally different objects, as such, one property may not exist in the other one or behave like in the other.
More info about what you can do -and how to do it- with this button can be found here
Solution/workaround
I can see that you are calling another sub to "personalize" the button created, since it is unknown, you would need to change in that according to the object in order to provide the desired format.
You would also need to invert the order in your code for the correct handling
...
If .Type = msoGroup Then
With Selection.ShapeRange
...
Further thoughts
I cannot possible think about a scenario where you would need to use active X instead of form button collection, so I would suggest to change all the buttons to that.

It is working just fine for me
The value of msoGroup is 6
Till the time the group is selected your code will work. Once you are out of design mode and the group is not selected, your code will not work.
And yes the above two command buttons are ActiveX and not Form Controls
My suggestion: Stick to Form controls.

Related

Excel VBA - Run-Time Error '424': Object Required

I have the following code for a Check Box (ActiveX Control) using Excel 2013:
Private Sub CheckBox1_Click()
If CheckBox1.Value = True Then
CheckBox2.Value = False
Else
CheckBox2.Value = True
End If
End Sub
Private Sub CheckBox2_Click()
If CheckBox2.Value = True Then
CheckBox1.Value = False
Else
CheckBox1.Value = True
End If
End Sub
What it does is simply uncheck Box 2 if I check Box 1, and vice versa. But if I use the above code for a Check Box (Form Control), I get a "Run-time error '424': Object required" error message. Does anyone know of a solution?
UPDATE: The same code above that I tried using in a file that I got from Bytes somehow worked. Since I'm a newbie in VBA, I think I'm gonna have to sit down and study how Excel, Macros & VBA work together. Once I find out the source of the problem (that technically I created myself), I'll post an answer here as to how I figured it out. Thanks to everyone that posted comments & replies. I really appreciate it!
There's a UX (user experience) issue here.
Checkboxes are for when you need the user to pick one or more values.
OptionButtons are for when you need the user to pick one of many mutually exclusive values.
So what you need is OptionButtons (ActiveX controls) - make sure they have the same GroupName, and you'll get the exact same behavior you're trying to achieve, without writing a single line of code:
And then in your VBA code you can access them all by their name (e.g. OptionButton1) to verify their value.
Form controls vs ActiveX controls
"Form Controls" are just shapes that you can assign to a macro (e.g. do something when the user clicks it) - you can't access them and their properties in code like you would with ActiveX controls.
With ActiveX controls you can access them as if they were global object variables, and do what you did:
CheckBox2.Value = True
The biggest hint you get, is IntelliSense: with ActiveX controls, when you type the dot (.) after the control's name, you get a dropdown in the editor, telling you that the VBE understands what you're talking about; when you do the same with a "form control", you don't get that dropdown, and the VBE does NOT understand what you're talking about - and if you persist and run that code, you'll run into run-time errors like you did.
You refer to a Form control by name or index into the Checkboxes collection:
Activesheet.CheckBoxes(1).Value
for example.
You use the incorrect Event listener. Try this
Private Sub CheckBox1_Change()
If CheckBox1 = True Then
CheckBox2 = False
Else
CheckBox2 = True
End If
End Sub
Here is the list event listeners for checkbox

VBA: Userform initialize method not being hit when userform initializes

My module code calling the userform:
PreInfo.Show
My userform code:
Public Sub PreInfo_Initialize()
Dim Invoice, Name, Model, Crank, MyValue1, StrokeL As Variant
'Dim ListBox1 As ListBox
Dim c As Range
Dim oneControl As Object
'Empty Text Boxes and Set Focus
For Each oneControl In PreInfo.Controls
Select Case TypeName(oneControl)
Case "TextBox"
oneControl.Text = vbNullString
'Case "ListBox"
'oneControl.AddItem "Test"
End Select
Next oneControl
With lbTest
.AddItem Item:="2 Cylinders" '3 different syntax used as test to isolate issue
.AddItem "3 Cylinders"
.AddItem ("5 Cylinders")
End With
Invoice.TextBox.SetFocus 'Activate?
End Sub
My module code does not trigger my userform initialize sub, therefore nothing in that sub runs. I cannot figure out why this is happening. I would greatly appreciate any help!
When this code runs, userform pops up, however none of the listbox items are added
Userform_Initialize event is triggered by a line like this called in a module:
Load Userform1
In order for it to be triggered again, you'll need to unload the userform (not simply hide it). This can be done either after the load call within the module:
Unload Userform1
Or anywhere within the Userform's code:
Unload Me
Notice that the events Initialize and QueryClose will be triggered by the Unload call as well (QueryClose is also triggered when the close button on the top right corner is pressed), so I really recommend you refrain from using Initialize. Instead, After the Load call, add the initialize code within the same module (or create a separate sub if it'll be called from multiple places).
Sub LoadThatUserform
Load Preinfo
'All textboxes are loaded with their value set to vbnullstring, _
unless you specified otherwise in the Properties box.
With ThatUserform.lbTest
'Answering this test
.AddItem Item:="2 Cylinders" 'Here you used the parameter name. _
It's entirely optional, which is why the one below _
also works. It's necessary, however, if you wanna skip _
an optional parameter on a procedure call.
.AddItem "3 Cylinders"
.AddItem ("5 Cylinders") 'This will theoretically create a _
run-time error: a procedure call either outside of a Call _
statement or not setting a value to a variable or property _
doesn't require parentheses.
End With
'After loading, show the form
Preinfo.Show
'Showing, if not as modeless, stops code execution for the user _
to make changes to the form. Once he presses a button _
or whatever, and the form is hidden, code will resume. _
After you grab every form data you need, just call Unload.
Unload Preinfo
End Sub
Last but not least, if you're running a Modeless form (let's code run in the background while showing), you'll need to use the Activate event for the code to run. The event sequence is:
Userform_Initialize, after Load Userform
Userform_Activate, after Userform.Show
Userform_QueryClose, after Unload Userform, pressing the closing "X" or terminating via closing Excel/Task Manager
Userform_Terminate, when it's really gonna end (though I have no clue how this is used).
I had the same problem, and found a very simple solution.
In your case, instead of using
Public Sub PreInfo_Initialize()
use
Public Sub UserForm_Initialize()
I have figured it out. Long story short, my Module needed the following code:
Userform.Userform_Activate 'THIS IS THE NEW CODE
Userform.Show 'existing code, unchanged
which signals the userform to activate before it is open (calling "initialize", then showing the userform for the user to alter).
Userform.Show SHOULD cue this activation sub to run, however mine was not for whatever reason. This fixes the issue until I determine why Userform.Userform_Activate was not called like it should have been.
I use userform.hide when the user clicks the "continue" button on the userform, which closes the userform and prints the userform inputs into a worksheet
What is happenening is that your userform is never unloaded from memory. Hide only removes it from view.
This means that it is only initialized the first time you run the userform within that Excel instance.
You can prevent this by using
unload me
or
End
instead of UserForm.Hide depending on your other code. You could also potentially use the UserForm_Activate method instead of UserForm_Initialize method.
To populate the ListBox, use:
lbTest.AddItem "3 Cylinders"
etc outside the With statement.
you have to keep syntax UserForm_Initialize() to make it happen
Cheers

Counting shapes by name in Visio

I want to count different types of shapes in my diagram, and I can't seem to get that done. I think I have to code something for that.
I use Visio 2007 for that.
I have a flow chart with mostly process shapes that I want to distinguish by name. E.g "Type A", "Type B". And at the end, I want to have a list that tells me how often I used Type A and Type B. Counting by hand will be to error prone.
I already checked out the report/statistic function (I'm using it in German, so I'm afraid I can't tell you the exact menu name), where you can define a report function by yourself, although that one misses features for my needs. I managed to make a report for my shapes, but only when they all are selected. But when the user has to select them by hand, then he can count them as well right from the start... And you have to make 4-5 clicks in order to get that static report result.
Another almost useful function I found was the layer method: Create a layer for the types I want to count, and then assign the shapes to that layer. But, again, this is too error prone. If the user misses a shape, the count will be wrong.
So I think I will need to code something with the VBA.
Additionally, I'd like to have a text field next to my diagram where the resulting counts for all types are always displayed. So that you see when you add a shape of Type A that the count goes up by one.
Could anyone help me on this?
try:
Option Explicit
Dim myShape As Shape
Sub ShapesDetails()
Call DeleteShapes(True)
ActiveSheet.Shapes.AddShape(msoShapeRectangle, 139.5, 81.75, 72, 72).Select
Selection.Name = "Rectangle"
ActiveSheet.Shapes.AddShape(msoShapeSmileyFace, 252.75, 71.25, 72, 72).Select
Selection.Name = "Smiley Face"
Application.CutCopyMode = False
Call ShapeDetails(True)
End Sub
Sub ShapeDetails(x As Boolean)
For Each myShape In ActiveSheet.Shapes
MsgBox "Shape name: " & myShape.Name & vbTab & " Shape type: " & myShape.Type
Next
End Sub
Sub DeleteShapes(x As Boolean)
For Each myShape In ActiveSheet.Shapes
myShape.Delete
Next
End Sub
Use Data= reports = advanced to configure a report to count objects with your custom shape Property (e.g. 'MIO') && exists. (Or another field, many to choose from). I set all the boxes i wanted to count to have property 'MIO'=TRUE, and then chose to display property Displayed Text. It takes some fiddling around in the Subtotals dialog and options in the next window to get the count looking nice. Leave COUNT unticked, and in the options dialog enable 'show all values' and tick 'exclude duplicate rows from group'.
Outputs as XML Excel Viso object. I know for the visio object, to update report, right click on it =Run report.
HTH

Provide a range selection tool/utility to the user in Excel VBA

I am trying to develop a user form in Excel 2007 VBA and want to provide a user with a range selection icon, something like this:
However, I have not been able to find any built-in form design tool or any online tool which provides this or at least gives me an idea. If anyone has any idea about this, I will greatly appreciate their help.
This control is called RefEdit control.
To use it, you have to first add it to the toolbox window by right-clicking in the toolbox window and selecting Additional Controls.... Then you select RefEdit.Ctrl and close the dialog.
Now you can select it in the toolbox and place it on your form.
Another alternative to using the RefEdit.Ctrl is to hook into some undocumented features of the TextBox control and use the Application.InputBox function.
There are two properties of the TextBox control that do not appear in the Properties dialog, that allow you to add a button on the right. They are DropButtonStyle and ShowDropButtonWhen. When the button is clicked it will fire the DropButtonClick event for the control where you can show the input box.
Start by placing a TextBox control on the form. Then add the following to the UserForm_Initialize procedure:
Private Sub UserForm_Initialize()
txtRefersTo.DropButtonStyle = frmDropButtonStyleReduce
txtRefersTo.ShowDropButtonWhen = frmShowDropButtonWhenAlways
End Sub
Then add an event handler to the DropButtonClick event as follows to capture the range using the Application.InputBox dialog:
Private Sub txtRefersTo_DropButtonClick()
Me.Hide
txtRefersTo.Text = Application.InputBox("Select the range", "Range Picker", txtRefersTo.Text, Type:=8)
Me.Show vbModal
End Sub
The main advantage to this approach is that it allows you to place a control within a frame or on a separate tab without experiencing the issues associated with the RefEdit.Ctrl. The disadvantage is that it requires a separate dialog to interact with Excel.
Although this question is already almost a decade old, it still came up as my first Google search result so I'm going to post an answer as another approach to consider. The InputBox with type set to cell reference might be sufficient for many people's needs. The InputBox type does the drudge work of validating the user's response. See this article for how to use the InputBox types: https://www.thespreadsheetguru.com/blog/vba-to-select-range-with-inputbox
I liked #krey answer which was basically a very simplified version of the link shared in #stifin answer --> https://www.thespreadsheetguru.com/blog/vba-to-select-range-with-inputbox
But both used "odd" names for the buttons and I think guides should use default names/values for easy understand and manipulation by end user. Additionally, I added a CommandButton to "run" the userform and a "select" statement for initial testing. I also wanted to provide an initial value as I try to pre-populate my userforms, but allow end user to override if needed.
Here is the final code snipppets utilizing a UserForm w/ one TextBox named TextBox1 (default) and one CommandButton named CommandButton1 (also default).
Option Explicit
Public rng As Range
Public Sub UserForm_Initialize()
Me.TextBox1.DropButtonStyle = fmDropButtonStyleReduce
Me.TextBox1.ShowDropButtonWhen = fmShowDropButtonWhenAlways
Set rng = Range("A1:B4")
TextBox1.Value = rng.Address(False, False)
End Sub
Public Sub CommandButton1_Click()
rng.Select
Unload Me
End Sub
Public Sub TextBox1_DropButtonClick()
Me.Hide
Set rng = Application.InputBox("Select the range", "Range Picker", TextBox1.Text, Type:=8)
TextBox1.Value = rng.Address(False, False)
Me.Show
End Sub

VBA Tab Key putting actual Tab Value in Text Box instead of navigating to next control

I have a VBA form (in Excel if that matters) that contains text boxes.
On three occasions, I have found myself pressing the tab key to navigate to the next control, but instead an actual TAB is being put in the text box.
The form normally acts as it should, but it does concern me that this gremlin is showing up sporadically.
It has shown up on Office 2003 as well as Office 2007 on two different computers.
Has anyone else encountered this problem and, if so, how did you fix it?
I was able to reproduce the problem 100% of the time by launching Excel, immediately pulling up the form, and holding down the tab key.
If I change any code at all in the form and resave the workbook, the problem goes away. I'm going to chalk this up to a fluke compilation error within VBA.
I created a form with three text boxes. I entered characters and tabbed onto the next for some time without being able to duplicate your problem.
The only way I can get an tab into the text box is by entering Ctrl+Tab. This might be embarrassing but backspace removes it so it is not a major issue. Is it possible that you are accidentally pressing Ctrl at the same time?
I find occasionally that if I mispress a key that the cursor jumps to somewhere else on the screen. I am not quite sure what I mean by "mispress"; it seems to be something to do with pressing two keys at once. This seems to be a feature of modern keyboards and how they detect which key has been pressed because I have encountered it on many different computers. The implication is that by mispressing a key, a control character (perhaps tab or ctrl+tab) is generated.
I also tried the following which worked and conceals the problem by removing the tab and moving on to the next control.
Private Sub TextBox1_Change()
If InStr(1, TextBox1.Text, Chr(9)) <> 0 Then
TextBox1.Text = Replace(TextBox1.Text, Chr(9), "")
TextBox2.SetFocus
End If
End Sub
As a quick work-around, use this code in the control's Exit event.
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
TextBox1.Text = VBA.Replace(TextBox1.Text, VBA.Chr(9), "")
End Sub
I have also had this behaviour in my coworkers' computer for several years now, while mine works fine. I have set all the Checkboxes TabStop property to False. It seems to work fine now.
Set the TabKeyBehavior property to False to get "Tab jumps to next field" behavior.
This might solve the problem:
Public Sub MoveFocusToNextControl(xfrmFormName As UserForm, _
xctlCurrentControl As control)
Dim xctl As control
Dim lngTab As Long, lngNewTab As Long
On Error Resume Next
' Move focus to the next control in the tab order
lngTab = xctlCurrentControl.TabIndex + 1
For Each xctl In xfrmFormName.Controls
lngNewTab = xctl.TabIndex
' An error will occur if the control does not have a TabIndex property;
' skip over those controls.
If Err.Number = 0 Then
If lngNewTab = lngTab Then
xctl.SetFocus
Exit For
End If
Else
Err.Clear
End If
Next xctl
Set xctl = Nothing
Err.Clear
End Sub