I used code provided on Creating form programmatically in the module using vba to create the dynamic form, everything works great for the most part, however, the only way I can close the form is using the red "X" in the corner and I want to be able to close it with a button.
I have tried using the simple Unload UserForm1 and tried to call the UserForm_QueryClose command as well, but nothing seems to work. I have also tried ThisWorkbook.VBProject.VBComponents.Remove ("UserForm1"), but I push the button and nothing happens.
This creates the form:
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(3)
'Create the User Form
With myForm
.Properties("Width") = 270
.Properties("Height") = 376
End With
This creates the command button:
'Create CommandButton Create
Set NewButton = myForm.designer.Controls.Add("Forms.commandbutton.1")
With NewButton
.Name = "cmd1"
.Caption = "Ok"
.Accelerator = "M"
.Top = 100
.Left = 200
.Width = 66
.Height = 20
.Font.Size = 8
.Font.Name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
This fills out the code in the form:
'add code for Command Button
myForm.CodeModule.InsertLines 16, "Private Sub cmd1_Click()"
myForm.CodeModule.InsertLines 17, "Unload UserForm1"
myForm.CodeModule.InsertLines 18, "End Sub"
I expect the form to unload once the button is pushed and move on to the next procedure, but nothing happens. I have tested other commands when hitting the button and it seems to work, but I just can't get it unloaded without pushing the red "X".
Related
I have code from this website:
Sub addLabel()
UserForm4.Show vbModeless
Dim theLabel As Object
Dim labelCounter As Long
For labelCounter = 1 To 3
Set theLabel = UserForm4.Controls.Add("Forms.Label.1", Cells(i, 1) & labelCounter, True)
With theLabel
.Caption = "Test" & labelCounter
.Left = 10
.Width = 50
.Top = 10 * labelCounter + 10
End With
Next
End Sub
This code is in a worksheet module.
It works, but when I open the form once more, it shows nothing. So, when I press f5, the form loads, but is blank.
There is no code in userForm4 events , so there wont be any answer by run nothing.
your code is a module and when you open module Sub addLabel() and run it , it will be show what you want.
you can write any code on UserForm_Click() or whatever you need to run on form events.
i'm making a code for Excel that opens every file in a specific folder. When the file is open I like to add a button to each of these files at the same location. I made this code shown as below. but somehow I get this error:
Run-Time Error '1004': Unable to get the Add property of the
OLEObjects class
The code breaks on the line where it says: set addbutton = etc...
Does anyone know why?
My Code:
Dim AddButton As OLEObject
Set AddButton =
Workbooks(ThisWB).Sheets("Planning").OLEObjects.add(ClassType:="Forms.CommandButton.1", Link:=False,
DisplayAsIcon:=False, Left:=3.52941176470588, Top:=106.764705882353,
Width:=47.6470588235294, Height:=24.7058823529412)
With AddButton
.Name = "SortPlanner"
.OnAction = "SortPersonalPlanner"
With .Object
.Caption = "Sorteren"
.BackColor = &HFFFFFF
End With
End With
You can do something like this, use .Buttons.Add instead of .OLEObjects.add
Set AddButton = Workbooks(ThisWB).Sheets("Planning").Buttons.Add(3.53, 106.76, 47.65, 24.71)
With AddButton
.Characters.Text = "Sorteren"
.Font.Bold = True
.OnAction = "SortPersonalPlanner"
End With
I want to bind an event to a button in runtime using Excel VBA. Is there a method to create it like button.Click += button_Click in C#?
This routine adds a button and a button click event at run time to a already existing Userform1. Note you need to set a reference to Microsoft Visual Basic For Applications Extensibility 5.3 (Tools | References)
Sub AddControlDynamically()
Dim vbCompFrm As VBComponent
Dim objButton As Object
'Edit "Userform1" in the following line to your Userform name
Set vbCompFrm = ThisWorkbook.VBProject.VBComponents("Userform1")
'Following line creates a command button on the form
Set objButton = vbCompFrm.Designer.Controls.Add("Forms.CommandButton.1")
With objButton
.Name = "cmdButton1" 'Can use this name for the Add event sub
.Left = 10
.Top = 10
.Height = 20
.Width = 80
.Caption = "My Button"
End With
With vbCompFrm.CodeModule
.InsertLines .CountOfLines + 1, "Private Sub cmdButton1_Click()"
.InsertLines .CountOfLines + 1, " MsgBox ""Hello World!"""
.InsertLines .CountOfLines + 1, "End Sub"
End With
End Sub
I have macro assigned to a rectangle shape that goes to the next sheet in my workbook.
I'm trying to add a press down and up effect to this rectangle.
When I use this code, the rectangle is only pressed down then then the next sheet is activated, and if I returned back to the previous sheet, the rectangle is released.
Wht I need is that the rectangle is pressed down and then released before going to the next sheet.
Dim MyButton As Shape
Dim oHeight, oWidth, cHeight, cWidth As Double
Dim oTop, oLeft As Long
Public Sub PressButton()
Set MyButton = ActiveSheet.Shapes(Application.Caller)
With MyButton
'Record original button properties.
oHeight = .Height
oWidth = .Width
oTop = .Top
oLeft = .Left
'Button Down (Simulate button click).
.ScaleHeight 0.9, msoFalse
.ScaleWidth 0.9, msoFalse
cHeight = .Height
cWidth = .Width
.Top = oTop + ((oHeight - cHeight) / 2)
.Left = oLeft + ((oWidth - cWidth) / 2)
End With
'Set MyButton variable to Nothing to free memory.
Set MyButton = Nothing
End Sub
Public Sub ReleaseButton()
Set MyButton = ActiveSheet.Shapes(Application.Caller)
With MyButton
'Button Up (Set back to original button properties).
.Height = oHeight
.Width = oWidth
.Top = oTop
.Left = oLeft
End With
'Set MyButton variable to Nothing to free memory.
Set MyButton = Nothing
End Sub
Public Sub NextPage()
PressButton
Application.Wait (Now + TimeSerial(0, 0, 1))
ReleaseButton
Dim ws As Worksheet
Set ws = ActiveSheet
Do While Not ws.Next.Visible = xlSheetVisible
Set ws = ws.Next
Loop
With ws.Next
.Activate
.Range("A1").Select
End With
End Sub
You're better off using a 'Command Button': shapes and rectangle objects don't really support the event-driven 'On Click' functionality you need here: calling an associated macro is pretty much all that they do.
However, you may well be stuck with that shape as your interface (support for ActiveX command buttons is very poor in 64-bit environments), so here goes...
Background: how to make a button look like a button:
Most shapes have a 'Shadow' property, and an outside shadow cast by a light source from a 45-degree angle (from the top-left corner) gives a 'raised' effect. Conversely, an inside shadow cast from the opposite angle (from a light source off the bottom-right corner) gives a 'sunken' effect.
In practice, an inside shadow for both is good enough: just change the angle.
In VBA, the 'angle' of the light source for your shape's shadow is given as X and Y offsets, and 45 degrees corresponds to 1.14142:
Dim oShape As Excel.Shape
Dim oShadow As Excel.ShadowFormat
Set oShape = ActiveSheet.Shapes(i)
Set oShadow = oShape.Shadow
' Shadow cast by light from above-right at 45 degrees for a 'raised' effect:
oShadow.OffsetX = Sqr(2)
oShadow.OffsetY = Sqr(2)
' Shadow cast by light from above-right at minus 45 degrees for a 'sunken' effect:
oShadow.OffsetX = -Sqr(2)
oShadow.OffsetY = -Sqr(2)
...And that's the code for your click 'up' and click 'down' button state.
I Strongly recommend that you use the built-in dialogs to set the shape's fill colour and the shadow's size, transparency and blur. For your reference, the settings I use for a smart 'semi-flat' light grey button are listed below - but I do not recommend that you set them in VBA code, as these formats will not be applied in the order you expect, and the button will not look like the 'clean' shape you can build using the UI dialogs:
' Light-grey button with a slightly darker 'softened' border
oShape.Fill.ForeColor.RGB = &HD8D8D8
oShape.Line.ForeColor.RGB = &HC0C0C0
oShape.Line.Weight = 2
oShape.Line.Transparency = 0.75
' Use the shape's shadow to give a 'raised button' effect:
oShadow.Style = msoShadowStyleInnerShadow
oShadow.Visible = True
oShadow.Blur = 2
oShadow.Size = 100
oShadow.Transparency = 0.5
' Shadow cast by light from above-right at 45 degrees for a 'raised' effect:
oShadow.OffsetX = Sqr(2)
oShadow.OffsetY = Sqr(2)
You can also use the 3-D effects dialog, but this works by a 'chisel' effect for most shapes (including your rectangle): I haven't found any predefined 'raised' or 'sunken' three-D styles for shapes.
Major Edit:
Guess who's looking at the job of replacing all the Active-X control buttons on all the tactical spreadsheet tools before the 64-Bit Office rollout renders them inoperable?
So your question just became very, very interesting indeed. Here's what I'm doing about that:
Generic 'Button Click' code for using Excel 'Shape' objects to call a VBA Macro instead of ActiveX controls.
This is what I'm using instead of ActiveX buttons: text labels, rectangles and images, placed into the worksheet using the 'Insert' menu on the Ribbon.
These objects are all Excel 'Shapes', they can all be associated with a named macro, and they have a common 'shadow' effect that serves as a 'raised button' 3D effect.
The example below is a function call from an image (it's a 32*32 icon for a database, with a question mark) embedded as a shape on a worksheet. I gave this ersatz control button a meaningful name, and I named the macro [Name]_Click(), because I'm replacing the existing 'Click' event procedures.
So this macro is a public subroutine on a worksheet identified with a code name, - users can 'rename' the sheet, changing the user-readable label, but they won't rename the underlying VBA class module - and it's visible as MySheetCodeName.img_TestDefaultDSN_Click() in the 'assign macro' list when you right-click the shape.
..That's why it's Public (not Private, as the automatically-created event procedure stubs for ActiveX controls will be): private subs aren't visible in the 'Assign Macro' list.
Public Sub img_TestDefaultDSN_Click()
ClickDown Me.Shapes("img_TestDefaultDB")
ShowDBStatus "EOD_Reports_DSN"
ClickUp Me.Shapes("img_TestDefaultDB")
End Sub
This calls a pair of generic 'Click Down' and 'Click Up' subroutines, in a regular code module:
Public Function ClickDown(objShape As Excel.Shape)
On Error Resume Next
'Recast the button shadow from bottom-right to top-left:
With objShape.Shadow
.Visible = msoFalse
.OffsetX = -1.2
.OffsetY = -1.2
.Visible = msoTrue
.Blur = 1
.Size = 99
.Transparency = 0.75
.Style = msoShadowStyleInnerShadow
.Obscured = msoFalse
End With
'Darken the button face slightly:
If objShape.Type = msoPicture Then
With objShape.PictureFormat
.Brightness = .Brightness - 0.01
End With
Else
With objShape.Fill
.Visible = msoTrue
.ForeColor.Brightness = .ForeColor.Brightness - 0.01
End With
End If
End Function
Public Function ClickUp(objShape As Excel.Shape)
On Error Resume Next
'Restore the button face to it's default brightness:
With objShape.Shadow
.Visible = msoFalse
.OffsetX = 1.2
.OffsetY = 1.2
.Visible = msoTrue
.Blur = 1
.Size = 99
.Transparency = 0.75
.Style = msoShadowStyleInnerShadow
.Obscured = msoFalse
End With
'Restore the button shadow to bottom-right:
If objShape.Type = msoPicture Then
With objShape.PictureFormat
.Brightness = .Brightness + 0.01
End With
Else
With objShape.Fill
.Visible = msoTrue
.ForeColor.Brightness = .ForeColor.Brightness + 0.01
End With
End If
End Function
You may well have your own preferences for the appearance of a 'control button', but this works for me.
Note that the 'Click Down' effect is never seen if 'Click Up' follows immediately: nor even if a 'Sleep' or an 'Application Wait' statement separates them - you'll only see it if there's real code with a user-detectable elapsed time or a modal dialog.
Is it possible to use Private subs. You only need to change the way you call the subroutines. To call private sub, even located in another code module, you have to use:
Application.Run "[ModuleName.]MacroName"[, arg1] [,arg2...],
Everything is in details explained here:
https://wellsr.com/vba/2015/excel/3-ways-to-call-a-private-sub-from-another-module/
I am trying to create labels in a Frame during runtime with VBA. The problem is, I want to be able to click them once they are created. So this is what I made : (my labels are attached to a Frame)
Set TheLabel = Frame.Controls.Add("Forms.Label.1", Visible = True)
With TheLabel
.Name = "Label" & i
.Caption = gTab(i, 2) & "_ " & gTab(i, 0) & Temp
.Left = 6 + gTab(i, 2) * 12
.Top = 12 + 16 * i
.Height = 12
.Width = 200
End With
Where i is an integer (it's the number of the current label).
With this code, I imagine the name of my Label is now Label1, Label2 etc.
But even with this piece of code:
Private Sub Label1_Click()
Frame.Height = 200
End Sub
It doesn't seem to work.
Thanks a lot!
To add controls to a userform at runtime, with code behind the controls, see this answer and this one as well.