VB.Net: Using and addressing buttons in TableLayoutPanel - vb.net

Hi I have this TablelayoutPanel setup currently in my program to create a grid of buttons that will later correspond to a specific column and row:
'****INITIALISES TABLE LAYOUT INTO FORM******
Dim ColCount, RowCount As Integer
'Later change so that values are automatically calculated
ColCount = 5
RowCount = 5
'*********Copy and pasted from site as example, CHANGE LATER*******
Haztable = New TableLayoutPanel
Haztable.AutoScroll = True
Haztable.Dock = DockStyle.Fill
Haztable.ColumnCount = ColCount
Haztable.RowCount = RowCount
For rowNo As Integer = 0 To Haztable.RowCount - 1
For columnNo As Integer = 0 To Haztable.ColumnCount - 1
'Dim ctrl As Control = New Button
'ctrl.Text = String.Format("{0} {1},{2}", ctrl.GetType().Name, columnNo, rowNo)
'ctrl.Size = New Size(20, 20)
'Haztable.Controls.Add(ctrl, columnNo, rowNo)
Dim buttonname As String
buttonname = "B" & columnNo & rowNo
Dim button As Control = New Button
button.Size = New Size(70, 20)
button.Name = buttonname
button.Text = buttonname
Haztable.Controls.Add(button, columnNo, rowNo)
AddHandler button.Click, AddressOf buttonname_Click
Next
Next
Me.Controls.Add(Haztable)
Call buttonfind()
And this all works, creating a grid of buttons, much like the layout of an excel spreadsheet.
The buttons are named according to their XY position (e.g. the button in (1,1) would be called "B11") but the problem is I can't seem to work out how I can address these buttons i.e
*If B(X.Y) is clicked then save boolean value that button at X,Y is pressed.
It would be great to have one algorithm to scan and check if any buttons have been pressed instead of using "Select Case" for each button.
I would just create the buttons in the designer but for my full code i'm going to need 1000+ buttons and that seems an inefficient way to do so.

Your buttonname_Click should have a Sender object which is the Button that you Clicked just cast it to a Button and check the name then.
Private Sub buttonname_Click(sender As System.Object, e As System.EventArgs)
Dim btn As Button = CType(sender, Button)
Select Case btn.Name
Case "B11"
'Do something
Case "B12"
'Do Something esle
'...........
End Select
End Sub
Based on your last statement see if this works you may need to build an Array or a List if you need to reference the Text elsewhere in your Program
Private Sub buttonname_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim btn As Button = CType(sender, Button)
If btn.Text = "H" Then
btn.Text = "M"
ElseIf btn.Text = "M" Then
btn.Text = "L"
ElseIf btn.Text = "L" Then
btn.Text = ""
Else
btn.Text = "H"
End If
End Sub

You have add clicked event and handle each of them by using their row and column number. Make yourself a new button first so that you can access row and column numbers with spending no effort to parse column and row numbers from the controls name:
Public Class NewButton
Inherits Button
Public Row, Column, ClickCount as Integer
End Class
Now create and handle:
Public Class Form1
Sub addbuttons()
Dim newbut As New NewButton
newbut.Name = "B12"
newbut.Row = "1"
newbut.Column = "2"
'and other properties...
AddHandler newbut.Click, AddressOf clicked
Me.Controls.Add(newbut)
End Sub
Sub clicked(sender As System.Object, e As System.EventArgs)
Dim x As NewButton = DirectCast(sender, NewButton)
If x.Column = 2 And x.Row = 1 Then
x.ClickCount += 1
End If
End Sub
End Class

Related

How to enable DataGridView cell boarder highlighting on selection VB.Net

I have two DataGridViews on a single windows form, dgvIncome and dgvCashFlow. When I run the program (acting as a user) and select a cell in dgvIncome, it highlights that cell's border to indicate the cell is selected.
However, when I do the same thing with dgvCashFlow, there is no border and it appears as though nothing is selected (I have checked, the cell is being selected).
Is there any way that I can make this second DataGridViews behave the same as the first one?
This is the only code I have written that formats the second DataGridView. Most of it is just for adding items from a text file to a ComboBox Column
Public Sub FormatCFS(ByVal dgvTableToFormat As DataGridView)
Dim cbcCategory As DataGridViewComboBoxColumn = dgvTableToFormat.Columns(0)
Dim sreReader As StreamReader
Dim strFormatDirectory As String
strFormatDirectory = Directory.GetFiles("C:\Program Files\Finance Manager\Files\Format\" & Today.Year).OrderByDescending(Function(f) New FileInfo(f).LastWriteTime).First()
sreReader = File.OpenText(strFormatDirectory)
Dim bolType As Boolean = 0
For Each line As String In File.ReadLines(strFormatDirectory)
If line = "EXPENSES" Then bolType = 1
If line <> "INCOMES" And line <> "" And bolType = 0 Then
cbcCategory.Items.Add(line.Trim())
ElseIf line <> "EXPENSES" And line <> "INCOMES" And line <> "" Then
If Not line.Remove(8, line.Length - 8) = "Category" Then cbcCategory.Items.Add(line.Remove(0, 8).Trim())
End If
Next
sreReader.Close()
'Format Columns
For Each Column As DataGridViewColumn In dgvTableToFormat.Columns
Column.SortMode = DataGridViewColumnSortMode.NotSortable
Column.Width = 100
Next
dgvTableToFormat.Columns(0).Width = 135
dgvTableToFormat.Columns(1).ValueType = Type.GetType("System.Decimal")
End Sub
This is only partial code. What I did is create a DB and it has two tables IncomeTable and ExpenseTable
I created two DGV dgvIncome and dgvExpense
Both DGV are on the same form See Screen Shot
Here is the code I used to highlight he rows. Not sure that is what you wanted?
Private Sub dgvIncome_CellClick(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvIncome.CellClick
selRow = e.RowIndex
dgvIncome.Rows(selRow).DefaultCellStyle.BackColor = Color.Blue
'dgvIncome.DefaultCellStyle.BackColor = Color.LightPink
End Sub
Private Sub dgvExpense_CellClick(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvExpense.CellClick
selRow = e.RowIndex
dgvExpense.Rows(selRow).DefaultCellStyle.BackColor = Color.Red
'dgvIncome.DefaultCellStyle.BackColor = Color.LightPink
'Line above changes all the CELLS
End Sub
Screen Shot
Edit this will highlight only the cell selected
dgvExpense.RowsDefaultCellStyle.SelectionBackColor = Color.Blue

How to get sender column and row number?

I have a TableLayoutPanel(tlp_printing_content_layer2) with 1 column and 2 row, each cell also contain 1 button, How can i get the column and cell number when button clicked? Because i want to replace the button with another usercontrol
Private Sub btn_printer_Click(sender As Object, e As EventArgs) Handles btn_printer2.Click, btn_printer3.Click, btn_printer4.Click, btn_printer5.Click
Dim currButton As Button = sender
Dim prtp As New ctrl_PrinterPanel
currButton.Dispose()
tlp_printing_content_layer2.Controls.Add(prtp, sender.column, sender.row)
End Sub
sender.column and sender.row is not work... or is that other way to replace the button with other usercontrol?
You can iterate through the columns and rows until you find a Button matching the name of your clicked button:
Private Sub PrintButton_Click(sender As Object, e As EventArgs) Handles PrintButtonOne.Click, PrintButtonTwo.Click
'find which row was clicked
Dim rowPos As Integer = whichRow(sender, e)
'did we get a valid result?
If rowPos > -1 Then
'this is a dummy red control so that we can see it working
Dim myNewControl As Panel = New Panel With {.BackColor = Color.Red}
'remove the old
TableLayoutPanel1.Controls.Remove(DirectCast(sender, Button))
'add the new
TableLayoutPanel1.Controls.Add(myNewControl, 0, rowPos)
End If
End Sub
Private Function whichRow(sender As Object, e As EventArgs) As Integer
'cast the button that was clicked
Dim clickButton As Button = DirectCast(sender, Button)
'look through all the cols and rows
For colNum As Integer = 0 To TableLayoutPanel1.ColumnCount
For rowNum As Integer = 0 To TableLayoutPanel1.RowCount
'try cast the control we find at position colnum:rownum
Dim testcontrol As Button = TryCast(TableLayoutPanel1.GetControlFromPosition(colNum, rowNum), Button)
If Not testcontrol Is Nothing Then
'is this testcontrol the same as the click control?
If clickButton.Name = testcontrol.Name Then
Return rowNum
End If
End If
Next
Next
'not found or some other issue
Return -1
End Function

Creating multiple click events for dynamic buttons in vb.net

When creating a button I want to create a click event for each button. How do I create a click event for each button created dynamically? Here is my code. It works to create a single event based on the first button created.
Sub CreateDynamicButton()
Dim ButtonNumber As Integer = 1
Dim axisX As Integer = 53
Dim axisY As Integer = 13
' Create a Button object
Do Until ButtonNumber = 11
Dim dynamicButton As New Button
' Set Button properties
dynamicButton.Location = New Point(axisX, axisY)
dynamicButton.Height = 30
dynamicButton.Width = 200
' Set background and foreground
dynamicButton.BackColor = Color.Beige
dynamicButton.ForeColor = Color.Black
dynamicButton.Text = "I am Dynamic Button" & ButtonNumber
dynamicButton.Name = "DynamicButton" & ButtonNumber
dynamicButton.Font = New Font("Georgia", 10)
AddHandler dynamicButton.Click, AddressOf dynamicButton_Click
' Add Button to the Form. Placement of the Button
' will be based on the Location and Size of button
Controls.Add(dynamicButton)
axisY = axisY + 35
ButtonNumber = ButtonNumber + 1
Loop
'Add Exit Button
Dim dynamicButtonExit As New Button
' Set Button properties
dynamicButtonExit.Location = New Point(axisX, axisY)
dynamicButtonExit.Height = 30
dynamicButtonExit.Width = 200
' Set background and foreground
dynamicButtonExit.BackColor = Color.Beige
dynamicButtonExit.ForeColor = Color.Black
dynamicButtonExit.Text = "Exit"
dynamicButtonExit.Name = "Exit"
dynamicButtonExit.Font = New Font("Georgia", 10)
AddHandler dynamicButtonExit.Click, AddressOf dynamicButtonExit_Click
' Add Button to the Form. Placement of the Button
' will be based on the Location and Size of button
Controls.Add(dynamicButtonExit)
End Sub
You don't need to create multiple event to handle your dynamic buttons, dynamicButton_Click is enough to handle all click. Better give ID for each button and you only need to do is in this event, do code as below:
Dim btn As Button = DirectCast(sender, Button)
If btn.ID = "DynamicButton1" then
'Do logic here for button 1
End If
You just need to add a little logic to handle each button click in the one event handler. If you use as 'Select Case' Statement it keeps things tidy as well.
If you have a lot of code for each button's logic, it may be better to write separate subs for each button and call the appropriate sub using each 'Case' block like in the second case block
Private Sub DynamicButton_click(sender As Object, e As EventArgs)
Dim btn As Button = DirectCast(sender, Button)
Select Case btn.Name
Case "DynamicButton1"
MessageBox.Show("button1")
Case "DynamicButton2"
dynamicbutton2_Click(sender, e)
End Select
End Sub
Private Sub dynamicbutton2_Click(sender As Button, e As EventArgs)
MessageBox.Show("Button2")
'and lots of other code
End Sub

How to manage dynamically created controls in VB.NET?

I just understand how to make controls dynamically in VB.NET (I mean, only part of adding a new one)
But, unlike VB6, it seems hard to handle those dynamic things.
When I click the DONE button, I want to make an array filled with the text of textboxes.
At the same time, I want to make a Delete button that removes the button itself and the textbox in the same line.
Is there any simple method or an sample code for this?
Thank you!
Drop a TableLayoutPanel on your form, called pnlLayout, and also the Add button called btnAdd. Configure TableLayoutPanel to have two columns, adjust column width as needed.
Paste below code into your form:
Public Class Form1
Dim deleteButtons As List(Of Button)
Dim textBoxes As List(Of TextBox)
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
deleteButtons = New List(Of Button)
textBoxes = New List(Of TextBox)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim elementCount As Integer = deleteButtons.Count
Dim txt As New TextBox
txt.Width = 100
txt.Height = 20
textBoxes.Add(txt)
Dim btn As New Button
btn.Width = 100
btn.Height = 20
btn.Text = "Delete " & elementCount.ToString
AddHandler btn.Click, AddressOf btnDelete
deleteButtons.Add(btn)
pnlLayout.SetCellPosition(txt, New TableLayoutPanelCellPosition(0, elementCount))
pnlLayout.SetCellPosition(btn, New TableLayoutPanelCellPosition(1, elementCount))
pnlLayout.Controls.Add(btn)
pnlLayout.Controls.Add(txt)
End Sub
Private Sub btnDelete(sender As Object, e As EventArgs)
Dim senderButton As Button = DirectCast(sender, Button)
Dim txt As TextBox = textBoxes(deleteButtons.IndexOf(senderButton))
pnlLayout.Controls.Remove(senderButton)
pnlLayout.Controls.Remove(txt)
End Sub
End Class
By default, it will have no textboxes and no Delete buttons, you can add as many rows of "Textbox + Delete button" as you want. When you press Delete, the row will be removed (and everything shifted to accommodate the empty space).
For the textbox'ex part:
Dim strcol() As String = {TextBox2.Text, TextBox3.Text}
For Each strtxt In strcol
MessageBox.Show(strtxt)
Next
It really depends on your code, but, if you have their name use this to delete the buttons &/ textbox'es:
For i As Integer = Me.Controls.Count - 1 To 0 Step -1
If TypeOf Me.Controls(i) Is TextBox Then
If Me.Controls(i).Name = "TextBox2" Then
Me.Controls.RemoveAt(i)
End If
End If
If TypeOf Me.Controls(i) Is Button Then
If Me.Controls(i).Name = "Button3" Then
Me.Controls.RemoveAt(i)
End If
End If
Next
But it depends on your code...

Simple VB, handling many buttons

In my VB solution I have a lot of buttons arranged in a grid. When the program is loaded one of the buttons is randomly set to be the right one (You have to click that one to win). Can anybody point my in the right direction? Because there must be a better way than manually coding every single button, and creating an event handler for every single button.
You don't have to give me a working example, just an overall idea of how this is done.
Thanks.
If you want to arrange the buttons in a grid, either use the TableLayoutPanel or add the buttons directly to the form and calculate their positions. The TableLayoutPanel is useful if you want to arrange the buttons automatically when the form resizes, otherwise adding the buttons directly seems easier to me.
Add the buttons to an array defined at form level to make them easily accessible
Public Const NColumns As Integer = 5, NRows As Integer = 4
Private buttons As Button(,) = New Button(NColumns - 1, NRows - 1) {}
You can add the buttons easily in loops
For ix As Integer = 0 To NColumns - 1
For iy As Integer = 0 To NRows - 1
Dim btn = New Button()
btn.Text = String.Format("{0:d2}{1:d2}", ix, iy)
btn.Location = New Point(leftMargin + ix * xDistance,
topMargin + iy * yDistance)
btn.Size = New Size(buttonWidth, buttonHeight)
AddHandler btn.Click, Addressof Button_Clicked
buttons(ix, iy) = btn
Controls.Add(btn)
Next
Next
You can determine the winning button with a random generator. Define it as form member, not as local variable.
Private randomGenrator As System.Random = New System.Random()
Determine the coordinates
Dim xWins = randomGenrator.Next(NColumns) 'Returns a number between 0 and NColumns-1
Dim yWins = randomGenrator.Next(NRows)
The click handler looks like this
Private Sub Button Button_Clicked(sender As Object, e As EventArgs)
If sender = buttons(xWins, yWins) Then
'You win
Else
'You loose
End
End Sub
First, you said you want a grid of buttons, so you have to have a FlowLayoutPanel control in your form in order to let the buttons you want to add, to be arranged automatically.
Second, you have to make use of a for loop, r any kind of look, in order to add the buttons to be added to previously added 'FlowLayoutPanel'.
class Answers
Dim strAnswerText as string
Dim AnswerFlag as Boolean
End Class
Sub LoadForm(byval a_Answers as Answer())
Dim i as Integer = 0
Dim b as Button
For(i=0;i<NUM_OF_BUTTONS;i++)
b = New Button()
b.Text = "Choice -" & i & "- " & a_Answers(i).strAnswerText
b.Tag = a_Answers(i).AnswerFlag
'Supposing that the FlowLayoutPanel control name is fl
AddHandler b.Click, Addressof Clicked
fl.controls.Add(b)
End For
End Sub
Sub Button Clicked(sender as object, e as EventArgs)
if sender.Tag = True
'True answer
else
'Wrong answer
end if
End Sub