I have a panel with 50 button and 1 label in my form
Private Sub flp_table_paint(sender As Object, e As PaintEventArgs) Handles flp_table.Paint
Dim i As Integer
For i = 1 To 50
Dim btn_tableNo As New Button
btn_tableNo.Width = 40
btn_tableNo.Height = 40
btn_tableNo.Text = i
AddHandler btn_tableNo.Click, AddressOf TableButtonClicked
Dim timer As New Timer
timer.Tag = i
Me.flp_table.Controls.Add(btn_tableNo)
Next
End Sub
What I try to do is, for every single button that i clicked they will start their own timer and show on the label.
Example:
11:00:00PM - Clicked on Button1 , lb_timer will show 1,2,3,4...
11:00:30PM - Clicked on Button2 , lb_timer will show 1,2,3,4...
11:00:45PM - Clicked on Button1 again, lb_timer will show 45,46,47,48...
11:00:50PM - Clicked on Button2 again, lb_timer will show 20,21,22,23...
Here is what i try so far, but fail...
Private Sub TableButtonClicked(ByVal sender As Object, ByVal e As EventArgs)
Dim currButton As Button = sender
selectedTable = currButton
For Each timer As Timer In Me.Controls
If timer.Tag = selectedTable.Text Then
timer.Start()
lb_timer.Text = timer.ToString
End If
Next
End Sub
I have no idea how to make it work, please help me...
Here asynchronous approach without Timer and one eventhandler for all buttons
' In constructor
AddHandler button1.Click, AddressOf Button_Click
AddHandler button2.Click, AddressOf Button_Click
AddHandler button3.Click, AddressOf Button_Click
' ... rest of buttons
' variable will keep name of the button which number is showing
Private _selectedButtonName As String
Private Async Sub Button_Click(sender As object, e As EventArgs)
Dim button As Button = DirectCast(sender, Button)
_selectedButtonName = button.Name
Dim isRunning As Boolean = (button.Tag IsNot Nothing)
If isRunning = True Then return
await StartCounterAsync(button)
End Sub
Private Async Function StartCounterAsync(Button button) As Task
button.Tag = new object()
Dim number As Integer = 0
While True
await Task.Delay(1000)
number += 1
If _selectedButtonName.Equals(button.Name)
lb_timer.Text = $"{button.Name}: {number}"
End If
End While
End Function
You can add CancellationToken in case you want reset counters.
Sadly the timer doesn't show elapsed time. An easier control to use for your purpose would be the StopWatch control. Its quite similar and will show a running time.
Dim StopWatchTest As New Stopwatch
StopWatchTest.Start()
Dim EllapsedTime As String = StopWatchTest.ElapsedMilliseconds / 1000
However since you want to continually update the label with the ellapsed time, you would need a timer to update the label at every tick.
Dim UpdateLabelTimer As New Timer()
UpdateLabelTimer.Interval = 1000 'How often to update your label (in milliseconds)
AddHandler UpdateLabelTimer.Tick, AddressOf Tick
UpdateLabelTimer.Start()
----------
Private Sub Tick()
lblLabel.text = StopWatchTest.ElapsedMilliseconds
End Sub
Related
I need to add some controls to a Visual Basic 2017 form programmatically. One of the controls is a textbox that needs a changetext event handler. Below is some code that accomplishes that task.
HOWEVER, the changetext event handler seems to fire right away, before the form even loads... before the textbox itself even loads! A "click" handler works fine, as expected. But changetext? Nope.
I've thrown together a simplified version to demonstrate. The line with the "DIES RIGHT HERE" comment causes the problem (not the comment, but the code to the left of it).
A textbox that is added at design time will work fine, not cause this problem, but that isn't an option.
What's causing this the changetext handler to be run early? How do I work around this?
Public Class Form1
Dim txtTest As TextBox
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim pntTextBox As Point
pntTextBox.X = 100
pntTextBox.Y = 100
txtTest = New TextBox
With txtTest
.Location = pntTextBox
.Width = 100
AddHandler txtTest.TextChanged, AddressOf txtTest_TextChanged
End With
Me.Controls.Add(txtTest)
End Sub
Private Sub txtTest_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyClass.TextChanged
Dim strTest As String
strTest = Str(txtTest.Width) ' ****** DIES RIGHT HERE
MsgBox(strTest)
End Sub
End Class
Made a few changes. Works.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For x As Integer = 1 To 2 'create multiple TB's
Dim pntTextBox As Point
pntTextBox.X = 100 * x
pntTextBox.Y = 100
Dim txtTest As TextBox = New TextBox
With txtTest
txtTest.Name = "tb_" & x.ToString
AddHandler txtTest.TextChanged, AddressOf txtTest_TextChanged
.Location = pntTextBox
.Width = 100
End With
Me.Controls.Add(txtTest)
Next
End Sub
Private Sub txtTest_TextChanged(ByVal sender As Object,
ByVal e As System.EventArgs) 'no handler at design time
Dim tb As TextBox = DirectCast(sender, TextBox)
Dim strTest As String
strTest = tb.TextLength.ToString
Debug.WriteLine("{0} {1}", tb.Name, strTest) 'put breakpoint here
End Sub
End Class
I created multiple button dynamically inside a panel based on multiple click on add button. Each button deletes When I click on it.
I want each button to delete when I single click on it, and say hello when I double click. Thank you.
I have tried using this code to delete which works fine, but I cannot figure how to assign seperate code to display hello when I double click or right click on it without affecting delete aspect of it.
Private Sub btnDynamic_Click(ByVal sender As Object, ByVal e As EventArgs)
'Reference the Button which was clicked.
Dim button As Button = CType(sender, Button)
'Determine the Index of the Button.
Dim index As Integer = Integer.Parse(button.Name.Split("_")(1))
'Find the TextBox using Index and remove it.
FlowLayoutPanel1.Controls.Remove(FlowLayoutPanel1.Controls.Find(("btnDynamic_" & index), True)(0))
'Remove the Button.
FlowLayoutPanel1.Controls.Remove(button)
'Rearranging the Location controls.
For Each btn As Button In FlowLayoutPanel1.Controls.OfType(Of Button)()
Dim controlIndex As Integer = Integer.Parse(btn.Name.Split("_")(1))
If (controlIndex > index) Then
Dim btn1 As Button = CType(FlowLayoutPanel1.Controls.Find(("btnDynamic_" & controlIndex), True)(0), Button)
btn1.Top = (btn.Top - 25)
'txt.Top = (txt.Top - 25)
End If
Next
End Sub
Here is the create button code:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
If TextBox1.Text = "" Then
Exit Sub
End If
Dim count As Integer = Form2.FlowLayoutPanel2.Controls.OfType(Of Button).ToList.Count
Dim button As Button = New Button
button.Size = New System.Drawing.Size(28, 21)
button.Name = "btnDynamic_" & (count + 1)
button.Text = TextBox1.Text
AddHandler button.Click, AddressOf Me.button_click
Form2.FlowLayoutPanel2.Controls.Add(button)
End Sub
You have to enable DoubleClick option first.
You do so with:
Public Class DoubleClickButton
Inherits Button
Public Sub New()
SetStyle(ControlStyles.StandardClick Or ControlStyles.StandardDoubleClick, True)
End Sub
End Class
Then create a "DoubleClick" and "SingleClick" methods and assign them to (new custom) buttons when you are creating them.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
For x = 0 To 2
Dim ButtonX As New DoubleClickButton
ButtonX.Text = x
AddHandler ButtonX.MouseClick, AddressOf SingleClickE
AddHandler ButtonX.MouseDoubleClick, AddressOf DoubleClickE
FlowLayoutPanel1.Controls.Add(ButtonX)
Next
End Sub
Private Sub SingleClickE(sender As Object, e As MouseEventArgs)
Debug.Print("Hello!")
End Sub
Private Sub DoubleClickE(sender As Object, e As MouseEventArgs)
FlowLayoutPanel1.Controls.Remove(sender)
End Sub
Thank you all for attempting to answer my question. I have been able to figure it out. I intend firing diffrent events with dynamically created buttons using single click, double click or right click. I ended up using single and right click command. Though would have prefered double click, but it is ok. Below is the code.
'Create buttons
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 1 To 5
Dim button As New Button
button.Text = i
AddHandler button.Click, AddressOf SingleClickE
AddHandler button.MouseDown, AddressOf RightClickE
FlowLayoutPanel1.Controls.Add(button)
Next
End Sub
'Fire it up with single click
Private Sub SingleClickE(sender As Object, e As MouseEventArgs)
Dim button As Button = CType(sender, Button)
MsgBox("Hello World")
End Sub
'Fire it up with Right Click
Private Sub RightClickE(sender As Object, e As MouseEventArgs)
Dim button As Button = CType(sender, Button)
If e.Button = MouseButtons.Right Then
FlowLayoutPanel1.Controls.Remove(button)
End If
End Sub
I have a very strange Problem with dynamic created Buttons in VB.NET:
The Click Event is not fired when creating them in a Loop. Here is my code:
Panel1.Controls.Clear()
For i As Integer = 0 To 100 Step 1
Dim b15 As new Button
b15.Text = "Test3"
b15.id = "a" & i
AddHandler b15.Click, AddressOf updateFunc
Panel1.Controls.Add(b15)
Next
This one doesn't work (only the PageLoad is fired, not the Click Event), but when i type
Dim b14 As New Button
b14.Text = "Test"
b14.id = "asdf"
AddHandler b14.Click, AddressOf updateFunc
Panel1.Controls.Add(b14)
it works fine and the Event is fired.
The Header of the Function updateFunc is the following:
Protected Sub updateFunc(ByVal sender As Object, ByVal e As System.EventArgs)
Any ideas why it doesn't work with the Loop?
Thanks for answers!
Do you include IsPostBack checking? I assume you did. Try create the control outside.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
'Do Something
Else
'Do Something else
End If
Panel1.Controls.Clear()
For i As Integer = 0 To 10 Step 1
Dim b15 As New Button
b15.Text = "Test3"
b15.ID = "a" & i
AddHandler b15.Click, AddressOf updateFunc
Panel1.Controls.Add(b15)
Next
End Sub
flpnlContent.Controls.Clear()
For i As Integer = 0 To 10
Dim b15 As New Button
b15.Text = "a" & i
b15.Name = "a" & i
AddHandler b15.Click, AddressOf btn_Click
flpnlContent.Controls.Add(b15)
Next
use this it will work
I dynamically created 5 Picture Box and added Events MouseEnter and MouseLeave, the problem is that when I hover the cursor on one of the picture box, the other will also trigger the event
Private Sub Form_TEST_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim ImgSelect As PictureBox
Dim x As Integer = 1
While Not x = 5
ImgSelect = New PictureBox
ImgSelect.Name = "image0" & x.ToString
ImgSelect.BackColor = Color.Black
ImgSelect.Size = New Size(203, 312)
ImgSelect.BorderStyle = BorderStyle.FixedSingle
ImgSelect.Visible = True
ImgSelect.BringToFront()
ImgSelect.SizeMode = PictureBoxSizeMode.StretchImage
FlowLayoutPanel1.Controls.Add(ImgSelect)
x += 1
AddHandler ImgSelect.MouseEnter, AddressOf ImgSelect_MouseEnter
AddHandler ImgSelect.MouseLeave, AddressOf ImgSelect_MouseLeave
End While
End Sub
In the mouse enter event handler, you can get UI control that trigger the event from sender parameter :
Private Sub ImgSelect_MouseLeave(sender As Object, e As System.EventArgs)
Dim CurrentImage As PictureBox = DirectCast(sender, PictureBox)
......
End Sub
Solution:
you have create one event for the all control add in flow layout panel
this statement bound event on imgselecet and you have one control img select tha's why fir event on all picture box...
AddHandler ImgSelect.MouseEnter, AddressOf ImgSelect_MouseEnter
AddHandler ImgSelect.MouseLeave, AddressOf ImgSelect_MouseLeave
OR WRITE THIS STATEMENT IN GLOBAL LEVEL AND REMOVE HANDLER
Dim WithEvents ImgSelect As New PictureBox
I have to create multiple timer "n" times with handler.
Which will be stored for a row in my DataGrid.
For each row there will be a timer that works seperately.
What I thought of looks like:
Private Sub CreateTimer()
Dim tmr As New Timer
tmr.Interval = 1000 '1 Second
tmr.Enabled = True
AddHandler tmr.Tick, AddressOf GlobalTimerTick
End Sub
'A timer tick handler that would work for each timer I add with the sub above
'All timers I created should work seperately
Private Sub GlobalTimerTick(TheTimer as Timer, ByVal sender As Object, ByVal e As EventArgs)
mynumber = mynumber + 1
With DataGridView1
.Rows(n).Cells(4).Value = mynumber " saniye"
End With
End Sub
So how can I achieve this?
I believe Tag property of Timer would work beautifully in your case. I don't have my IDE currently, but the following snippet should give you the idea.
Private Sub CreateTimer()
Dim tmr As New Timer
tmr.Interval = 1000 '1 Second
tmr.Enabled = True
tmr.Tag = ROW_INDEX
AddHandler tmr.Tick, AddressOf GlobalTimerTick
End Sub
'A timer tick handler that would work for each timer I add with the sub above
'All timers I created should work seperately
Private Sub GlobalTimerTick(ByVal sender As Object, ByVal e As EventArgs)
mynumber = sender.Tag
With DataGridView1
.Rows(n).Cells(4).Value = mynumber " saniye"
End With
End Sub