Loop that creates labels that can open a new form - vb.net

hey everyone can someone help me with some codes in vb.net
i created a loop that can generate labels with my OleDbDataReader
now i was wondering if i can make those labels open new form
and can i use the data in this label in my new form like the label text created !
here is my code :
Dim cnn As New OleDbCommand(query, con)
Dim cmd As New OleDbDataAdapter(cnn)
Dim dt As New DataTable()
cmd.Fill(dt)
Dim reader As OleDbDataReader
reader = cnn.ExecuteReader()
Dim number As Integer = 0
Dim location As Integer = 0
While reader.Read()
Dim sensibleFont As New Font("Segoe UI", 15)
Dim lb As New Label()
lb.Name = "labb" + number.ToString
lb.Size = New System.Drawing.Size(350, 40)
lb.Location = New System.Drawing.Point(50, 15 + location)
lb.Text = dt.Rows(number)(0).ToString()
lb.ForeColor = Color.Black
lb.Font = sensibleFont
GroupBox1.Controls.Add(lb)
Dim lb2 As New Label()
lb2.Name = "labs" + number.ToString
lb2.Size = New System.Drawing.Size(280, 40)
lb2.Location = New System.Drawing.Point(10, 5 + location)
lb2.Text = dt.Rows(number)(2).ToString()
lb2.ForeColor = Color.Black
lb2.Font = sensibleFont
GroupBox2.Controls.Add(lb2)
location += 40
number += 1
End While
con.Close()

Create a sub that does what you want.
Private Sub OpenForm()
Dim myForm As New MyForm()
myForm.Show()
End Sub
During label creation, add a click event that uses this sub as it's handler
AddHandler lb.Click, AddressOf OpenForm

As shown in the answer by A Friend, you can add a handler to a label's click event. Extending that to use the correct signature for the handler, you can get the object which raised the event and so use its properties, such as the .Text property:
Sub Label_Click(sender As Object, e As EventArgs)
Dim lbl = DirectCast(sender, Label)
Dim frm2 = New OtherForm(lbl.Text)
frm2.Show()
End Sub
To go with it, you will need a constructor (the Sub New) in the other form (which I named "OtherForm") like this:
Public Class OtherForm
Sub New()
InitializeComponent()
End Sub
Sub New(info As String)
InitializeComponent()
Label1.Text = info
End Sub
End Class
Where Label1 is just a label I put on OtherForm for testing purposes.
You might find the .Tag property of a control better for passing data as it can be any Object, e.g. an instance of a class.
I notice that you are reading the database twice: once to fill the datatable and then again as a count of the rows in the datatable, which is a bit wasteful. Also, you should dispose of a font when you have finished with it: the Using construct will take care of that for you, similarly for a connection to a database. Like this:
Sub PopulateGroupBox()
Dim connStr = "CONNECTION STRING HERE"
Dim query = "SQL QUERY HERE"
Dim dt As New DataTable()
Using con As New OleDbConnection(connStr)
Dim cnn As New OleDbCommand(query, con)
Dim cmd As New OleDbDataAdapter(cnn)
cmd.Fill(dt)
End Using
Dim location As Integer = 0
Using sensibleFont As New Font("Segoe UI", 15)
For i = 0 To dt.Rows.Count - 1
Dim lb1 As New Label()
lb1.Name = "labb" & i.ToString()
lb1.Size = New System.Drawing.Size(350, 40)
lb1.Location = New System.Drawing.Point(50, 15 + location)
lb1.Text = dt.Rows(i)(0).ToString()
lb1.ForeColor = Color.Black
lb1.Font = sensibleFont
AddHandler lb1.Click, AddressOf Label_Click
GroupBox1.Controls.Add(lb1)
Dim lb2 As New Label()
lb2.Name = "labs" & i.ToString()
lb2.Size = New System.Drawing.Size(280, 40)
lb2.Location = New System.Drawing.Point(10, 5 + location)
lb2.Text = dt.Rows(i)(2).ToString()
lb2.ForeColor = Color.Black
lb2.Font = sensibleFont
AddHandler lb2.Click, AddressOf Label_Click
GroupBox2.Controls.Add(lb2)
location += 40
Next
End Using
End Sub

Related

How can I write a loop to replace this if statement for different buttons

I have an Access datatable named A. It has 90 rows and each row has 2 columns as follows:
I have a vb form that has 90 green buttons and code:
Private Sub _1st_Floor_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim myConnection As New OleDbConnection(myConnString)
Dim myCommand As New OleDbCommand("SELECT ID FROM A WHERE Busy=True", myConnection)
myConnection.Open()
Dim reader As OleDbDataReader
Dim dt As New DataTable
dt.Load(myCommand.ExecuteReader)
If dt.Rows(0).Item(0).ToString = 1 Then
Button1.BackColor = Color.Red
Button1.FlatAppearance.BorderColor = Color.Red
End If
If dt.Rows(1).Item(0).ToString = 2 Then
Button2.BackColor = Color.Red
Button2.FlatAppearance.BorderColor = Color.Red
End If
End Sub
This works fine, but I don't want to repeat the same If block over and over again for 90 buttons. How can I write a loop with just one set of code for all 90 buttons?
Loop through your records and find the corresponding buttons:
For Each row As DataRow In dt.Rows
Dim buttonName as String = "button" & row(0).ToString()
Dim cntrls() As Control = Me.Controls.Find(buttonName, True)
If cntrls IsNot Nothing Then
Dim btn As Button = TryCast(cntrls(0), Button)
If btn IsNot Nothing Then
btn.BackColor = Color.Red
btn.FlatAppearance.BorderColor = Color.Red
End If
End If
Next
This is dependent on the buttons' naming scheme being consistent.
Using your own "words" :) maybe not the most efficient way but I just wanted to write this by reusing your code as much as possible...
Private Sub _1st_Floor_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim myConnection As New OleDbConnection(myConnString)
Dim myCommand As New OleDbCommand("SELECT ID FROM A WHERE Busy=True", myConnection)
myConnection.Open()
Dim reader As OleDbDataReader
Dim dt As New DataTable
dt.Load(myCommand.ExecuteReader)
For index As Integer = 1 To 90
If dt.Rows(index - 1).Item(0).ToString = index.ToString Then
Dim button As Button = CType(Me.Controls("Button" + index.ToString), Button)
button.BackColor = Color.Red
button.FlatAppearance.BorderColor = Color.Red
End If
Next
End Sub
I used this post to get controls by name String

Adding dynamic Button and changing its Property text. VB.NET

I have this problem by changing the text of added dynamically button.
I want to change the button text from "Select" to "Update".
this is my code.
dim oButton as button
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dr As SqlDataReader
Dim cn As SqlConnection = New SqlConnection("Data Source=server;Initial Catalog=testDB;Integrated Security=True;MultipleActiveResultSets=true;")
cmd.Connection = cn
cmd.CommandType = CommandType.StoredProcedure
cmd.CommandText = "votecand"
Dim stream As New MemoryStream()
cn.Open()
dr = cmd.ExecuteReader
If dr.HasRows = True Then
while dr.read
oButton = New Button
oButton.Enabled = True
oButton.Font = New Font("Tahoma", 11, FontStyle.Regular)
oButton.Location = New Point(ButtonNumber * 30, ButtonNumber * 30)
oButton.Name = "MyButton" & ButtonNumber.ToString
oButton.Size = New Size(134, 34)
oButton.BackColor = Color.MediumSeaGreen
oButton.FlatStyle = FlatStyle.Flat
oButton.ForeColor = Color.White
oButton.Text = "Select"
oButton.Visible = True
oButton.Dock = DockStyle.Bottom
oButton.Tag = ButtonNumber
AddHandler oButton.Click, AddressOf onButtonClick
Me.Controls.Add(oButton)
End while
End if
End sub
this code is MyFunc Function
Private Sub MyFunc(ByVal ButtonNumber As Integer)
Dim cn As SqlConnection = New SqlConnection("Data Source=server;Initial Catalog=testDB;Integrated Security=True;MultipleActiveResultSets=true;")
Dim command As New SqlCommand
command = New SqlCommand("select first_name,middle_name,last_name,position,gender,course,year_level,aff,student_id from tbl_cand where id=#id", cn)
command.Parameters.AddWithValue("#id", SqlDbType.VarChar).Value = ButtonNumber.ToString
Dim dt As New DataTable()
Dim adapater As New SqlDataAdapter(command)
adapater.Fill(dt)
Dim fname As String = dt.Rows(0).ItemArray(0).ToString
Dim mname As String = dt.Rows(0).ItemArray(1).ToString
Dim lname As String = dt.Rows(0).ItemArray(2).ToString
Dim gender As String = dt.Rows(0).ItemArray(3).ToString
Dim course As String = dt.Rows(0).ItemArray(4).ToString
Dim year As String = dt.Rows(0).ItemArray(5).ToString
Dim aff As String = dt.Rows(0).ItemArray(6).ToString
Dim studid As String = dt.Rows(0).ItemArray(7).ToString
lblfname.Text = fname
lblmname.Text = mname
lbllname.Text = lname
lblgender.Text = gender
lblyear.Text = year
lblmajor.Text = course
lblaff.Text = aff
connect()
sql = "INSERT INTO tbl_castvote(can_id,fname,img,student_id)"
sql = sql + "VALUES(#canid,#fname,#pos,#img,#voterid,#stdid)"
cmd = New SqlCommand(sql, con)
With cmd
.Parameters.AddWithValue("canid", studid)
.Parameters.AddWithValue("fname", fname)
Dim ms As New MemoryStream()
pb.Image.Save(ms, pb.Image.RawFormat)
Dim data As Byte() = ms.GetBuffer()
Dim p As New SqlParameter("#img", SqlDbType.VarBinary)
p.Value = data
.Parameters.Add(p)
.Parameters.AddWithValue("stdid", studentid.Text)
End With
If MsgBox("You have selected" & " '" & fname & " " & mname & " " & lname & "' " & "as" & " '" & pos & "' ", vbOKCancel + vbInformation, "Voting System") = vbOK Then
cmd.ExecuteNonQuery()
oButton.Text = "Update" --> this line is my problem. Can't change the oButton.text "Select" to "Update"
End If
End Sub
and this is my button click handler
Private Sub onButtonClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim ButtonNumber As Integer
If CType(sender, Button).Tag IsNot Nothing Then
If Integer.TryParse(CType(sender, Button).Tag.ToString, ButtonNumber) Then
MyFunc(ButtonNumber)
End If
End If
End Sub
pls help me. thank you
A couple of issues. You need to increment your ButtonNumber value inside your loop:
while dr.read
ButtonNumber += 1
oButton = New Button
oButton.Name = "MyButton" & ButtonNumber.ToString
Then in your function, you have to find your button to update it:
cmd.ExecuteNonQuery()
Dim btn As Button = Me.Controls.OfType(Of Button).
Where(Function(x) x.Name = "myButton" & btnNumber.ToString).
FirstOrDefault()
If btn IsNot Nothing Then
btn.Text = "Update"
End If
Change your function parameter to be unique:
Private Sub MyFunc(btnNumber As Integer)
You are using one reference for multiple buttons. You have two options from the above code.
1. Save your added button references in a list
Private Buttons As List(of Button)
Before you start your loop
Buttons = New List(of Button)
in your loop
Dim oButton = New Button
ButtonNumber = Buttons.Count '<-- use the collection count as the number
...blah blah blah...
Buttons.Add(oButton)
Then in myFunc simply use
Buttons(ButtonNumber).Text = "whatever"
2. If this is the only place you reference it, pass the sender along instead.
Private Sub MyFunc(Byref Pressed_Button as Button, ByVal ButtonNumber As Integer)
...blah blah blah...
Pressed_Button.Text = "whatever"
End Sub
Private Sub onButtonClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim PressedButton as Button = CType(sender, Button)
Dim ButtonNumber As Integer
If PressedButton.Tag IsNot Nothing Then
If Integer.TryParse(PressedButton.Tag.ToString, ButtonNumber) Then
MyFunc(PressedButton, ButtonNumber)
End If
End If
End Sub
There are also ways to search for the control by name, but keeping your own index is more efficient.

Update a chart automatically with a timer

So, I am developing an application and I got stuck probably on a basic thing that I can't solve. I have a chart which is connected to a database and it will be running a query. I was able to do it, but the issue there I am facing is that it won't update unless I close and open the application.
I will show you the code that I am using and then explain it:
Public Sub UpdateChart()
Try
SQLCon = New SqlConnection
SQLCon.ConnectionString = "......................"
Timer1.Interval = 3000
Timer1.Start()
Dim sqlStatis As String = "SELECT Top 5 Filename, Filesize FROM infofile"
Dim da As New SqlDataAdapter(sqlStatis, SQLCon)
Dim ds As New DataSet()
da.Fill(ds, "infofile")
Chart1.DataSource = ds.Tables("infofile")
Catch ex As Exception
MessageBox.Show(ex.ToString())
Finally
SQLCon.Dispose()
End Try
End Sub
Public Sub BuildChart()
Dim Chart1 = New Chart()
Dim ChartArea1 As ChartArea = New ChartArea()
Dim Legend1 As Legend = New Legend()
Dim Series1 As Series = New Series()
Me.Controls.Add(Chart1)
ChartArea1.Name = "ChartArea1"
Chart1.ChartAreas.Add(ChartArea1)
Legend1.Name = "Legend1"
Chart1.Legends.Add(Legend1)
Chart1.Location = New System.Drawing.Point(12, 12)
Chart1.Name = "Chart1"
Series1.ChartArea = "ChartArea1"
Series1.Legend = "Legend1"
Series1.Name = "Tamanho do ficheiro"
Chart1.Series.Add(Series1)
Chart1.Size = New System.Drawing.Size(600, 300)
Chart1.TabIndex = 0
Chart1.Text = "Chart1"
Chart1.Series("Tamanho do ficheiro").XValueMember = "Filename"
Chart1.Series("Tamanho do ficheiro").YValueMembers = "Filesize"
End Sub
This method will be called on the form and the data will be shown as I want. As you can see on the method I have a Timer and it will update the chart every 3 seconds or 3000 milliseconds.
Inside of the Timer I have this:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
UpdateChart()
End Sub
And inside of the form I have this:
Public Sub Gráfico_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BuildChart()
UpdateChart()
End Sub
It doesn't gives me any error but it doesn't update even if I create a button called "Update Chart" and put the method already created inside of the button.
So do you have any ideia I could I solve my problem?
I would move
Timer1.Interval = 3000
Timer1.Start()
to the end of the Form Load
and Dim Chart1 as a form level variable and new it up in the Load as well

How to update a Chart

I've just finished developing a piece of code where I am able to create a Chart and query from my database. Here I insert values from the database and it will show to the user.
I will post here the code that I've done to create a chart:
Public Sub BuildChart()
Try
SQLCon = New SqlConnection
SQLCon.ConnectionString = "........."
Dim sqlStatis As String = "SELECT Top 5 Filename, Filesize FROM infofile"
Dim Chart1 As New Chart()
Dim da As New SqlDataAdapter(sqlStatis, SQLCon)
Dim ds As New DataSet()
da.Fill(ds, "infofile")
Dim ChartArea1 As ChartArea = New ChartArea()
Dim Legend1 As Legend = New Legend()
Dim Series1 As Series = New Series()
Me.Controls.Add(Chart1)
ChartArea1.Name = "ChartArea1"
Chart1.ChartAreas.Add(ChartArea1)
Legend1.Name = "Legend1"
Chart1.Legends.Add(Legend1)
Chart1.Location = New System.Drawing.Point(12, 12)
Chart1.Name = "Chart1"
Series1.ChartArea = "ChartArea1"
Series1.Legend = "Legend1"
Series1.Name = "Tamanho do ficheiro"
Chart1.Series.Add(Series1)
Chart1.Size = New System.Drawing.Size(600, 300)
Chart1.TabIndex = 0
Chart1.Text = "Chart1"
Chart1.Series("Tamanho do ficheiro").XValueMember = "Filename"
Chart1.Series("Tamanho do ficheiro").YValueMembers = "Filesize"
Chart1.DataSource = ds.Tables("infofile")
Catch ex As Exception
MessageBox.Show(ex.ToString())
Finally
SQLCon.Dispose()
End Try
End Sub
As you can see I've created a method which will be called in the form and the info will be shown there. Outside of everything I declared a variable Dim Chart1 As New Chart(). Now I want to create a method which allows me with a timer to update automatically the chart. So I should create another method called UpdateChart where I could insert there this:
Timer1.Interval = 3000
Timer1.Start()
But now I have no idea what should I use to update it every 3 secs or 3000 milliseconds.
On Load you want to call the BuildChart method and start the timer:
Private Sub frmTest_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
BuildChart()
With Timer1
.Enabled = True
.Interval = 3000
.Start()
End With
End Sub
For BuildChart you only need to create the chart itself and not bind the data.
Public Sub BuildChart()
Try
Dim Chart1 As New Chart()
Dim ChartArea1 As ChartArea = New ChartArea()
Dim Legend1 As Legend = New Legend()
Dim Series1 As Series = New Series()
Me.Controls.Add(Chart1)
ChartArea1.Name = "ChartArea1"
Chart1.ChartAreas.Add(ChartArea1)
Legend1.Name = "Legend1"
Chart1.Legends.Add(Legend1)
Chart1.Location = New System.Drawing.Point(12, 12)
Chart1.Name = "Chart1"
Series1.ChartArea = "ChartArea1"
Series1.Legend = "Legend1"
Series1.Name = "Tamanho do ficheiro"
Chart1.Series.Add(Series1)
Chart1.Size = New System.Drawing.Size(600, 300)
Chart1.TabIndex = 0
Chart1.Text = "Chart1"
Chart1.Series("Tamanho do ficheiro").XValueMember = "Filename"
Chart1.Series("Tamanho do ficheiro").YValueMembers = "Filesize"
Catch ex As Exception
MessageBox.Show(ex.ToString())
Finally
SQLCon.Dispose()
End Try
End Sub
We then want UpdateChart to be called from the Timer.Tick event.
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
UpdateChart()
End Sub
Private Sub UpdateChart()
Chart1.Series(0).Points.Clear()
Chart1.DataSource = ""
SQLCon = New SqlConnection
SQLCon.ConnectionString = "............."
Dim sqlStatis As String = "SELECT Top 5 Filename, Filesize FROM infofile"
Dim da As New SqlDataAdapter(sqlStatis, SQLCon)
Dim ds As New DataSet()
da.Fill(ds, "infofile")
Chart1.DataSource = ds.Tables("infofile")
End Sub
Be aware though that this will create a lot of hits to your database.

Datagridview strange display error on init

upon initialization of my UI i get the following very strange behavior regarding to the drawing of the datagridview:
Basically, expect the first row header and the column headers (which i did not include in the pic) it looks like the DGV prints what is on the Screen "behind" his application.
What the hell is this and does anyone know a way to fix it?
Code of Container:
Public Class DGVControl
Dim dt As DataTable
Public Sub init()
dt = New DataTable
Dim arr(ldfAttributes.Count - 1) As String
Dim cms As New ContextMenuStrip
Dim i As Integer = 0
For Each att As String In Attributes.Keys
Dim cmsitem As New ToolStripMenuItem
dt.Columns.Add(att, GetType(String))
cmsitem.Name = att
cmsitem.Text = att
cmsitem.Owner = cms
cmsitem.CheckOnClick = True
cmsitem.Checked = my.Settings.shownColumns.Contains(att)
AddHandler cmsitem.CheckedChanged, AddressOf showOrHideColumn
cms.Items.Add(cmsitem)
arr(i) = "No Data"
i += 1
Next
For i = 1 To my.settings.anzEntries
dt.Rows.Add(arr)
Next
MainDGV.DataSource = dt
MainDGV.ContextMenuStrip = cms
For Each attName as String In Attributes.key
showOrHideColumn(cms.Items(attName), New EventArgs())
Next
MainDGV.RowHeadersWidth = 90
MainDGV.RowTemplate.Height = 40
MainDGV.RowHeadersDefaultCellStyle.BackColor = Color.White
MainDGV.RowHeadersDefaultCellStyle.Font = New Font(MainDGV.ColumnHeadersDefaultCellStyle.Font, FontStyle.Bold)
MainDGV.ColumnHeadersDefaultCellStyle.BackColor = Color.White
MainDGV.ColumnHeadersDefaultCellStyle.Font = New Font(MainDGV.ColumnHeadersDefaultCellStyle.Font, FontStyle.Bold)
MainDGV.BackgroundColor = Color.White
End Sub
Private Sub showOrHideColumn(sender As Object, e As EventArgs)
Dim cmsitem As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
MainDGV.Columns(cmsitem.Name).Visible = cmsitem.Checked
End Sub
'taken from: http://stackoverflow.com/questions/710064/adding-text-to-datagridview-row-header
Private Sub nameRowHeaders(sender As Object, e As EventArgs) Handles MainDGV.DataBindingComplete
Dim dgv As DataGridView = CType(sender, DataGridView)
For i As Integer = 0 To dgv.RowCount - 1
dgv.Rows(i).HeaderCell.Value = ("Entry " &(i+1).toString())
Next
End Sub
End Class
EDIT:
As soon as you once select a row, all cells will be displayed in the right way until you restart the application