The solution presented below (code and form with the test result) was made using "Controls" to treat the objects of each group.
Private Sub CommandButtonTeste_Click()
Dim Bandeira As Variant
'Pega o ícone da bandeira desejada
Set Bandeira = LoadPicture("F:\Teste\Japao.ico")
'Teste #1: Altera todos os dados do primeiro grupo
GrupoDeObjetos 1, True, True, _
"Japão", _
Bandeira, _
"Arroz", _
"Perda", _
"Troca"
'Teste #2: Torna os objetos do Segundo grupo invisíveis
GrupoDeObjetos 2, False, True
'Teste #3: Desabilita os objetos do terceiro grupo
GrupoDeObjetos 3, True, False
'Teste #4: Força um erro, pois o grupo 4 não existe
GrupoDeObjetos 4, True, True
End Sub
Public Sub GrupoDeObjetos( _
ByVal IndiceDoGrupo As Integer, _
ByVal GrupoVisivel As Boolean, _
ByVal GrupoHabilitado As Boolean, _
Optional ByVal LegendaDoFrame As String = "", _
Optional ByVal Imagem As Variant = "", _
Optional ByVal LegendaDaImagem As String = "", _
Optional ByVal LegendaDoBotao1 As String = "", _
Optional ByVal LegendaDoBotao2 As String = "")
Dim i As Integer
'Verifica o índice
If IndiceDoGrupo < 1 Or IndiceDoGrupo > 3 Then
Beep
MsgBox "Índice do Grupo de Objetos inválido!" & _
Chr(13) & Chr(13) & _
"Índice: " & IndiceDoGrupo
Exit Sub
End If
'Tratamento dos objetos do grupo
' Atualiza o índice do grupo com o valor
' do índice dos controles no formulário
Select Case IndiceDoGrupo
Case 1
'Índice do Frame1 no formulário
IndiceDoGrupo = 0
Case 2
'Índice do Frame2 no formulário
IndiceDoGrupo = 5
Case 3
'Índice do Frame3 no formulário
IndiceDoGrupo = 11
End Select
'Atualiza dados do objeto se os dados foram passados
If LegendaDoFrame <> "" Then Me.Controls(IndiceDoGrupo).Caption = LegendaDoFrame
If Imagem <> "" Then Me.Controls(IndiceDoGrupo + 1).Picture = Imagem
If LegendaDaImagem <> "" Then Me.Controls(IndiceDoGrupo + 2).Caption = LegendaDaImagem
If LegendaDoBotao1 <> "" Then Me.Controls(IndiceDoGrupo + 3).Caption = LegendaDoBotao1
If LegendaDoBotao2 <> "" Then Me.Controls(IndiceDoGrupo + 4).Caption = LegendaDoBotao2
'Trata os objeto do grupo (Visible/Enabled)
For i = 0 To 4
'Grupo visível ou não
Me.Controls(IndiceDoGrupo + i).Visible = GrupoVisivel
'Grupo habilitado ou não
Me.Controls(IndiceDoGrupo + i).Enabled = GrupoHabilitado
Next i
End Sub
Note on the code that the Indicedogrupo is a single variable treated in two different ways:
1. When calling the routine this index points to the desired group, in this case the groups of values 1, 2 and 3.
2. In the code, depending on the group chosen to handle, this variable receives the index value of the Frame of the group, in this case 0, 5 and 11 respectively for the groups 1, 2 and 3.
Notice that each group has 5 objects, such as the group 2 was created immediately after the group 1, the content of your Frame is the 5. (Group 1 objects have the indices: 0, 1, 2, 3 and 4)
The difference in the group 3 was 11 and not 10, is that the Label3 was inserted in the form before that group, therefore the Label3 got the index 10.
IMPORTANT!
For this code to work properly, when creating your group of objects insert each group object in the sequence you want to work, and do not insert any object other than this group until it is finished.
Group him, put in the toolbox and ready, just treat the content of each new object you put in the form (in this case starting from 1).
This is the test results:
Note that there are four tests, but I did not present the dialog box generated by the purposeful error of test #4 (it was closed before the Printscreen), to make it easy to identify in the image above what happened:
1. All data from group 1 were changed, including the image of the flag
2. The group 2 became invisible
3. The group 3 was disabled, however, although the image is also disabled, it is not "faded" (I did not do this effect in the example)
4. The error message caused by calling a fourth group that does not exist in the form generated the appropriate error message (I did not submit)
COMPLEMENT
If the Label3 is deleted from the form, the index of the third object will change, to solve this one can create a routine to fetch the index of the first object of the group when initializing the form, for example.
Simple suggestion of routine call:
Dim Indice1, Indice2, Indice3 as Integer
Indice1 = IndiceDoObjeto(UserForm1, "Frame1")
Indice2 = IndiceDoObjeto(UserForm1, "Frame2")
Indice3 = IndiceDoObjeto(UserForm1, "Frame3")
If the object is not located in the form I would indicate inform by means of a message and exit the program immediately after the message, because it does not make sense to continue having this type of error.
This way no errors will occur when manipulating objects between groups.
ORGANISATION IN THE ORDER OF THE CONTENTS OF OBJECTS IN THE GROUP
When working with groups of this type (much more extensive), I came across a problem that can occur in two ways:
If the objects of a group were not created in the desired or intuitive order (from the top left to the bottom right), the index of each object in the group will evidently not follow this order, which makes it difficult - at least - the initial treatment of these in the code.
If you change the position or order of the object in the form, with "Bring Forward" or "Send Back", for example, the contents of the objects in the form are changed, then it may occur that a group object is "replaced" by another in the treatment to group objects or even all objects have their contents changed (in case of bringing forward an object that was created before the group).
As a solution, I did a test, I started to sort the objects as desired, so that their indexes were in the order "intuitive". To do so, I did this in a new form, so there is no problem with other objects that could interfere in this process.
So, without having to "regroup", because they remained "grouped" even with the resources of type "Forward" and "Retreat", for example, at the end I put it in the toolbox.
At this time, this new group was ordered as desired, that is, when inserting it in any form, the order of the indexes of its objects keep the order in which I changed in the group.
SOLICITING
Where there are other ways of doing so, including through Object classes with properties to pass this data, if you can post here an example I would be very grateful!
Okay, I understand the "problem". But the question is? So what? What does this "malformation" of names prevent or harm you? The fact that you have Frame3, Image3, ..., Label4, ... is it really a problem? If you happen to have code that manipulates these elements assuming their names will always have the same ending number, maybe that was a bad choice. To have a generic code, it would not be easier (and correct) to access objects within the frame (the main container object) through the property
Controls
frame?– Luiz Vieira
For example: https://social.msdn.microsoft.com/Forums/office/en-US/d411f921-998c-4d8f-a4be-fcb5034642c9/excel-vba-iterate-controls-inside-frame?forum=exceldev
– Luiz Vieira
Luiz, I am already preparing with the Controls that in my case is laborious (involves several Abels and images for graphic resources that I have as default), I will do for this example and put here, but I would like to know if it was not the case to create a Class. I don’t know how to work with classes and it seems that through them I can also create properties.
– Leo
A question that will help a lot, how do I know the id or index of a specific object, without having to "scan" all the form objects to find it? With this I solve the problem easily and directly.
– Leo
Yes, it has how to know the specific index. It is in the order of creation. So, since you generated a "template" on Toolbar, the elements will be created in the same order. So picking up by the index is also a good idea. : ) About classes, you are right. Maybe it is the best way. I have very little experience with OO in VBA, but certainly has a lot.
– Luiz Vieira
Okay, what I really wanted to know is if you have a function that returns the object index, for example: id = Indicedoobject(Label5), of course I can create this function, but would it have something like this in the VBA? I haven’t located.
– Leo
But if you’re going to take the object index by name, it’s no use. It’s easier to get the name. I figured you’d store the fixed indexes, and then pick up via
Controls(indice)
.– Luiz Vieira
Hi Luiz, did not understand your comment, you thought of something different from what I presented in the reply? I used fixed indexes both to identify each group of objects, and to identify each object within their group, the Controls(index). What would be the other option?
– Leo
So, actually I had imagined that the indexes would work differently in VBA: with hierarchy of children when adding a control within a frame, so the indexes would be by "father" control. Because if you do it like this, the way you answer it, it will be unviable, right? (if Label3 does not exist, your code no longer works).
– Luiz Vieira
You are right, in the professional version I made a routine for when the form initialize is searched for the id of the object by its name (the id would be the index according to the respective Control in the form, searched within a For Next), for example: id = Indicedoobject(Userform1, "Frame3"). If the object is not found, I inform and finish the program to hit the error. Thus, the insertion or deletion of objects is indifferent, provided that objects belonging to a group are not deleted.
– Leo