Change Event for Multiple Check Boxes // Excel VBA // WithEvents // ClassModule - excel

I have 25 text boxes named in the following manner on a UserForm
Name: id_[X]_box 1<= x <= 25
I am trying to write a program which can register a change event for all 25 boxes and populate the corresponding [DESCRIPTION] Labels.
Naming scheme for Description Labels Name: desc_[X]_label 1 <= X <= 25
When I program for a change event for just one box (i.e id_box_1), the functionality works fine.
When I try to implement for the 25 boxes with WithEvents and ClassModules, I am getting an error "Can't compile Module"
The form's Name: links
Please see relevant code snippets below
Code in the UserForm_Initialize function
Private Sub UserForm_Initialize()
'Code to make single change event subroutine register for all id_[INT]_textboxes on links form
Dim ctrl As MSForms.Control
Dim text_box_handler As text_boxes_change
Set textBox_collection = New Collection
For Each ctrl In Me.controls
If TypeOf ctrl Is MSForms.TextBox Then
If Split(ctrl.Name, "_")(0) = "id" Then
Set text_box_handler = New text_boxes_change
Set text_box_handler.control_text_box = ctrl
textBox_collection.Add text_box_handler
End If
End If
Next ctrl
End Sub
Custom Class Module Code
Class Module Name: text_boxes_change
Option Explicit
'This class assists in validating multiple text boxes on forms without having to define event
functions for each text box separately
'Global Constants
Const CASHFLOW As String = "Chart"
Const SETUP As String = "Settings"
Const INVOICE_STATUSES As String = "K13:K18"
Const TIME_UNITS As String = "L21:L24"
Const RELATION_TYPES As String = "M21:M25"
Const ACTIVITIES_COL As String = "T"
Const PROJ_START_ROW As Integer = 6
Public WithEvents MyTextBox As MSForms.TextBox
Public Property Set control_text_box(ByVal tb As MSForms.TextBox)
Set MyTextBox = tb
End Property
Public Sub BoxesGroup_Change()
'Setting default background color for the box
Me.MyTextBox.BackColor = RGB(255, 255, 255)
'Setting up Cashflow Worksheet Object
Dim cashflow_sheet As Worksheet
Set cashflow_sheet = Sheets("Chart")
'Finding lastrow with text inside the Sub-Activites column in Chart sheet
Dim lastrow As Integer
lastrow = cashflow_sheet.Cells(Rows.Count, ACTIVITIES_COL).End(xlUp).Row
'Range to represent the activities column in Chart worksheet
Dim activities_range As Range
Set activities_range = cashflow_sheet.Range(ACTIVITIES_COL & CStr(PROJ_START_ROW) & ":" & _
ACTIVITIES_COL & CStr(lastrow))
'A variable to store the user inputed value for id_box
Dim row_id As String
row_id = Me.MyTextBox.value
If IsNumeric(row_id) = True Then
If CInt(row_id) >= PROJ_START_ROW And CInt(row_id) <= lastrow Then
Dim desc_caption As String
'SheetFunctions is a Module ; links_description is a Function that returns a string
representing a cell address based on the rules of the workbook; functionality is tested and verified
for this part
desc_caption = SheetFunctions.links_description(row_id)
If desc_caption <> "" Then
Me.MyTextBox.BackColor = RGB(255, 255, 255)
Me.desc_1_label.Caption = desc_caption
Else
Me.MyTextBox.BackColor = RGB(140, 39, 30)
End If
Else
Me.MyTextBox.BackColor = RGB(140, 39, 30)
End If
Else
Me.MyTextBox.BackColor = RGB(140, 39, 30)
End If
End Sub
Screenshot of the Form

Related

Loop Through VBA Variables

I'm making a Userform in VBA where I have Text Box's where I can search items. I have about 30 Text Box's so I want to cut down the code using a loop instead of copy and pasting the same code 30 times.
Problem: I don't know how to loop through a public variable
Public Variable: Public oEventHandler(Number) As New clsSearchableDropdown
oEventHandler would go from 1 to 30 (e.g oEventHandler2,oEventHandler3...oEventHandler30)
clsSearchableDropdown is the Class Module for the search feature
Text Box: TextBox(Number)
ListBox: ListBox(Number)
Here is the original code (No Issue Just to Compare):
With oEventHandler1
' Attach the textbox and listbox to the class
Set .SearchListBox = Me.ListBox1
Set .SearchTextBox = Me.TextBox1
' Default settings
.MaxRows = 10
.ShowAllMatches = True
.CompareMethod = vbTextCompare
.WindowsVersion = False
End With
This is what I'm trying to do:
Dim i As Integer
for i = 1 to 30
With Me.Controls.Item("oEventHandler" & i)
' Attach the textbox and listbox to the class
Set .SearchListBox = Me.Controls.Item("ListBox" & i)
Set .SearchTextBox = Me.Controls.Item("TextBox" & i)
' Default settings
.MaxRows = 10
.ShowAllMatches = True
.CompareMethod = vbTextCompare
.WindowsVersion = False
End With
Next i
I know that oEventHandler is not a control but is there a similar code I can use to loop through a public variable?
Here is the code that worked for me:
' Make a New Collection
Dim coll As New Collection
' Add all Public Variables to Collection (n = Number 1 to 30)
coll.Add uQuote.oEventHandler(n)
(e.g oEventHandler1, oEventHandler2... oEventHandler30)
Dim i As Integer
for i = 1 to 30
With coll(i)
' Attach the textbox and listbox to the class
Set .SearchListBox = Me.Controls.Item("ListBox" & i)
Set .SearchTextBox = Me.Controls.Item("TextBox" & i)
' Default settings
.MaxRows = 10
.ShowAllMatches = True
.CompareMethod = vbTextCompare
.WindowsVersion = False
End With
Next i
If I understand you correctly, in the userform you have 30 Textboxes and 30 Listboxes, where each Textbox(N) is to search the value in the Listbox(N) located under that TextBox(N). So it looks something like this :
On the left side is TextBox01, under TextBox01 is ListBox01
On the right side is TextBox02, under TextBox02 is ListBox02
If the animation is similar with your expectation....
Preparation :
Make a named range (as many as needed) with something like List01, List02, List03, and so on for the value to populate each ListBox.
Name each ListBox with something like ListBox01, ListBox02, and so on.
Name each TextBox with something like TextBox01, TextBox02, and so on.
In the Userform module:
Dim MyTextBoxes As Collection
Private Sub UserForm_Initialize()
'populate the ListBoxes with value in a named range
Dim LBname As String: Dim RGname As String: Dim i As Integer
For i = 1 To 2
LBname = "ListBox" & Format(i, "00")
RGname = "List" & Format(i, "00")
Controls(LBname).List = Application.Transpose(Range(RGname))
Next i
'add each TextBox to class
Set MyTextBoxes = New Collection
For Each ctl In Me.Controls
Set TextBoxClass = New Class1
If TypeName(ctl) = "TextBox" And InStr(ctl.Name, "TextBox") Then Set TextBoxClass.obj = ctl
MyTextBoxes.Add TextBoxClass
Next
End Sub
In the Class Module named Class1:
Private WithEvents tb As MSForms.TextBox
Property Set obj(t As MSForms.TextBox)
Set tb = t
End Property
Private Sub tb_Change()
Dim idx As String: Dim LBname As String: Dim arr
idx = Right(tb.Name, 2)
LBname = "ListBox" & idx
arr = Application.Transpose(Range("List" & idx))
With Userform1.Controls(LBname)
If tb.text = "" Then
.Clear
.List = arr
Else
.Clear
For i = LBound(arr, 1) To UBound(arr, 1)
If LCase(arr(i)) Like "*" & LCase(tb.value) & "*" Then .AddItem arr(i)
Next i
End If
End With
End Sub
If in your userform you have another textbox which not to use as a search of the items in respective listbox, then maybe don't name the textbox with "TextBox" but something else, for example "blablabla".
if your existing textbox and listbox already named something like ListBox1, ListBox2, ListBox3 and so on, TextBox1, TextBox2, TextBox3 and so on... then name the named range like List1, List2, List3 and so on. In the class module, change the code for idx using the replace method, something like idx = replace(tb.name,"TextBox",""). Also in the Userform module for LBname and RGname use the replace method.
Because I'm limited in English language, I'm sorry I can't detail the code for further explanation.

TextBox ClassModule - Change backgroundcolor only on a real value change

I have a Userform with multiple Controls (Textbox). Those Textboxes will be populated by selecting a ListBox item.
When initializing the UserForm those TextBoxes will be assigned to a specific Class which handles them.
I want VBA to change the background color of those textboxes only when a real change of the value was performed. What I have is that the BackgroundColor is always changed as soon as a change was performed, but that's not what I want.
Example #1:
Textbox value before change: "test"
Textbox value after change: "test2"
--> BackgroundColor should be changed
Example #2:
Textbox value before change: "test"
Textbox value after change: "test bla" but then I am typing "test" again.
--> BackgroundColor should not be changed, because initial Value is in the TextBox again.
What I have so far:
' **************************************************************
' Module: clsTextbox Typ = Class Module
' **************************************************************
Public WithEvents mTextBoxs As MSForms.TextBox
Private Sub mTextBoxs_Change()
If mTextBoxs.Text = strInitialVal Then
Reset_BackColor
Else
mTextBoxs.BackColor = RGB(255, 255, 153)
End If
End Sub
Public Sub Reset_BackColor()
mTextBoxs.BackColor = RGB(255, 255, 255)
End Sub
' **************************************************************
' Module: frmEmployee Type = Userform
' **************************************************************
Dim arrLabels() As New clsLabel, UBoundarrLabels As Integer
Dim arrTextBoxs() As New clsTextbox, UBoundarrTextBoxs As Integer
Private Sub UserForm_Initialize()
Dim Ctrl As Control, obLabel As MSForms.Label, obTextbox As MSForms.TextBox
tblName = "tblMitarbeiter"
Set wb = ThisWorkbook
Set ws = wb.Sheets("Mitarbeiter")
i = 0
For Each Ctrl In Me.Controls
If Left(Ctrl.Name, 7) = "TextBox" Then
i = i + 1
ReDim Preserve arrTextBoxs(i)
Set obTextbox = Me.Controls("TextBox" & i)
Set arrTextBoxs(i).mTextBoxs = obTextbox
End If
Next Ctrl
' Fill Listbox1 with values (Vorname & Nachname) from Table [tblMitarbeiter]
Dim lngLastRow As Long: lngLastRow = getListLastRow(ws, tblName)
Dim vArrListBox1() As Variant
ReDim vArrListBox1(0 To lngLastRow - 1, 0 To 2)
For j = 1 To lngLastRow
vArrListBox1(j - 1, 0) = ws.ListObjects("tblMitarbeiter").DataBodyRange(j, 1).Value
vArrListBox1(j - 1, 1) = ws.ListObjects("tblMitarbeiter").DataBodyRange(j, 2).Value
vArrListBox1(j - 1, 2) = ws.ListObjects("tblMitarbeiter").DataBodyRange(j, 3).Value
Next j
For t = 1 To 4
Me.Controls("TextBox" & t) = vArrEmployee(t - 1)
Next t
strInitialVal = Me.Controls("TextBox2")
End Sub
My thoughts are:
As you can see I tried to declare a public variable (strInitialVal) in a Module which gets the initial value of a textbox (e.g. TextBox2) and when performing the mTextBoxs_Change() Event it checks whether the strInitialVal is the same as the value in the Textbox and so on.
--> this works, but only for a 1:1 relation of the variable and a textbox.
How can I manage to load all textbox values into an Array? and Check the values in the TextBox Class afterwards.
If you need more information please let me know. I hope I did not violate any SO-rules.
You could use collections to hold your textboxes.
After option explicit, declare these collections
Private ColTxtBox As New Collection
Then when dynamically creating textboxes, here is one example:
`'Create Unit size; textbox
Set TxtBox = New DynamicTxtbox
TxtBox.Row = FormRows
TxtBox.Column = A_Deliv.F_UnitSize
Call TxtBox.InitText(frm_delivery.Frame1, "txtbox" & TxtBox.Row) 'this is the
constructor
ColTxtBox.Add TxtBox`
However, if you already created all textboxes on your form and they are fixed, it is sufficient to run through all controls and add these to your collection (if it's a textbox!). Then in your textbox class, you can easily loop through all your texboxes - and access their current values with something like
`Private Sub mTextBoxs_Change()
For Each TxtBox In ColTxtBox
If InStr(Me.Value,TxtBox.Value) > 0 Then
Reset_BackColor
Else
mTextBoxs.BackColor = RGB(255, 255, 153)
End If
Next TxtBox
EndS Sub`

Re-write dynamic textbox after button is pressed

I've created a code in VBA to collect data using a multi-page control. In each page, I've added checkboxes dynamically based on rows from the worksheet in Excel and, for each checkbox, there's a textbox and 2 command buttons, just like the image below:
Input Window:
The code to automatically add controls is:
Private Sub UserForm_Initialize()
fmat_disp.Value = 0
fmat_set.Value = 0
'---------------------------------------------------------------------------------------------
'Inspeção de Mecânica
Sheets("Mecânica").Activate
n_anom = Application.WorksheetFunction.CountA(Range("1:1")) - 1
AreasInspecao.mecanica.ScrollHeight = 10 + 18 * (n_anom)
For i = 1 To n_anom
'Selecionar anomalia
Set SelAnom = AreasInspecao.mecanica.Controls.Add("Forms.CheckBox.1", "sel_anom_" & i)
SelAnom.Caption = Worksheets("Mecânica").Cells(1, i + 1)
SelAnom.AutoSize = True
SelAnom.Height = 18
SelAnom.Left = 5
SelAnom.Top = 5 + (SelAnom.Height) * (i - 1)
SelAnom.Tag = i
Same goes to the textbox and plus/minus buttons, only changing the captions.
What I want is:
1) when CHECKBOX is CHECKED, respective TEXTBOX must show 1
2) when MINUS sign is PRESSED, respective TEXTBOX must decrement
3) when PLUS sign is PRESSED, respective TEXTBOX must increment
4) when "Finalizar Inspeção" is PRESSED, all data collected must be sent to Excel, filling a worksheet.
I simply don't know how to link each button/checkbox to your respective textbox without creating a subroutine for each one! I'll have ~500 subroutines....that's impossible to manage manually....
OK here's a rough outline for handling the click events on the checkboxes and buttons.
First two custom classes for capturing the clicks: each of these is very simple - all they do is call a method on the userform with the clicked control as an argument.
'clsCheck
Public WithEvents chk As MSForms.CheckBox
Private Sub chk_Click()
frmExample.HandleClick chk
End Sub
'clsButton
Public WithEvents btn As MSForms.CommandButton
Private Sub btn_Click()
frmExample.HandleClick btn
End Sub
Userform code - my form is named "frmExample".
Note the naming convention which allows groups of controls to be treated as a "unit".
Option Explicit
'These two global collections hold instances of the custom classes
Dim colCheckBoxes As Collection
Dim colButtons As Collection
Private Sub UserForm_Activate()
Const CON_HT As Long = 18
Dim x As Long, cbx As MSForms.CheckBox, t
Dim btn As MSForms.CommandButton, txt As MSForms.TextBox
Dim oCheck As clsCheck, oButton As clsButton
Set colCheckBoxes = New Collection
Set colButtons = New Collection
For x = 1 To 10
t = 5 + CON_HT * (x - 1)
Set cbx = Me.Controls.Add("Forms.CheckBox.1", "cbox_" & x)
cbx.Caption = "Checkbox" & x
cbx.Width = 80
cbx.Height = CON_HT
cbx.Left = 5
cbx.Top = t
colCheckBoxes.Add GetCheckHandler(cbx) '<< save in collection
Set btn = Me.Controls.Add("Forms.CommandButton.1", "btnplus_" & x)
btn.Caption = "+"
btn.Height = CON_HT
btn.Width = 20
btn.Left = 90
btn.Top = t
btn.Enabled = False '<<buttons start off disabled
colButtons.Add GetButtonHandler(btn) '<< save in collection
Set btn = Me.Controls.Add("Forms.CommandButton.1", "btnminus_" & x)
btn.Caption = "-"
btn.Height = CON_HT
btn.Width = 20
btn.Left = 130
btn.Top = t
btn.Enabled = False '<<buttons start off disabled
colButtons.Add GetButtonHandler(btn) '<< save in collection
'no events are captured for the textboxes...
Set txt = Me.Controls.Add("Forms.Textbox.1", "txt_" & x)
txt.Width = 30
txt.Height = CON_HT
txt.Left = 170
txt.Top = t
Next x
End Sub
'All "clicked" controls saved in instances of the custom classes
' get passed here. Handle based on control type/name
Public Sub HandleClick(ctrl As MSForms.Control)
Dim num
num = Split(ctrl.Name, "_")(1) 'which set of controls are we working with?
Dim txt As MSForms.TextBox
'get the matching text box...
Set txt = Me.Controls("txt_" & num)
If ctrl.Name Like "cbox_*" Then
If ctrl.Value Then txt.Value = 1
Me.Controls("btnplus_" & num).Enabled = ctrl.Value
Me.Controls("btnminus_" & num).Enabled = ctrl.Value
ElseIf ctrl.Name Like "btnplus_*" Then
txt.Value = txt.Value + 1
ElseIf ctrl.Name Like "btnminus_*" Then
txt.Value = txt.Value - 1
End If
End Sub
'couple of "factory" functions for the event-handling classes
Private Function GetCheckHandler(cb As MSForms.CheckBox)
Dim rv As New clsCheck
Set rv.chk = cb
Set GetCheckHandler = rv
End Function
Private Function GetButtonHandler(btn As MSForms.CommandButton)
Dim rv As New clsButton
Set rv.btn = btn
Set GetButtonHandler = rv
End Function
Sample file: https://www.dropbox.com/s/k74c08m0zkwn9l7/tmpFormEvents.xlsm?dl=0

Use VBA to assign all checkboxes to class module

I'm having a problem assigning VBA generated ActiveX checkboxes to a class module. When a user clicks a button, the goal of what I am trying to achieve is: 1st - delete all the checkboxes on the excel sheet; 2nd - auto generate a bunch of checkboxes; 3rd - assign a class module to these new checkboxes so when the user subsequently clicks one of them, the class module runs.
I've borrowed heavily from previous posts Make vba code work for all boxes
The problem I've having is that the 3rd routine (to assign a class module to the new checkboxes) doesn't work when run subsequently to the first 2 routines. It runs fine if run standalone after the checkboxes have been created. From the best I can tell, it appears VBA isn't "releasing" the checkboxes after they have been created to allow the class module to be assigned.
The below code is the simplified code that demonstrates this problem. In this code, I use a button on "Sheet1" to run Sub RunMyCheckBoxes(). When button 1 is clicked, the class module did not get assigned to the newly generated checkboxes. I use button 2 on "Sheet1" to run Sub RunAfter(). If button 2 is clicked after button 1 has been clicked, the checkboxes will be assigned to the class module. I can't figure out why the class module won't be assigned if just the first button is clicked. Help please.
Module1:
Public mcolEvents As Collection
Sub RunMyCheckboxes()
Dim i As Double
Call DeleteAllCheckboxesOnSheet("Sheet1")
For i = 1 To 10
Call InsertCheckBoxes("Sheet1", i, 1, "CB" & i & "1")
Call InsertCheckBoxes("Sheet1", i, 2, "CB" & i & "2")
Next
Call SetCBAction("Sheet1")
End Sub
Sub DeleteAllCheckboxesOnSheet(SheetName As String)
Dim obj As OLEObject
For Each obj In Sheets(SheetName).OLEObjects
If TypeOf obj.Object Is MSForms.CheckBox Then
obj.Delete
End If
Next
End Sub
Sub InsertCheckBoxes(SheetName As String, CellRow As Double, CellColumn As Double, CBName As String)
Dim CellLeft As Double
Dim CellWidth As Double
Dim CellTop As Double
Dim CellHeight As Double
Dim CellHCenter As Double
Dim CellVCenter As Double
CellLeft = Sheets(SheetName).Cells(CellRow, CellColumn).Left
CellWidth = Sheets(SheetName).Cells(CellRow, CellColumn).Width
CellTop = Sheets(SheetName).Cells(CellRow, CellColumn).Top
CellHeight = Sheets(SheetName).Cells(CellRow, CellColumn).Height
CellHCenter = CellLeft + CellWidth / 2
CellVCenter = CellTop + CellHeight / 2
With Sheets(SheetName).OLEObjects.Add(classtype:="Forms.CheckBox.1", Link:=False, DisplayAsIcon:=False, Left:=CellHCenter - 8, Top:=CellVCenter - 8, Width:=16, Height:=16)
.Name = CBName
.Object.Caption = ""
.Object.BackStyle = 0
.ShapeRange.Fill.Transparency = 1#
End With
End Sub
Sub SetCBAction(SheetName)
Dim cCBEvents As clsActiveXEvents
Dim o As OLEObject
Set mcolEvents = New Collection
For Each o In Sheets(SheetName).OLEObjects
If TypeName(o.Object) = "CheckBox" Then
Set cCBEvents = New clsActiveXEvents
Set cCBEvents.mCheckBoxes = o.Object
mcolEvents.Add cCBEvents
End If
Next
End Sub
Sub RunAfter()
Call SetCBAction("Sheet1")
End Sub
Class Module (clsActiveXEvents):
Option Explicit
Public WithEvents mCheckBoxes As MSForms.CheckBox
Private Sub mCheckBoxes_click()
MsgBox "test"
End Sub
UPDATE:
On further research, there is a solution posted in the bottom answer here:
Creating events for checkbox at runtime Excel VBA
Apparently you need to force Excel VBA to run on time now:
Application.OnTime Now ""
Edited lines of code that works to resolve this issue:
Sub RunMyCheckboxes()
Dim i As Double
Call DeleteAllCheckboxesOnSheet("Sheet1")
For i = 1 To 10
Call InsertCheckBoxes("Sheet1", i, 1, "CB" & i & "1")
Call InsertCheckBoxes("Sheet1", i, 2, "CB" & i & "2")
Next
Application.OnTime Now, "SetCBAction" '''This is the line that changed
End Sub
And, with this new formatting:
Sub SetCBAction() ''''no longer passing sheet name with new format
Dim cCBEvents As clsActiveXEvents
Dim o As OLEObject
Set mcolEvents = New Collection
For Each o In Sheets("Sheet1").OLEObjects '''''No longer passing sheet name with new format
If TypeName(o.Object) = "CheckBox" Then
Set cCBEvents = New clsActiveXEvents
Set cCBEvents.mCheckBoxes = o.Object
mcolEvents.Add cCBEvents
End If
Next
End Sub
If OLE objects suit your needs then I'm glad you've found a solution.
Are you aware, though, that Excel's Checkbox object could make this task considerably simpler ... and faster? Its simplicity lies in the fact that you can easily iterate the Checkboxes collection and that you can access its .OnAction property. It is also easy to identify the 'sender' by exploiting the Evaluate function. It has some formatting functions if you need to tailor its appearance.
If you're after something quick and easy then the sample below will give you an idea of how your entire task could be codified:
Public Sub RunMe()
Const BOX_SIZE As Integer = 16
Dim ws As Worksheet
Dim cell As Range
Dim cbox As CheckBox
Dim i As Integer, j As Integer
Dim boxLeft As Double, boxTop As Double
Set ws = ThisWorkbook.Worksheets("Sheet1")
'Delete checkboxes
For Each cbox In ws.CheckBoxes
cbox.Delete
Next
'Add checkboxes
For i = 1 To 10
For j = 1 To 2
Set cell = ws.Cells(i, j)
With cell
boxLeft = .Width / 2 - BOX_SIZE / 2 + .Left
boxTop = .Height / 2 - BOX_SIZE / 2 + .Top
End With
Set cbox = ws.CheckBoxes.Add(boxLeft, boxTop, BOX_SIZE, BOX_SIZE)
With cbox
.Name = "CB" & i & j
.Caption = ""
.OnAction = "CheckBox_Clicked"
End With
Next
Next
End Sub
Sub CheckBox_Clicked()
Dim sender As CheckBox
Set sender = Evaluate(Application.Caller)
MsgBox sender.Name & " now " & IIf(sender.Value = 1, "Checked", "Unchecked")
End Sub

VBA error 424 when trying to use class method from another module

I have a class called autoCRUD in a class module in excel 2013. From another module (a regular one) I try to call a method from this class and I get the "Object required" exception.
Here's the method:
Public Function CreateCRUDView(TipoCRUD As String) 'TipoCRUD pode ser C (Create), R (Read), U (Update), D (Delete)
Dim myForm As Object
Dim NewFrame As MSForms.Frame
Dim NewButton As MSForms.CommandButton
Dim NewListBox As MSForms.ListBox
Dim NewLabel As MSForms.Label
Dim X As Integer
Dim Line As Integer
Dim t As Integer
Dim arrLeg() As Variant
arrLeg = legenda
'This is to stop screen flashing while creating form
Application.VBE.MainWindow.Visible = False
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_MSForm)
'Create the User Form
With myForm
.Properties("Caption") = "New Form"
.Properties("Width") = 300
.Properties("Height") = 270
End With
'Criar labels
t = 10
For Each lbl In arrLeg
Set NewLabel = myForm.Designer.Controls.Add("Forms.label.1")
With NewLabel
.name = "lbl_" + Replace(CStr(lbl.Value), " ", "")
.t = (10 + t)
.Left = 10
.Font.Size = 8
End With
t = t + 10
Next
'Create CommandButton Create
Set NewButton = myForm.Designer.Controls.Add("Forms.commandbutton.1")
With NewButton
.name = "cmd_1"
If UCase(TipoCRUD) = "C" Then
.Caption = "Salvar"
ElseIf UCase(TipoCRUD) = "U" Then
.Caption = "Alterar"
End If
.Accelerator = "M"
.Top = Top + 10
.Left = 200
.Width = 66
.Height = 20
.Font.Size = 8
.Font.name = "Tahoma"
.BackStyle = fmBackStyleOpaque
End With
Top = Top + 10
End Function
The code from another module that calls the method is :
Public Sub Main()
Dim ac As autoCrud
Set ac = New autoCrud
ac.CreateCRUDView ("c")
End Sub
I don't get it, why am I getting this error?
Here is the code for "legenda":
Public Property Get sht() As Worksheet
Const shtName As String = "Teste1"
Set sht = ActiveWorkbook.Worksheets(shtName)
End Property
Public Property Get legenda() As Range
Const linha As Integer = 3
Const colunaI As Integer = 2
Dim colunaF As Integer
Dim i As Integer
i = colunaI
Do While sht.Cells(linha, i).Value <> ""
i = i + 1
Loop
colunaF = (i - 1)
Set legenda = sht.Range(Cells(linha, colunaI), Cells(linha, colunaF))
End Property
The lbl.Value is supposed to be a string value, the name of the label. And it comes from the spread sheet in the header of the table, teh legenda() only selects that header and the arrLeg takes the legenda as a range and transforms it in an array.
Edit:
Apparently the error occurs in the line that says: .name = "lbl_" + Replace(CStr(lbl.Value), " ", "")
As you can see, I've tried to take the spaces from the string and also ensure that it is a string, but none of it worked.
Edit 2:
I actually just use a class for organization and re-usability purposes. I take the properties and other methods and use them inside the 'createCRUDView' method, this method will then create a CRUD View, that is, create a form either to "Create", "Read" (not used since it's excel),"Update or "Delete" data entries. It basically creates forms dynamically to any table you make
VBA error 424 is object required error. So I'm now pretty sure that lbl in CStr(lbl.Value) is not an object. With your code legenda is a Range but after
Dim arrLeg() As Variant
arrLeg = legenda
arrLeg will be a variant array. This array does not contain objects. You can debug this with
For Each lbl In arrLeg
...
MsgBox TypeName(lbl)
...
Next
So you should use CStr(lbl).
And
Set legenda = sht.Range(Cells(linha, colunaI), Cells(linha, colunaF))
will only work while the "Teste1" sheet is the ActiveSheet because Cells(linha, colunaI) is not explicit assigned to a sheet so the ActiveSheet will be supposed.
Set legenda = sht.Range(sht.Cells(linha, colunaI), sht.Cells(linha, colunaF))
will be better.

Resources