I am trying to see all the labels in Me.Controls and when I use:
For Each Control As Label In Me.Controls.OfType(Of Label)()
MsgBox(Control.Name.ToString)
Next
it only shows the labels that have NOT been renamed. Am I doing something wrong here?
For the most part, your code looks right, unless you have labels inside other container controls like Panels and GroupBoxes. In which case, you would need to loop through those containers, too.
Here is an example:
Dim allContainers As New Stack(Of Control)
allContainers.Push(Me)
While allContainers.Count > 0
For Each item As Control In allContainers.Pop.Controls
If item.Controls.Count > 0 Then
allContainers.Push(item)
End If
If TypeOf item Is Label Then
MessageBox.Show("Label.Name = " + item.Name)
End If
Next
End While
Related
I'm making a form that has a few hundred labels, and when a Clear button is clicked, I need to reset the text of specific labels to 0 while leaving other label's text alone. I don't want to use a group box because it will not look good with my current layout.
I'm trying to use the code:
For Each cnt In Me.Controls
If TypeOf cnt Is Label Then
CType(cnt, Label).Text = ""
End If
Which works fine for clearing every Label, but I want to specify a specific Tag as well. I tried
For Each cnt In Me.Controls
If TypeOf cnt Is Label And CType(cnt, Label).Tag = "ResetTo0" Then
CType(cnt, Label).Text = ""
End If
When I try to use this code, I get a cast exception error.
Does anyone know how I can add in my tag as well without getting a cast error, or a better way to do this?
Just use the extension OfType to get only labels and already of the right type
For Each cnt In Me.Controls.OfType(Of Label)
If cnt.Tag = "ResetTo0" Then
cnt.Text = ""
End If
Next
And if not all labels have the Tag property set then add also a check for Nothing
if cnt.Tag IsNot Nothing AndAlso cnt.Tag = "ResetTo0" Then
.....
End if
You can even try with a single line (albeit I suspect that this approach is not the best for clarity and performance)
Me.Controls.OfType(Of Label).
Where(Function(x) x.Tag = "ResetTo0").
ToList().
ForEach(Function(k) k.Text = "")
I have many labels. When a label is clicked, I change the BackColor to aqua. When I click on another label, both of them are aqua, but I want the color of the first label to go back to normal. It there a way to do that?
Here is my code:
Dim clickedLabel = TryCast(sender, Label)
If clickedLabel IsNot Nothing Then
clickedLabel.BackColor = Color.Aqua
TextBox1.Text = clickedLabel.Text
Else
End If
Put them all in a collection so that you can apply the default-color on all others or - if they are all in the same container-control like a Panel - use this code:
For Each lbl In LabelPanel.Controls.OfType(Of Label)()
clickedLabel.BackColor = If(lbl Is clickedLabel, Color.Aqua, DefaultColor)
Next
TextBox1.Text = clickedLabel.Text
Instead of LabelPanel.Controls you could also use Me.Controls, but then all labels on the form are used even if it's not related. Labels that are in other container controls won't be find in this way anyway, so no recursive search.
DefaultColor is a System.Drawing.Color that you store as class/member variable(shared or as instance-variable).
Call me crazy but for the life of me I cannot make this work. I have the following code:
Dim cControl As Control
For Each cControl In Me.Controls
If (TypeOf cControl Is Button) Then
cControl.ForeColor = Color.Black
cControl.Font = New Font(cControl.Font, FontStyle.Regular)
End If
Next cControl
Me.ActiveControl.ForeColor = Color.Blue
Me.ActiveControl.Font = New Font(Me.ActiveControl.Font, FontStyle.Bold)
I am trying to make the font black and regular for all of the buttons on the form (there are a lot) and the button just clicked, bolded and blue.
The second part of the code works (making the font bold and blue), it's the first that is not simply working.
What am I missing?
I've never tried it like that before, but I have used Linq to accomplish what you want.
Dim btn() As Button
btn = Me.Controls.OfType(Of Button)().Where(Function(c) c.Name.Contains("")).ToArray()
This will basically create an array of buttons from your form, then you can just loop through each one.
Dim i As Integer = 0
While i < btn.Count
btn(i).Enabled = True
btnText(i).BackColor = Color.DarkOliveGreen
btnText(i).ForeColor = Color.White
i += 1
End While
If you have a naming convention for your buttons and want to only change certain buttons where the empty quotes are you can have "btnTest".
Then you will have an index of any button that contains the text "btnTest" in it. So that would include "btnTest1", "btnTest2", "btnTestAnything1234" etc.
Hope this helps and you can use it!
Nevermind I found my problem. The buttons are in a group box so I had to reference the group box directly
I have created a function to translate my forms. I can loop through every control in a form to call this function, but I have made a situation, I cannot handle.
In one of my forms, I have groupbox in a groupbox.
This source works if I only have one groupbox.
Public Function translate_form(ByVal form As Form)
Dim control As Object
Dim controlname As String
form.Text = Get_Control_Name(form.Name, "Form")
Try
For i = 0 To form.Controls.Count - 1
control = form.Controls(i)
If TypeOf (control) Is MenuStrip Then
For j = 0 To control.items.count - 1
control.items(j).text = Get_Control_Name(form.Name, "MenuItem" & j)
Next
Else
controlname = Get_Control_Name(form.Name, control.Name)
control.Text = IIf(controlname Is Nothing, control.Text, controlname)
If TypeOf (control) Is GroupBox Then
For j = 0 To control.Controls.Count - 1
controlname = Get_Control_Name(form.Name, control.Controls(j).Name)
control.Controls(j).Text = IIf(controlname Is Nothing, control.Controls(j).Text, controlname)
If TypeOf (control.Controls(j)) Is Button Then
control.Controls(j).AutoSize = True
End If
Next
End If
If TypeOf (control) Is Button And UCase(control.Text) <> "X" Then
control.AutoSize = True
End If
End If
Next
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical)
End Try
End Function
But in some cases I want to sperate controls inside a container. I could have one more loop if the
control.Controls(j)
is a groupbox but I want to make this function to handle any kind of "container pyramid", if you know what I mean. Maybe I will have a container which has one also and that one too etc... Or is there any control I can use as a groupbox but it doesn't count as a contaier, so I can see it with:
form.Controls
Any suggestions?
Thanks in advance.
The reason why your code does not deliver what you want is that you are not performing a recursive search of controls. Bear in mind that Form.Controls contains only the parent controls (not the children controls eventually contained by the parents; like the situation you refer of controls contained by a GroupBox). Additionally, I see various not-too-right issues (you should writeOption Strict On on the top of your file) and that's why this answer intends to provide you with a somehow better framework to work with (you have just to fill in the blanks with your code):
Public Sub translate_form2(ByVal form As Form)
Try
For Each ctrl As Control In form.Controls
actionsCurrentControl(ctrl)
recursiveControls(ctrl)
Next
Catch ex As Exception
End Try
End Sub
'Accounting for all the child controls (if any)
Public Sub recursiveControls(parentControl As Control)
If (parentControl.HasChildren) Then
For Each ctrl As Control In parentControl.Controls
actionsCurrentControl(ctrl)
recursiveControls(ctrl)
Next
End If
End Sub
Public Sub actionsCurrentControl(curControl As Control)
If TypeOf curControl Is MenuStrip Then
Else
If TypeOf (curControl) Is GroupBox Then
End If
If TypeOf (curControl) Is Button And UCase(curControl.Text) <> "X" Then
End If
End If
End Sub
translate_form2 iterates through all the parent controls as in your code (but by relying on a set of Subs (you are wrongly using a Function without returning any value, what is wrong), making the structure more adaptable); it also calls recursiveControls (which also calls itself for each control it analyses) to take care of any child control which might be present. I am also including actionsCurrentControl which contains all the actions to perform for each control (you have to populate it with your code).
I am creating a chess program. And it is composed of sixty four picture boxes with alternating black and white background colours.
I have named them pba1, pba2, pbb1, pbb2, pbc1 and so on.
Now, I want to loop through only the black ones, for example, I want to loop through only, pba1, pbb2, pbc3 and so on.
How do I create a loop for this in VB.NET?
I know of the way to loop through similarly named controls, but I am not able to adapt that method for my problem. Can you tell me a solution?
EDIT: In pba1, pb stands for picture box, and a1 stands for the square. Just in case, you wonder why such a name.
EDIT: Check out this answer
Loop through the PictureBox's in your ControlCollection and test for BackColor. I used the Form's ControlCollection, if they are in some other type of container control use that.
For Each cntrl As Control In Me.Controls
If TypeOf cntrl Is PictureBox Then
If cntrl.BackColor = Color.Black Then
'Do Something
End If
End If
Next
Base on the additional information that you gave in your answer, the reason your example is not working is that the Controls Name is a String and you are comparing it to the PictureBox Control not the Name of the Control.
You can try using the Tag Property instead of the Name of the Control, it will be cleaner and easier to read. I just put a 1 in the PictureBox's Tag Property for Black and a 0 for White.
Private Sub OriginalColour()
For Each cntrl As Control In Me.Controls
Dim result As Integer
If TypeOf cntrl Is PictureBox Then
If Integer.TryParse(cntrl.Tag.ToString, result) Then
If result = 1 Then
cntrl.BackColor = Color.Gray
Else
cntrl.BackColor = Color.White
End If
End If
End If
Next
End Sub
Generating controls at design time via the Forms Designer only makes sense for layouts which benefit from the forms designer.
In your case, you just have 64 uniform boxes in 8 rows of 8. Don’t use the Forms Designer for this, create the controls at runtime, and don’t give them names like pba1, just put them into an appropriate data structure (such as an 8x8 array):
Private chessFields As PictureBox(8, 8)
' In Form_Load:
For i = 0 To 7
For j = 0 To 7
chessFields(i, j) = New PictureBox
' Set size, position … then, finally,
Controls.Add(chessFields(i, j))
Next
Next
That way, you can access the fields in an orderly fashion without having to go via the Form.Controls collection.
Put all the pictureboxes in an 8x8 tableLayoutPanel (also useful for scaling etc). Then
For Each pb As PictureBox In TableLayoutPanel1.Controls
Dim col As Integer = TableLayoutPanel1.GetCellPosition(pb).Column
Dim row As Integer = TableLayoutPanel1.GetCellPosition(pb).Row
If col Mod 2 = 0 Xor row Mod 2 = 0 Then
pb.BackColor = Color.Black
Else
pb.BackColor = Color.White
End If
Next
Of course you could also use an array of the squares if you have that available.
This will not affect the events (pba1.click etc).
This is fairly simple and it may be resource heavy, but it works. I have a form with 36 CheckBoxes. This takes advantage of the fact that when you copy a checkbox it just increases the number of the name. I ended up with 36 checkboxes named CheckBox1 thru Checkbox36. The Function returns a checkbox, which may be used to set or read any property.
Private Function GetCheckBox(ByVal Index As Integer) As CheckBox
Dim CKBox As checkbox
For Each cntrl As Control In Me.Controls
If TypeOf cntrl Is CheckBox Then
CKBox = cntrl
If CKBox.Name = "CheckBox" & Index Then
Exit For
End If
End If
Next
Return ckbox
End Function