Caselle di testo dinamiche inserite in un UserForm
Recentemente mi è stata posta questa domanda: “Si può inserire in una UserForm un numero variabile, fissato a run-time (magari tramite opportuna macro VBA) di caselle di testo?” La richiesta è inusuale, visto che il più delle volte una UserForm viene definita al tempo di progetto. Con un po’ di pazienza, frugando nella Guida dell’Editor VBA, ho trovato la risposta, di cui riporto un tipico esempio in fondo a questo post. Adattandolo al caso che tormentava il nostro amico ho escogitato una prima macro di test, sull’evento Click dell’unico pulsante di una UserForm1, per il resto vuota di altri controlli:
Private Sub CommandButton1_Click()
Dim miaTxtBox As Control
Set miaTxtBox = Controls.Add("Forms.TextBox.1", "miaCasella", True)
With miaTxtBox
.Left = 18
.Top = 150
.Width = 175
.Height = 20
End With
Me.Controls("miaCasella").Value = InputBox("Scrivi...")
End Sub
L’istruzione basilare, grassettata, ha la seguente sintassi:
Controls.Add(“<Tipo ctrontrollo>”, “Nome”,
E ha l’effetto di aggiungere (metodo Add) all’insieme dei Controls una TextBox definita come “Forms.Textbox.1” – mentre analoghe sintassi valgono per altri controlli come il "MSForms.CommandButton.1” esemplificato dalla Guida e altri di pari eloquenza. Il terzo argomento va prudentemente posto a True assicurando la visibilità della neonata casella impostata nella MiaTxtBoz (di tipo Control, ovviamente). Dopo di che a MiaTxtBox sono assegnati, dinamicamente, proprietà relative al posizionamento e alle dimensioni e, infine, vi viene inserito il valore stabilito dall’utente in risposta a una InputBox.
Come i più svegli subito notano nell’ultima istruzione si ricorre, in alternativa a miaTextBox, al nome “miaCasella”, secondo nome facoltativo di Controls.Add.
Se poi si vuole lanciare la UserForm1 non resta che lanciare una macro bene nota come questa:
Sub UserFormDinamica()
Load UserForm1
UserForm1.Show
End Sub
Una variante appena un po’ più elaborata è la seguente, che crea ben due (“e regali..”, dicono a Livorno) casellineficcandovi due scemenze:
Dim CaselleAggiunte As Boolean
Private Sub CommandButton1_Click()
If Not CaselleAggiunte Then
Me.Controls.Add "Forms.TextBox.1", "Casella1", True
Me.Controls.Add "Forms.TextBox.1", "Casella2", True
With Me.Controls("Casella2")
.Left = 50
.Top = 50
End With
CaselleAggiunte = True
End If
Me.Controls("Casella1") = "ambarabà"
Me.Controls("Casella2") = "Ciccì coccò"
End Sub
Il punto più rilevante è dato dalle istruzioni “creative” la cui sintassi è nata dalla scoperta che non occorre nessuna variabile per registrare il nuovo controllo, basta invocare il medoto Add dell’insieme Controls dell’UserForm corrente, ovvero Me.Controls.
Creazione dinamica di N casella all’apertura dell’UserForm
Dopo i precedenti esperimenti, torniamo all’esigenza iniziale ovvero, ricordate?, aggiungere un numero di TexBox definite di volta in volta. In tale prospettiva, si compiano le mosse seguenti:
1. Creare un UserForm2
2. Aggiungervi come prima un solo CommandButton1, magari dotato di Caption “Caselle dinamiche” in luogo del default “UserForm2”;
3. Digitare la macro dell’evento Initialize:
Private Sub UserForm_Initialize()
Dim i As Integer, N As Integer
Dim NomeCasella As String
Dim Cima As Integer
N = Range("NumCaselle")
Cima = 10
Me.Height = N * 25 + 75
CommandButton1.Top = Me.Height - 50
' If N > 10 Then N = 10 ' Limitazione num. caselle? Non serve col combo...
For i = 1 To N
NomeCasella = "Casella" & i
Me.Controls.Add "Forms.TextBox.1", NomeCasella, True
With Me.Controls(NomeCasella)
.Left = 50
.Height = 20
.Width = 150
.Top = Cima
End With
Cima = Cima + 25
Next
End Sub
Commenti tacitiani. Il valore N è attinto da una cella del foglio di lavoro preliminarmente battezzata “NumCaselle”, ove l’utente dovrà stabilire appunto il desiato numero caselle. Il clou sta nel ciclo For i = 1 To N in seno al quale vengono via via fissato un NomeCasella pari a “ Casella” & i vale a dire “Casella1”, “Casella2” e così via. Il dimensionamento Me.Heigth dell’altezza del Form in modo da adeguarsi alle N caselle (ciascuna di altezza, Height, pari a 20) + 5 spazi tra le stesse è lasciato all’esegesi autogestita. Idem il posizionamento del Top del CommandButton1, sottostante alla N caselline ma senza sparire.
E la Sub dell’evento Click di quest’ultimo? Eccone una ipotetica, che segnala (MsgBox) i nomi delle N caselle create inserendovi man mano numeri casuali. Tanto per fare qualcosa, nei casi personali ognuno personalizzerà questa faccenda.
Private Sub CommandButton1_Click()
Dim Ctrl As Control
For Each Ctrl In Me.Controls
If Left(Ctrl.Name, 7) <> "Command" Then
Randomize
Ctrl = Int(Rnd * 100000 + 100)
MsgBox Ctrl.Name
End If
Next
End Sub
Concludo suggerendo, in luogo del controllo del numero massimo N = 10, un combo box sul foglio di lavoro associato alla predetta cella di nome”NumCaselle”.
Ultimissima variante
Consiste nell’omissione del secondo argomento di Controls.Add, nel qual caso la caselle di testo via via create assumono i nomi default o standard che dir si voglia “TextBox1” ,” TextBox2”, eccetera.
Private Sub UserForm_Initialize()
Dim i As Integer, N As Integer
Dim Cima As Integer
N = Range("NumCaselle")
Cima = 10
Me.Height = N * 25 + 75
CommandButton1.Top = Me.Height - 60
For i = 1 To N
Me.Controls.Add "Forms.TextBox.1", , True
With Me.Controls(i)
.Left = 50
.Height = 20
.Width = 150
.Top = Cima
End With
Cima = Cima + 25
Next
End Sub
L’esempio della Guida
Esempio dell'evento AddControl e del metodo Add
In questo esempio il metodo Add viene utilizzato per aggiungere un controllo a un form in fase di esecuzione. L'evento AddControl viene utilizzato per verificare se il controllo è stato aggiunto.
Per eseguire l'esempio, copiare il codice riportato di seguito nella sezione Dichiarazioni di un form. Verificare che il form contenga:
· Un controllo CommandButton (CommandButton1).
· Un controllo Label (Label1).
Dim Mycmd as Control
Private Sub CommandButton1_Click()
Set Mycmd = Controls.Add("Forms.CommandButton.1") ', CommandButton2, Visible)
Mycmd.Left = 18
Mycmd.Top = 150
Mycmd.Width = 175
Mycmd.Height = 20
Mycmd.Caption = "This is fun." & Mycmd.Name
End Sub
Private Sub UserForm_AddControl(ByVal Control As _
MSForms.Control)
Label1.Caption = "Control was Added."
End Sub
Nota. Qui osservo, solamente, che a) definire a livello Dichiarazione la variabile Mycmd (o la mia Casella nel caso di una TextBox) non è indispensabile, come ho mostrato nei miei esempietti; b) il secondo pulsante di comando Mycmd creato di fatto non serve quasi a nulla, non potendo associarvi routine d’evento (possibilità speciale ammessa in VB .NET). Lo stesso vale per le nostre caselle di cui però si può modificare il valore.
?>