I'm confused as to why this isn't working...
Here's a brief description of what I've declared my buttons dynamically as the form loads because the form resizes itself depending on whats selected. I've named the buttons button1 and button2. I've added a handler to button2 to handle when the button gets clicked. GetButtonColl is called after the buttons are created and I verified it's populated with the buttons on the form. Why doesn't a simple .enable property work on these dynamically created buttons? Is there something I need to do different?
Here's a condensed version of my code:
Public buttonColl As New List(Of Button)
'---------------------------------------------------------------------------------------------------------------
' Function: GetButtonColl
' Parameters: none
' Returns: none
' Description: Loops through all the controls on the form and searches for buttons that were created after the form has been resized
' and adds them to a List which will be used to quickly control the buttons properties throughout the session
'----------------------------------------------------------------------------------------------------------------
Public Sub GetButtonColl()
For x As Integer = 0 To Me.Controls.Count - 1
Dim b As Control = TryCast(Me.Controls(x), Control)
If b IsNot Nothing AndAlso b.Tag Is Nothing Then
If TypeOf (b) Is Button Then
buttonColl.Add(b)
End If
End If
Next
End Sub
Public Sub button1_Handler(ByVal sender As Object, ByVal e As System.EventArgs)
Try
For Each bttn As Button In buttonColl
If bttn.Name = "button2" Then
bttn.Enabled = False
End If
Next
Catch ex As Exception
End Try
End Sub
Here's how I'm creating my buttons through the code:
btn = New System.Windows.Forms.Button
With btn
.Enabled = true
.Location = New System.Drawing.Point(9, 332)
.Size = New System.Drawing.Size(122, 26)
.Name = "button1"
.Text = "TestButton"
.BackColor = System.Drawing.SystemColors.Control
.Cursor = System.Windows.Forms.Cursors.Default
.Font = New System.Drawing.Font("Arial", 11.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
.ForeColor = System.Drawing.SystemColors.ControlText
.RightToLeft = System.Windows.Forms.RightToLeft.No
.TabIndex = TabIndex
.UseVisualStyleBackColor = False
End With
Me.Controls.Add(btn)
Simplify. The sender object is the button clicked on just cast it back.
Public Sub button1_Handler(ByVal sender As Object, ByVal e As System.EventArgs)
Dim btn As Button = DirectCast(sender, Button)
If btn.Name = "button2" Then
btn.Enabled = False
End If
End Sub
btn = New System.Windows.Forms.Button
With btn
.Enabled = true
.Location = New System.Drawing.Point(9, 332)
.Size = New System.Drawing.Size(122, 26)
.Name = "button2" 'wouldn't this be button2?
.Text = "TestButton"
.BackColor = System.Drawing.SystemColors.Control
.Cursor = System.Windows.Forms.Cursors.Default
.Font = New System.Drawing.Font("Arial", 11.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
.ForeColor = System.Drawing.SystemColors.ControlText
.RightToLeft = System.Windows.Forms.RightToLeft.No
.TabIndex = TabIndex
.UseVisualStyleBackColor = False
Addhandler btn.Click, AddressOf button1_Handler 'add the delegate
End With
Me.Controls.Add(btn)
Also add the Button to the List when you create it, if you need it in a List.
Are the buttons directly contained within the form, or are they inside another panel? Looping through me.controls will not get grandchild controls, it isn't recursive.
Related
I have a form with a SplitContainer in dock fill. In panel 1 of the split container I have buttons, in panel 2, I have a UserControl in dock fill. The Usercontrol classes in panel2 change depending on buttons clicked in panel1 but is kept dock fill.
Each Usercontrol have a minimum size.
The MinimumSize of the form is recalculate every time I change UCs and also when I move the splitter. This looks perfectly fine.
When I resize the form manually, everything follow as intended by default : fine. Meaning, the form can't be resized under minimum size value.
When I move the splitter manually, everything follow as intended by default : fine. Meaning, panel 1 and panel 2 UC resize as well as all the children.
But, when at any given moment if the form is at minimum size and I try to move the slider. The form resize properly to allow panel 2 UC minimum size to fit BUT the UC doesn't resize...
Any idea why and how to fix it?
As suggested, I simplified the application to a minimum and here is the code of the MainForm :
Public Class MainForm
Private Sub SetMinSize()
Dim borderWidth = Me.Width - Me.ClientSize.Width
Me.MinimumSize = New Size(borderWidth + Me.SplitContainerMain.Panel1.Size.Width + Me.SplitContainerMain.SplitterWidth + Me.MainUserControl.MinimumSize.Width,
Me.MinimumSize.Height)
End Sub
Private Sub MainUserControl_ControlAdded(sender As Object, e As ControlEventArgs)
Me.SetMinSize()
End Sub
Private Sub SplitContainerMain_SplitterMoved(sender As Object, e As SplitterEventArgs) Handles SplitContainerMain.SplitterMoved
Me.SetMinSize()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.SuspendLayout()
Me.SplitContainerMain.Panel2.Controls.Remove(Me.MainUserControl)
Try ' The try catch avoid error in case the handle is not created
RemoveHandler Me.MainUserControl.ControlAdded, AddressOf Me.MainUserControl_ControlAdded
Catch ex As Exception
End Try
Me.MainUserControl.Dispose()
Me.MainUserControl = New UC1UserControl
Me.MainUserControl.Dock = DockStyle.Fill
Me.SplitContainerMain.Panel2.Controls.Add(Me.MainUserControl)
AddHandler Me.MainUserControl.ControlAdded, AddressOf Me.MainUserControl_ControlAdded
Me.ResumeLayout()
Me.SetMinSize()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Me.SuspendLayout()
Me.SplitContainerMain.Panel2.Controls.Remove(Me.MainUserControl)
Try ' The try catch avoid error in case the handle is not created
RemoveHandler Me.MainUserControl.ControlAdded, AddressOf Me.MainUserControl_ControlAdded
Catch ex As Exception
End Try
Me.MainUserControl.Dispose()
Me.MainUserControl = New UC2UserControl
Me.MainUserControl.Dock = DockStyle.Fill
Me.SplitContainerMain.Panel2.Controls.Add(Me.MainUserControl)
AddHandler Me.MainUserControl.ControlAdded, AddressOf Me.MainUserControl_ControlAdded
Me.ResumeLayout()
Me.SetMinSize()
End Sub
End Class
And this is the designer:
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class MainForm
Inherits System.Windows.Forms.Form
'Form remplace la méthode Dispose pour nettoyer la liste des composants.
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'Requise par le Concepteur Windows Form
Private components As System.ComponentModel.IContainer
'REMARQUE : la procédure suivante est requise par le Concepteur Windows Form
'Elle peut être modifiée à l'aide du Concepteur Windows Form.
'Ne la modifiez pas à l'aide de l'éditeur de code.
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
Me.SplitContainerMain = New System.Windows.Forms.SplitContainer()
Me.Button2 = New System.Windows.Forms.Button()
Me.Button1 = New System.Windows.Forms.Button()
Me.MainUserControl = New UserControl()
CType(Me.SplitContainerMain, System.ComponentModel.ISupportInitialize).BeginInit()
Me.SplitContainerMain.Panel1.SuspendLayout()
Me.SplitContainerMain.Panel2.SuspendLayout()
Me.SplitContainerMain.SuspendLayout()
Me.SuspendLayout()
'
'SplitContainerMain
'
Me.SplitContainerMain.Dock = System.Windows.Forms.DockStyle.Fill
Me.SplitContainerMain.FixedPanel = System.Windows.Forms.FixedPanel.Panel1
Me.SplitContainerMain.Location = New System.Drawing.Point(0, 0)
Me.SplitContainerMain.Name = "SplitContainerMain"
'
'SplitContainerMain.Panel1
'
Me.SplitContainerMain.Panel1.Controls.Add(Me.Button2)
Me.SplitContainerMain.Panel1.Controls.Add(Me.Button1)
Me.SplitContainerMain.Panel1MinSize = 170
'
'SplitContainerMain.Panel2
'
Me.SplitContainerMain.Panel2.Controls.Add(Me.MainUserControl)
Me.SplitContainerMain.Panel2MinSize = 0
Me.SplitContainerMain.Size = New System.Drawing.Size(784, 561)
Me.SplitContainerMain.SplitterDistance = 170
Me.SplitContainerMain.TabIndex = 0
'
'Button2
'
Me.Button2.Location = New System.Drawing.Point(40, 110)
Me.Button2.Name = "Button2"
Me.Button2.Size = New System.Drawing.Size(75, 23)
Me.Button2.TabIndex = 1
Me.Button2.Text = "Button2"
Me.Button2.UseVisualStyleBackColor = True
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(40, 41)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(75, 23)
Me.Button1.TabIndex = 0
Me.Button1.Text = "Button1"
Me.Button1.UseVisualStyleBackColor = True
'
'MainUserControl
'
Me.MainUserControl.Dock = System.Windows.Forms.DockStyle.Fill
Me.MainUserControl.Location = New System.Drawing.Point(0, 0)
Me.MainUserControl.Name = "MainUserControl"
Me.MainUserControl.Size = New System.Drawing.Size(610, 561)
Me.MainUserControl.TabIndex = 0
'
'MainForm
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.AutoSize = True
Me.ClientSize = New System.Drawing.Size(784, 561)
Me.Controls.Add(Me.SplitContainerMain)
Me.MinimumSize = New System.Drawing.Size(800, 600)
Me.Name = "MainForm"
Me.Tag = ""
Me.Text = "Demo"
Me.SplitContainerMain.Panel1.ResumeLayout(False)
Me.SplitContainerMain.Panel2.ResumeLayout(False)
CType(Me.SplitContainerMain, System.ComponentModel.ISupportInitialize).EndInit()
Me.SplitContainerMain.ResumeLayout(False)
Me.ResumeLayout(False)
End Sub
Friend WithEvents SplitContainerMain As SplitContainer
Friend WithEvents MainUserControl As UserControl
Friend WithEvents Button2 As Button
Friend WithEvents Button1 As Button
End Class
And Here is some screen shots :
UC1UserControl displayed correctly
UC2UserControl displayed correctly
UC2UserControl after spliter moved
There is finally no code in UC1UserControl and UC2UserControl except an Label and and a different backcolor to identifiy the UC.
Thanks
After several hours of testing, logging ,etc...
I have found a solution to this.
I have added a line in the sub SetMinSize :
Private Sub SetMinSize()
Dim borderWidth = Me.Width - Me.ClientSize.Width
Me.MinimumSize = New Size(borderWidth + Me.SplitContainerMain.Panel1.Size.Width + Me.SplitContainerMain.SplitterWidth + Me.MainUserControl.MinimumSize.Width,
borderHeight + Me.MainUserControl.MinimumSize.Height)
Me.SplitContainerMain.Panel2.Size = Me.MainUserControl.Size
End Sub
And now it works. Apparently, when moving the splitter, the right panel of the SplitContainer (SplitContainerMain.Panel2) wasn't resized after the form resized.
The content of the codes given below;
3 panels and 2 Splitter are required. However, the 2nd splitter (Green) must be located between the gray and brown panel. But not in the right place. Are there any suggestions?
Thanks.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Show()
Dim tmpSplitter As Splitter
Dim tmpPanel As Panel
Dim MainPanel As Panel
' This is main panel
'
MainPanel = New Panel
With MainPanel
.Name = "MainPanel"
.Dock = DockStyle.Fill
.BackColor = Color.LightGray
.BorderStyle = BorderStyle.Fixed3D
.Visible = True
End With
Me.Controls.Add(MainPanel)
' 1: First Top Panel and Splitter
'
tmpPanel = New Panel
With tmpPanel
.Name = "Panel1"
.Dock = DockStyle.Top
.BackColor = Color.Red
.Visible = True
End With
tmpSplitter = New Splitter
With tmpSplitter
.Name = "Split1"
.Dock = DockStyle.Top
.BackColor = Color.Blue
.Cursor = Cursors.HSplit
End With
Me.Controls.Add(tmpSplitter)
Me.Controls.Add(tmpPanel)
' 2: Second Panel added to the left side of the main panel
'
MainPanel.Dock = DockStyle.Right
MainPanel.Size = New Size(MainPanel.Width * 0.5, MainPanel.Height)
Dim btn As New Button
btn.Size = New Size(10, 50)
btn.Location = New Point(MainPanel.Location.X - btn.Width, MainPanel.Location.Y)
Me.Controls.Add(btn)
tmpPanel = New Panel
With tmpPanel
.Size = New Size(10, MainPanel.Height)
.Location = New Point(MainPanel.Location.X - .Width - 5, MainPanel.Location.Y)
.Name = "Panel2"
.Dock = DockStyle.Fill
.BackColor = Color.Brown
End With
' THIS SPLITTER IS NOT IN THE RIGHT PLACE. Must be between brown and gray panel
'
tmpSplitter = New Splitter
With tmpSplitter
.Size = New Size(5, MainPanel.Height)
.Location = New Point(MainPanel.Location.X - .Width, MainPanel.Location.Y)
.Name = "Split2"
.Dock = DockStyle.Right
.BackColor = Color.Green
.Cursor = Cursors.VSplit
End With
Me.Controls.Add(tmpSplitter)
Me.Controls.Add(tmpPanel)
End Sub
End Class
a little more research and try to solve the solution
Me.Controls.SetChildIndex (tmpSplitter, 0)
is enough to write on the last line. Thank you for your contributions.
how to add a form in a panel inside tab page ?
i use this code to do it, but when i resize my main form, the form inside tab page doesn't auto resize.
Public Sub showForm(ByVal frm As MetroForm)
Dim a As New Panel
For i As Integer = 0 To tabPage.TabCount - 1
If frm.Text = tabPage.TabPages(i).Text Then
tabPage.SelectedIndex = i
Exit Sub
End If
Next
a = New Panel
tabPage.TabPages.Add("")
tabPage.TabPages(tabPage.TabPages.Count - 1).Controls.Add(a)
a.Dock = DockStyle.Fill
frm.TopLevel = False
frm.MinimizeBox = False
frm.MaximizeBox = False
frm.DisplayHeader = False
frm.AutoSize = False
frm.Dock = DockStyle.Fill
tabPage.TabPages(tabPage.TabPages.Count - 1).Text = frm.Text
a.Visible = True
a.Name = "pnl" & frm.Name
a.Controls.Add(frm)
frm.Dock = DockStyle.Fill
frm.Visible = True
frm.BringToFront()
AddHandler a.ControlRemoved, AddressOf Me.removePanel
tabPage.SelectedIndex = tabPage.TabPages.Count - 1
tabPage.TabPages(tabPage.TabPages.Count - 1).Name = frm.Text
End Sub
and to remove the tab page when form is closed :
Private Sub removePanel(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim a As Panel = DirectCast(sender, Panel)
For Each obj As TabPage In tabPage.TabPages
If obj.Name = sender.Parent.Name Then
obj.Controls(0).Dispose() 'remove form
tabPage.TabPages.Remove(obj) 'remove tab page
RemoveHandler a.ControlRemoved, AddressOf Me.removePanel
End If
Next
End Sub
here's the screenshot :
I have a dynamically created tabpage where I have placed dynamically created a button and label. I'm trying to figure out how to change the label.text with the button.click event. Everything works correctly until I add in the With/End With to change the label text in the button click subroutine. This is my first try at dynamically programming (hobby of mine, so trying to learn), but I do have a specific end goal for this application. Any thoughts on how to fix this problem?
Private Sub initialize_Button()
Dim button_Mybutton As New Button
With button_Mybutton
.Name = "button_My_Button"
.AutoSize = True
.Text = "Calculate"
.Visible = True
.Top = 200
.Left = 10
End With
AddHandler button_Mybutton.Click, AddressOf Me.button_Click
Me.Controls.Add(button_Mybutton)
End Sub
Protected Sub button_Click(ByVal sender As Object, ByVal e As EventArgs)
MsgBox("Button Clicked")
With label_Test
.text = "Test Confirmed"
End With
End Sub
Private Sub label_Test_Output()
Dim label_Test As New Label
With label_Test
.Name = "label_Test"
.Top = 200
.Left = 100
.AutoSize = True
.Text = "Label Test"
.Visible = True
End With
Me.Controls.Add(label_Test)
End Sub
Move the declaration of the controls outside the methods, to the class level. Then you can access them from anywhere in the class.
Private button_Mybutton As Button
Private label_Test As Label
Private Sub initialize_Button()
button_Mybutton = New Button()
With button_Mybutton
.Name = "button_My_Button"
.AutoSize = True
.Text = "Calculate"
.Visible = True
.Top = 200
.Left = 10
End With
AddHandler button_Mybutton.Click, AddressOf Me.button_Click
Me.Controls.Add(button_Mybutton)
End Sub
Protected Sub button_Click(ByVal sender As Object, ByVal e As EventArgs)
MsgBox("Button Clicked")
If label_Test IsNot Nothing Then
With label_Test
.text = "Test Confirmed"
End With
End If
End Sub
Private Sub label_Test_Output()
label_Test = New Label()
With label_Test
.Name = "label_Test"
.Top = 200
.Left = 100
.AutoSize = True
.Text = "Label Test"
.Visible = True
End With
Me.Controls.Add(label_Test)
End Sub
You should also check if the label is created when accessing it, since there is a possibility that you can click the button before calling label_Test_Output. Added null check to handler.
Hey all i have created dynamic buttons at runtime and i would like to disable them when a user clicks on a form button.
This is the code i have for that button:
Dim intXX As Integer = 0
Do Until intXX = intX
userAvatar(intXX).Enabled = False
intXX = intXX + 1
Loop
The buttonNames is an array of all populated button names created at runtime. However, trying the .enabled = false at the end of that does not work. What other ways are there to do that with buttons created at runtime?
How i create the buttons are like this:
private sub createButton()
Dim personAvatar As New PictureBox
With personAvatar
.AutoSize = False '> ^
If intX = 7 Then
thePrviousAvatarImg = 0
End If
If intX <= 6 Then
.Location = New System.Drawing.Point(10 + thePrviousAvatarImg, 10)
ElseIf intX >= 7 And intX <= 14 Then
.Location = New System.Drawing.Point(10 + thePrviousAvatarImg, 150)
Else
Exit Sub
End If
.Name = "cmd" & nameOfPerson
.Size = New System.Drawing.Size(100, 100)
.TabStop = False
.Text = ""
.BorderStyle = BorderStyle.FixedSingle
.BackgroundImageLayout = ImageLayout.Center
.BackColor = Color.LightGray
.BackgroundImage = Image.FromFile(theAvatarDir)
.Tag = nameOfPerson
.BringToFront()
End With
AddHandler personAvatar.Click, AddressOf personAvatar_Click
Me.Controls.Add(personAvatar)
userAvatar(intX) = personAvatar
intX = intX + 1
End With
End Sub
Thanks for your time and help!
David
You can't refer to button objects using a string representation of their names. Instead of using buttonNames (which I assume is an array of strings), use an array of buttons and add each button to that. Then loop through that array (as you've done here) setting enabled = false on each one.
So before you create each picture box, declare an array to store them:
Dim MyPictureBoxes() as PictureBox
Then as you create each one, add them to the array. When you're done creating them, you can disable them like this:
For Each MyPictureBox In MyPictureBoxes
Debug.Print(MyPictureBox.Name)
MyPictureBox.enabled = False
Next
I've created a form with two buttons, cmdGo and cmdDisable, to demonstrate this more completely:
Public Class Form1
Dim MyPictureBoxes(4) As PictureBox
Private Sub cmdGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdGo.Click
Dim personAvatar As New PictureBox
Dim intX As Integer = 0
While intX < 5
personAvatar = New PictureBox
With personAvatar
.AutoSize = False
.Left = intX * 100
.Top = 100
.Name = "cmd" & intX
.Size = New System.Drawing.Size(100, 100)
.TabStop = False
.Text = ""
.BorderStyle = BorderStyle.FixedSingle
.BackgroundImageLayout = ImageLayout.Center
.BackColor = Color.LightGray
.BringToFront()
End With
Me.Controls.Add(personAvatar)
MyPictureBoxes(intX) = personAvatar
intX = intX + 1
End While
End Sub
Private Sub cmdDisable_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdDisable.Click
For Each MyPictureBox In MyPictureBoxes
Debug.Print(MyPictureBox.Name)
MyPictureBox.Enabled = False
Next
End Sub
End Class
Notice how MyPictureBoxes is scoped for the whole form so it's accessible to both subs.