How to assign code to a dynamically created button? - vba

First of all: I am a beginner on VBA and I don't have a clue about how UserForms works.
That said I am trying to assing code to 3 dynamically created CommandButtons.
After some research come across this page and I just wrote a code to write the codes of the buttons. Problem is, I need to distribute this Workbook so this approach is not good anymore.
I reaserched a lot (1, 2, 3, 4) and came across this post. I tried to do the example that #SiddharthRout did but I was not sucessfull. I tried to understand how the ClassModule works but I couldn't (1, 2). I think a code just exactly the one #SiddharthRout would solve my problem but I can't manage to make it work on a normal module.
Long story short: I need a code to assing the codes to the CommandButtons without using extensibility (code that writes code).
EDIT
I want to create these buttons on a normal Sheet, not on a UserForm.

Read this:
http://scriptorium.serve-it.nl/view.php?sid=13
Sub MakeForm()
Dim TempForm As Object ' VBComponent
Dim FormName As String
Dim NewButton As MSForms.CommandButton
Dim TextLocation As Integer
' ** Additional variable
Dim X As Integer
'Locks Excel spreadsheet and speeds up form processing
Application.VBE.MainWindow.Visible = False
Application.ScreenUpdating = False
' Create the UserForm
Set TempForm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
'Set Properties for TempForm
With TempForm
.Properties("Caption") = "Temporary Form"
.Properties("Width") = 200
.Properties("Height") = 100
End With
FormName = TempForm.Name
' Add a CommandButton
Set NewButton = TempForm.Designer.Controls _
.Add("forms.CommandButton.1")
With NewButton
.Caption = "Click Me"
.Left = 60
.Top = 40
End With
' Add an event-hander sub for the CommandButton
With TempForm.CodeModule
' ** Add/change next 5 lines
' This code adds the commands/event handlers to the form
X = .CountOfLines
.InsertLines X + 1, "Sub CommandButton1_Click()"
.InsertLines X + 2, "MsgBox ""Hello!"""
.InsertLines X + 3, "Unload Me"
.InsertLines X + 4, "End Sub"
End With
' Show the form
VBA.UserForms.Add(FormName).Show
'
' Delete the form
ThisWorkbook.VBProject.VBComponents.Remove VBComponent:=TempForm
End Sub

This code from here:
Sub CreateButtons()
Dim arrNames As Variant
Dim arrCaptions As Variant
Dim Wkb As Workbook
Dim Wks As Worksheet
Dim NewBtn As OLEObject
Dim Code As String
Dim NextLine As Long
Dim LeftPos As Long
Dim Gap As Long
Dim i As Long
'The Workbook, where...
Set Wkb = ActiveWorkbook
'... the worksheet is, where the button will be created
' and code will be written.
Set Wks = Wkb.Worksheets(1)
'Commandbuttons' CODENAMES in array
arrNames = Array("cmbName1", "cmbName2", "cmbName3")
'Commandbuttons' captions in array
arrCaptions = Array("First Task", "Second Task", "Third Task")
'Button pos.
LeftPos = 100
Gap = 15
For i = LBound(arrNames) To UBound(arrNames)
'Add a CommandButton to worksheet
Set NewBtn = Wks.OLEObjects.Add(ClassType:="Forms.CommandButton.1")
'Set button's properties
With NewBtn
.Left = LeftPos
.Top = 5
.Width = 65
.Height = 30
.Name = arrNames(i)
.Object.Caption = arrCaptions(i)
.Object.Font.Size = 10
.Object.Font.Bold = True
.Object.Font.Name = "Times New Roman"
End With
'Add the event handler code
Code = "Sub " & NewBtn.Name & "_Click()" & vbCrLf
Code = Code & " MsgBox ""Hello...""" & vbCrLf
Code = Code & "End Sub"
'"Code" is a string
With Wkb.VBProject.VBComponents(Wks.CodeName).CodeModule
'Find last line in Codemodule
NextLine = .CountOfLines + 1
.InsertLines NextLine, Code
End With
'NEXT button's pos.
LeftPos = LeftPos + NewBtn.Width + Gap
Next i
End Sub

Related

Copy and paste large number of charts from Excel to PowerPoint via VBA

The task is to loop through an Excel workbook with multiple sheets and copy all the charts contained in the workbook into a PowerPoint presentation, one chart per slide and always the same layout.
Sub PPT_Example()
Dim pptApp As PowerPoint.Application
Dim pptPres As PowerPoint.Presentation
Dim sh As Worksheet
Dim ch As ChartObject
Set pptApp = New PowerPoint.Application
pptApp.Visible = True
Set pptPres = pptApp.Presentations.Add
pptPres.PageSetup.SlideSize = PpSlideSizeType.ppSlideSizeOnScreen16x9
For Each sh In ActiveWorkbook.Sheets
For Each ch In sh.ChartObjects
Dim pptSlide As Slide
Dim Title As Object
Dim Box As Object
Dim Txt As Object
Set pptSlide = pptPres.Slides.Add(pptPres.Slides.Count + 1, ppLayoutBlank)
ch.Copy
With pptSlide.Shapes.Paste
.Top = Application.CentimetersToPoints(3.3)
.Left = Application.CentimetersToPoints(0.76)
.Width = Application.CentimetersToPoints(16)
.Height = Application.CentimetersToPoints(10.16)
End With
'Insert Box
Set Box = pptSlide.Shapes.AddShape(Type:=msoShapeRectangle, _
Left:=Application.CentimetersToPoints(17.1), _
Top:=Application.CentimetersToPoints(3.3), _
Width:=Application.CentimetersToPoints(7.22), _
Height:=Application.CentimetersToPoints(9.29))
Prop_Box.Name = "Box"
pptSlide.Shapes("Box").Fill.ForeColor.RGB = RGB(219, 233, 255)
pptSlide.Shapes("Box").Line.ForeColor.RGB = RGB(0, 102, 255)
'Insert the text box
Set Txt = pptSlide.Shapes.AddTextbox(Orientation:=msoTextOrientationHorizontal, _
Left:=Application.CentimetersToPoints(17.1), _
Top:=Application.CentimetersToPoints(3.3), _
Width:=Application.CentimetersToPoints(7.22), _
Height:=Application.CentimetersToPoints(9.29))
Txt.Name = "Txt"
pptSlide.Shapes("Txt").TextFrame.TextRange.Font.Size = 14
pptSlide.Shapes("Txt").TextFrame.TextRange.Font.Bold = msoCTrue
pptSlide.Shapes("Txt").TextFrame.TextRange.Font.Name = "Arial"
pptSlide.Shapes("Txt").TextFrame.TextRange.Text = "Sample Text"
'Clear the Clipboard
Dim oData As New DataObject 'object to use the clipboard
oData.SetText Text:=Empty 'Clear
oData.PutInClipboard
Next
Next
End Sub
The code works on my example (2 sheets, 3 charts total) but not if I apply it to the real thing, which is a workbook with 10-15 sheets and 8 charts per sheet. At some (random?) point, the code stops and gives me this error.
Run-time error:
Shapes (unknown member): Invalid request. Clipboard is empty or contains data which may not be pasted here.
I noted that the code crashed earlier, the more objects I put on the slides (which is why I left the text and the box in my example, although not strictly neccessary). Given that and the error message, I assumed the clipboard might not be cleared properly after each loop, so I put in a section to clear the clipboard but it didn't solve the issue.
After the chart is copied, try adding DoEvents and pausing the macro for a few seconds before pasting it into your slide. And the same thing after it's pasted into your slide.
So, for example, first add the following function to pause your code . . .
Sub PauseMacro(ByVal secs As Long)
Dim endTime As Single
endTime = Timer + secs
Do
DoEvents
Loop Until Timer > endTime
End Sub
Then try something like this . . .
ch.Copy
DoEvents
PauseMacro 5 'pause for 5 seconds
With pptSlide.Shapes.Paste
DoEvents
PauseMacro 5 'pause for 5 seconds
.Top = Application.CentimetersToPoints(3.3)
.Left = Application.CentimetersToPoints(0.76)
.Width = Application.CentimetersToPoints(16)
.Height = Application.CentimetersToPoints(10.16)
End With
You may find through testing that you can pause for less than 5 seconds, maybe 3 seconds.
My approach is to split out potentially time-consuming operations into separate functions (see "'' Call as a Function" below). When a function is called, and then has to return, it seems that Excel/VBA/the-little-green-men-running-everything make sure that whatever operation it is waits until the operation is finished (the chart is totally added to the clipboard, the clipboard contents are totally pasted, the shape is totally instantiated, etc.) before continuing.
This also means not necessarily forcing a delay during execution that might not be needed (the Do Until or Loop Until or Wait that is often suggested).
So your code might look like this (caveat: untested)
Sub PPT_Example()
Dim pptApp As PowerPoint.Application
Dim pptPres As PowerPoint.Presentation
Dim sh As Worksheet
Dim ch As ChartObject
Set pptApp = New PowerPoint.Application
pptApp.Visible = True
Set pptPres = pptApp.Presentations.Add
pptPres.PageSetup.SlideSize = PpSlideSizeType.ppSlideSizeOnScreen16x9
For Each sh In ActiveWorkbook.Sheets
For Each ch In sh.ChartObjects
Dim pptSlide As Slide
Dim Title As Object
Dim Box As Object
Dim Txt As Object
Set pptSlide = NewSlide(pptPres) '' Call as a Function
ch.Copy
Dim shp As PowerPoint.Shape
Set shp = NewShape(pptSlide) '' Call as a Function
With shp
.Top = Application.CentimetersToPoints(3.3)
.Left = Application.CentimetersToPoints(0.76)
.Width = Application.CentimetersToPoints(16)
.Height = Application.CentimetersToPoints(10.16)
End With
'Insert Box
Set Box = NewBox(pptSlide) '' Call as a Function
Prop_Box.Name = "Box"
pptSlide.Shapes("Box").Fill.ForeColor.RGB = RGB(219, 233, 255)
pptSlide.Shapes("Box").Line.ForeColor.RGB = RGB(0, 102, 255)
'Insert the text box
Set Txt = NewTextBox(pptSlide) '' Call as a Function
Txt.Name = "Txt"
pptSlide.Shapes("Txt").TextFrame.TextRange.Font.Size = 14
pptSlide.Shapes("Txt").TextFrame.TextRange.Font.Bold = msoCTrue
pptSlide.Shapes("Txt").TextFrame.TextRange.Font.Name = "Arial"
pptSlide.Shapes("Txt").TextFrame.TextRange.Text = "Sample Text"
'Clear the Clipboard
Dim oData As New DataObject 'object to use the clipboard
oData.SetText Text:=Empty 'Clear
oData.PutInClipboard
Next
Next
End Sub
Function NewSlide(pptPres As PowerPoint.Presentation) As PowerPoint.Slide
Set NewSlide = pptPres.Slides.Add(pptPres.Slides.Count + 1, ppLayoutBlank)
End Function
Function NewShape(pptSlide As PowerPoint.Slide) As PowerPoint.Shape
Set NewShape = pptSlide.Shapes.Paste
End Function
Function NewBox(pptSlide As PowerPoint.Slide) As Object
Set Box = pptSlide.Shapes.AddShape(Type:=msoShapeRectangle, _
Left:=Application.CentimetersToPoints(17.1), _
Top:=Application.CentimetersToPoints(3.3), _
Width:=Application.CentimetersToPoints(7.22), _
Height:=Application.CentimetersToPoints(9.29))
End Function
Function NewTextBox(pptSlide As PowerPoint.Slide) As Object
Set NewTextBox = pptSlide.Shapes.AddTextbox(Orientation:=msoTextOrientationHorizontal, _
Left:=Application.CentimetersToPoints(17.1), _
Top:=Application.CentimetersToPoints(3.3), _
Width:=Application.CentimetersToPoints(7.22), _
Height:=Application.CentimetersToPoints(9.29))
End Function

Excel/VBA Macros assistance

I am having a bit of trouble with some code and was wondering if someone could maybe assist. Basically I have 2 errors which I can't work out myself (too inexperienced with VBA, unfortunately)
Brief overview:
This macro is designed to generate a new workbook with copies of selected sheets from a "source" workbook in order to present to clients as a report batch. Essentially - we have master workbook "A" which may have 50 tabs or so, and we want to quickly select a couple of sheets to "copy" into a new workbook to save and send to a client. The code is a bit of a mess but I am not really sure what is going on/what I can remove etc.
Problems:
When you run the attached code/macro in Excel, it does everything it is supposed to do, however, it ALSO copies the sheet from which you run the macro. (i.e. I might be on sheet 1 in the Workbook. Run the macro to generate reports, checkbox menu appears and I select sheets 2, 5 & 9 - it will then copy into a new Workbook sheets 2, 5 & 9 AND sheet 1. But I never selected sheet 1 from the checkbox menu...)
Once this code has finished running, I am unable to save the Excel file. It just crashes and says "Microsoft Excel has stopped working" and then the file dies and I have to close Excel and recover etc. etc. I combined 2 pieces of code to get this working and I imagine I may be missing something crucial which is causing the problem. We have another piece of code to print sheets out in a similar way to this, and if I run this I am able to save with no problems.
Code:
I have included all the Visual Basic code (i.e. for the generate reports & print sheets macros).
I really don't have any experience with VBA so I hope someone will be able to assist! Thanks in advance :)
Sub PrintSelectedSheets()
Dim i As Integer
Dim TopPos As Integer
Dim SheetCount As Integer
Dim Printdlg As DialogSheet
Dim CurrentSheet As Worksheet, wsStartSheet As Worksheet
Dim CB As CheckBox
Application.ScreenUpdating = False
'Check for protected workbook
If ActiveWorkbook.ProtectStructure Then
MsgBox "Workbook is protected.", vbCritical
Exit Sub
End If
'Add a temporary dialog sheet
Set CurrentSheet = ActiveSheet
Set wsStartSheet = ActiveSheet
Set Printdlg = ActiveWorkbook.DialogSheets.Add
SheetCount = 0
'Add the checkboxes
TopPos = 40
For i = 1 To ActiveWorkbook.Worksheets.Count
Set CurrentSheet = ActiveWorkbook.Worksheets(i)
'Skip empty sheets and hidden sheets
If Application.CountA(CurrentSheet.Cells) <> 0 And _
CurrentSheet.Visible Then
SheetCount = SheetCount + 1
Printdlg.CheckBoxes.Add 78, TopPos, 150, 16.5
Printdlg.CheckBoxes(SheetCount).Text = _
CurrentSheet.Name
TopPos = TopPos + 13
End If
Next i
'Move the OK and Cancel buttons
Printdlg.Buttons.Left = 240
'Set dialog height, width, and caption
With Printdlg.DialogFrame
.Height = Application.Max _
(68, Printdlg.DialogFrame.Top + TopPos - 34)
.Width = 230
.Caption = "Select sheets to print"
End With
'Change tab order of OK and Cancel buttons
'so the 1st option button will have the focus
Printdlg.Buttons("Button 2").BringToFront
Printdlg.Buttons("Button 3").BringToFront
'Display the dialog box
CurrentSheet.Activate
wsStartSheet.Activate
Application.ScreenUpdating = True
If SheetCount <> 0 Then
'the following code will print the selected sheets as multiple print jobs.
'continuous page numbers will therefore not be printed
If Printdlg.Show Then
For Each CB In Printdlg.CheckBoxes
If CB.Value = xlOn Then
Worksheets(CB.Caption).Activate
ActiveSheet.PrintOut
'ActiveSheet.PrintPreview 'for debugging
End If
Next CB
'the following code will print the selected sheets as a single print job.
'This will allow the sheets to be printed with continuous page numbers.
'If Printdlg.Show Then
'For Each CB In Printdlg.CheckBoxes
'If CB.Value = xlOn Then
'Worksheets(CB.Caption).Select Replace:=False
'End If
'Next CB
'ActiveWindow.SelectedSheets.PrintOut copies:=1
'ActiveSheet.Select
Else
MsgBox "No worksheets selected"
End If
'End If
End If
'Delete temporary dialog sheet (without a warning)
Application.DisplayAlerts = False
Printdlg.Delete
'Reactivate original sheet
CurrentSheet.Activate
wsStartSheet.Activate
End Sub
Sub GenerateClientExcelReports()
'1. Declare variables
Dim i As Integer
Dim SheetCount As Integer
Dim TopPos As Integer
Dim lngCheckBoxes As Long, y As Long
Dim intTopPos As Integer, intSheetCount As Integer
Dim intHor As Integer 'this will be for the horizontal position of the items
Dim intWidth As Integer 'this will be for the overall width of the dialog box
Dim intLBLeft As Integer, intLBTop As Integer, intLBHeight As Integer
Dim Printdlg As DialogSheet
Dim CurrentSheet As Worksheet, wsStartSheet As Worksheet
Dim CB As CheckBox
'Dim wb As Workbook
'Dim wbNew As Workbook
'Set wb = ThisWorkbook
'Workbooks.Add ' Open a new workbook
'Set wbNew = ActiveWorkbook
On Error Resume Next
Application.ScreenUpdating = False
'2. Check for protected workbook
If ActiveWorkbook.ProtectStructure Then
MsgBox "Workbook is protected.", vbCritical
Exit Sub
End If
'3. Add a temporary dialog sheet
Set CurrentSheet = ActiveSheet
Set wsStartSheet = ActiveSheet
Set Printdlg = ActiveWorkbook.DialogSheets.Add
SheetCount = 0
'4. Add the checkboxes
TopPos = 40
For i = 1 To ActiveWorkbook.Worksheets.Count
Set CurrentSheet = ActiveWorkbook.Worksheets(i)
'5. Skip empty sheets and hidden sheets
If Application.CountA(CurrentSheet.Cells) <> 0 And _
CurrentSheet.Visible Then
SheetCount = SheetCount + 1
Printdlg.CheckBoxes.Add 78, TopPos, 150, 16.5
Printdlg.CheckBoxes(SheetCount).Text = _
CurrentSheet.Name
TopPos = TopPos + 13
End If
Next i
'6. Move the OK and Cancel buttons
Printdlg.Buttons.Left = 240
'7. Set dialog height, width, and caption
With Printdlg.DialogFrame
.Height = Application.Max _
(68, Printdlg.DialogFrame.Top + TopPos - 34)
.Width = 230
.Caption = "Select sheets to generate"
End With
'8. Change tab order of OK and Cancel buttons
' so the 1st option button will have the focus
Printdlg.Buttons("Button 2").BringToFront
Printdlg.Buttons("Button 3").BringToFront
'9. Display the dialog box
CurrentSheet.Activate
wsStartSheet.Activate
Application.ScreenUpdating = True
If SheetCount <> 0 Then
If Printdlg.Show Then
For Each CB In Printdlg.CheckBoxes
If CB.Value = xlOn Then
Worksheets(CB.Caption).Select Replace:=False
'For y = 1 To ActiveWorkbook.Worksheets.Count
'If WorksheetFunction.IsNumber _
'(InStr(1, "ActiveWorkbook.Sheets(y)", "Contents")) = True Then
'CB.y = xlOn
'End If
End If
Next
ActiveWindow.SelectedSheets.Copy
Else
MsgBox "No worksheets selected"
End If
End If
'Delete temporary dialog sheet (without a warning)
'Application.DisplayAlerts = False
'Printdlg.Delete
'Reactivate original sheet
'CurrentSheet.Activate
'wsStartSheet.Activate
'10. Delete temporary dialog sheet (without a warning)
Application.DisplayAlerts = False
Printdlg.Delete
'11. Reactivate original sheet
CurrentSheet.Activate
wsStartSheet.Activate
Application.DisplayAlerts = True
End Sub
Sub SelectAllCheckBox()
Dim CB As CheckBox
For Each CB In ActiveSheet.CheckBoxes
If CB.Name <> ActiveSheet.CheckBoxes(1).Text Then
CB.Value = ActiveSheet.CheckBoxes(1).Value
End If
Next CB
'ActiveSheet.CheckBoxes("Check Box 1").Value
End Sub
as for problem n°1
add a declaration of a boolean variable
Dim firstSelected As Boolean
and then modify the For Each CB In Printdlg.CheckBoxes loop block code as follows
If CB.Value = xlOn Then
If firstSelected Then
Worksheets(CB.Caption).Select Replace:=False
Else
Worksheets(CB.Caption).Select
firstSelected = True
End If
'For y = 1 To ActiveWorkbook.Worksheets.Count
'If WorksheetFunction.IsNumber _
'(InStr(1, "ActiveWorkbook.Sheets(y)", "Contents")) = True Then
'CB.y = xlOn
'End If
End If
since there's always an ActiveWorksheet when macro starts and thus if you only use Worksheets(CB.Caption).Select Replace:=False statement you keep adding it to the via Printdlg selected sheets.

How can I import code to a Activex Control Button on another page?

I have use a button (by clicking) to create a new sheet and insert a button on it, but I want to import codes to the new button (here is MyPrecodedButton).
Private Sub CommandButton1_Click()
Dim z As Integer
Dim wb As Workbook
Dim ws2 As Worksheet, wsnew As Worksheet
Set wb = ThisWorkbook
Set ws2 = wb.Sheets("Sheet2")
z = ws2.Cells(2, 1).Value
Set wsnew = Sheets.Add ' Declare your New Sheet in order to be able to work with after
wsnew.Name = "PIAF_Summary" & z
z = z + 1
With wsnew.Range("A1:G1")
.Merge
.Interior.ColorIndex = 23
.Value = "Project Name (To be reviewed by WMO)"
.Font.Color = vbWhite
.Font.Bold = True
.Font.Size = 13
End With
ws2.Cells(2, 1).Value = z
Dim Rngc As Range: Set Rngc = wsnew.Range("F35")
With ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False, Left:=Rngc.Left, Top:=Rngc.Top, Width:=205, Height:=20)
.Name = "MyPrecodedButton" ' change the name
End With
End sub
Here is the code for MyPrecodedButton
Public Sub MyPrecodedButton_Click()
MsgBox "Co-Cooo!"
End Sub
Let's demonstrate briefly what you can do with VBA to Add buttons.
Below code will Add a button to cell B2 if the ActiveSheet is not "Sheet1".
Option Explicit
Sub SayHello()
MsgBox "Hello from """ & ActiveSheet.Name & """"
End Sub
Sub AddButton()
Dim oRng As Range
Dim oBtns As Buttons ' Add "Microsoft Forms 2.0 Object Library" to References if you want intellisense
If ActiveSheet.Name <> "Sheet1" Then ' Only works if it's not "Sheet1"
Set oRng = Range("B2")
Set oBtns = ActiveSheet.Buttons
With oBtns.Add(oRng.Left * 1.05, oRng.Top * 1.05, oRng.Width * 0.9, oRng.Height * 2 * 0.9)
.Caption = "Say Hello!"
.OnAction = "SayHello"
End With
Set oBtns = Nothing
Set oRng = Nothing
End If
End Sub
Before and After screenshots:
Now Clicking on the button:
So, if you code is generic enough (to work with all your possible situations), there is no need to Add Codes via code. i.e. have your codes ready, then just assign the button's OnAction property to call the correct Sub.

Implement For Loop with Counter

I have a Word Userform where I add text boxes dynamically. The code then puts information from the textboxes to bookmarks which are picture filenames. It is all dynamic in that you enter how many textboxes you need and it then adds them to the userform and the text in the document. I left this last part of code out because its very long and not needed at this point.
I am attempting to put this first part of my code into a "For Loop" but I have been having a lot of difficulty doing so. The second part of my code I am providing has a textbox counter I trying to tie into it.
Right now my code works if I enter 10 into a textbox called "Amount" which you see throughout the code. I need to be able to enter any number.
If you think the entire code will help let me know and I will add it instead. I have been able to get everything else to work but for some reason this has had me stumped for days.
Need "For loop" implemented
Sub CommandButton1_Click()
Dim Textbox As Object
Dim Textbox1 As Object
Dim Textbox2 As Object
Dim Textbox3 As Object
Dim Textbox4 As Object
Dim Textbox5 As Object
Dim Textbox6 As Object
Dim Textbox7 As Object
Dim Textbox8 As Object
Dim Textbox9 As Object
Dim Textbox10 As Object
Dim TBs(9) As Object
Set TBs(0) = UserForm1.Controls("TextBox_1"): Set TBs(1) = UserForm1.Controls("TextBox_2"): Set TBs(2) = UserForm1.Controls("TextBox_3")
Set TBs(3) = UserForm1.Controls("TextBox_4"): Set TBs(4) = UserForm1.Controls("TextBox_5"): Set TBs(5) = UserForm1.Controls("TextBox_6")
Set TBs(6) = UserForm1.Controls("TextBox_7"): Set TBs(7) = UserForm1.Controls("TextBox_8"): Set TBs(8) = UserForm1.Controls("TextBox_9")
Set TBs(9) = UserForm1.Controls("TextBox_10"):
Dim i
For i = 0 To Amount - 1
With ActiveDocument
If .Bookmarks("href" & i + 1).Range = ".jpg" Then
.Bookmarks("href" & i + 1).Range _
.InsertBefore TBs(i)
.Bookmarks("src" & i + 1).Range _
.InsertBefore TBs(i)
.Bookmarks("alt" & i + 1).Range _
.InsertBefore TBs(i)
End If
End With
Next
End Sub
TextBox Counter
Private Sub AddLine_Click()
Dim theTextbox As Object
Dim textboxCounter As Long
For textboxCounter = 1 To Amount
Set theTextbox = UserForm1.Controls.Add("Forms.TextBox.1", "Test" & textboxCounter, True)
With theTextbox
.Name = "TextBox_" & textboxCounter
.Width = 200
.Left = 70
.Top = 30 * textboxCounter
End With
Next
End Sub

Error with creating command button during runtime

I have a module that creates command buttons during run-time. It will create the command buttons in a specified user-form. Program works fine, when I execute the module.
However when I use the user-form to call the module instead, I have a error stating
Run-time error '91':
Object variable or With block variable not set
Code
Sub AddButtonAndShow()
Dim Butn As CommandButton
Dim Line As Long
Dim objForm As Object
Dim i As Integer
Dim x As Integer
Set objForm = ThisWorkbook.VBProject.VBComponents("Current_Stock")
For i = 1 To 3
Set Butn = objForm.Designer.Controls.Add("Forms.CommandButton.1")
With Butn
.Name = "CommandButton" & i
.Caption = i
.Width = 100
.Left = 300
.Top = 10 * i * 2
End With
Next
For x = 1 To 3
With objForm.CodeModule
Line = .CountOfLines
.InsertLines Line + 1, "Sub CommandButton" & x & "_Click()"
.InsertLines Line + 2, "MsgBox ""Hello!"""
.InsertLines Line + 3, "End Sub"
End With
'
Next x
End Sub
Kindly advise.
Editted post: based on VBProject Form Components
Earlier post is for Excel Sheet buttons. I noticed for Form buttons you may set the caption by directly referring to the button itself. I tried out your code. Doesn't seem to find any errors. The only addtional things I did was adding the reference Library (MS VB Extensibility 5.3), Private scope to code and combining code into one with statement.
As per this Mr.Excel article, you need add do Events to run the code when VB Editor is closed. Your error seems to be very much alike to what's mentioned in the article.
Revised Code:
Sub AddButtonAndShow()
Dim Butn As CommandButton
Dim Line As Long
Dim objForm As Object
Dim i As Integer
Dim x As Integer
Dim code As String
Application.DisplayAlerts = False
DoEvents
On Error Resume Next
Set objForm = ActiveWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
objForm.Name = "thisform1"
For i = 1 To 3
Set Butn = objForm.Designer.Controls.Add("Forms.CommandButton.1")
With Butn
.Name = "CommandButton" & i
.Caption = i
.Width = 100
.Left = 100
.Top = (i * 24) + 10
Line = objForm.CodeModule.CountOfLines + 1
code = "Private Sub " & Butn.Name & "_Click()" & vbCr
code = code & "MsgBox ""Hello!""" & vbCr
code = code & "End Sub"
objForm.CodeModule.InsertLines Line, code
End With
Next
Application.DisplayAlerts = False
VBA.UserForms.Add(objForm.Name).Show
End Sub
Excel Command Button code:
Private Sub CommandButton3_Click()
Call AddButtonAndShow
End Sub
Output: Use an Excel Sheet button to open the newly created Form with buttons.
Initial post:
Please take a look at this post for reference: Excel VBA create a button beside cell.
Possible error due to (object doesn't support property or method), is within the Caption property. As it has to be set with theBttn.Object.Caption
Try this please:
With Butn
.Name = "CommandButton" & i
.Object.Caption = i
.Width = 100
.Left = 300
.Top = 10 * i * 2
End With