VB Tab control in draw.mode - vb.net

I am trying to make the tabs show horizontally on the right side of my form. I can't use tabcontrol from tool box because of how the text displays.
I am using a code that I found to help me. But after exhausting all of my resources I can't seem to get the code to point to the tabPages collection. I have entries in there but the tabs show up blank.
Public Sub New()
tabControl1 = New TabControl()
Dim tabPage1 As New TabPage()
' Sets the tabs to be drawn by the parent window Form1.
' OwnerDrawFixed allows access to DrawItem.
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed
tabControl1.Controls.Add(tabPage1)
tabControl1.Location = New Point(25, 25)
tabControl1.Size = New Size(250, 250)
tabPage1.TabIndex = 0
myTabRect = tabControl1.GetTabRect(0)
ClientSize = New Size(300, 300)
Controls.Add(tabControl1)
AddHandler tabControl1.DrawItem, AddressOf OnDrawItem
End Sub!
tab Example

You can set the .Alignment property of the TabControl to Left to use horizontal tabs.
If you don't like that, try a FlowLayoutPanel with a separate TabControl for each tab, e.g.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Dim flp As New FlowLayoutPanel
flp.Dock = DockStyle.Left
flp.AutoSize = True
flp.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowOnly
Me.Controls.Add(flp)
For i As Integer = 0 To 5
Dim tbc As New TabControl
Dim tbp As New TabPage("Tab" & i.ToString)
tbc.TabPages.Add(tbp)
flp.Controls.Add(tbc)
Next i
End Sub
End Class

I ended up compiling this code from different sources to get this working,
Private Sub TabControl1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles TabControl1.DrawItem
Dim g As Graphics
Dim sText As String
Dim iX As Integer
Dim iY As Integer
Dim sizeText As SizeF
Dim ctlTab As TabControl
Dim r As New RectangleF(e.Bounds.X, e.Bounds.Y + 2, e.Bounds.Width, e.Bounds.Height - 2)
ctlTab = CType(sender, TabControl)
g = e.Graphics
sText = ctlTab.TabPages(e.Index).Text
sizeText = g.MeasureString(sText, ctlTab.Font)
iX = e.Bounds.Left + 6
iY = e.Bounds.Top + (e.Bounds.Height - sizeText.Height) / 2
g.DrawString(sText, ctlTab.Font, Brushes.Black, iX, iY)
End Sub
The text doesn't show up in the RAD but it does when I debug/run it.
Many thanks to LUC001 # http://www.dreamincode.net/forums/topic/125792-how-to-make-vertical-tabs/

Related

Creating a simple addition form application programmatically

I want to create a simple addition program in vb.net form application. Also i want to create all controls programmatically. I have three text boxes and one button. When the button is clicked , it take value from two text boxes and assign it to the third text box value.
I am unable to get text boxes string from button click handle.
My coding is as follows:
Public Class Form1
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Pushbutton
Dim PushButton As New Button()
PushButton.Text = "Add"
PushButton.Location = New Point(10, 100)
Me.Controls.Add(PushButton)
AddHandler PushButton.Click, AddressOf myButtonHandler_Click
'
'TextBox1
Dim TextBox1 As New TextBox
TextBox1.Location = New Point(10, 3)
Me.Controls.Add(TextBox1)
'TextBox2
Dim TextBox2 As New TextBox
TextBox2.Location = New Point(200, 3)
Me.Controls.Add(TextBox2)
Dim TextBox3 As New TextBox
TextBox3.Location = New Point(200, 100)
Me.Controls.Add(TextBox3)
End Sub
Private Sub myButtonHandler_Click(ByVal sender As Object, ByVal e As EventArgs)
End Sub
Public Function ADD(x As Double, y As Double) As Double
ADD = x + y
End Function
End Class
Moving the declaration of the controls to Form level allows them to be seen in all the methods of the form.
Public Class Form3
Private TextBox1 As New TextBox
Private TextBox2 As New TextBox
Private TextBox3 As New TextBox
Private PushButton As New Button
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Pushbutton
PushButton.Text = "Add"
PushButton.Location = New Point(10, 100)
Me.Controls.Add(PushButton)
AddHandler PushButton.Click, AddressOf myButtonHandler_Click
'TextBox1
TextBox1.Location = New Point(10, 3)
Controls.Add(TextBox1)
'TextBox2
TextBox2.Location = New Point(200, 3)
Controls.Add(TextBox2)
'TextBox3
TextBox3.Location = New Point(200, 100)
Controls.Add(TextBox3)
End Sub
Private Sub myButtonHandler_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim firstNumber = CDbl(TextBox1.Text)
Dim secondNumber = CDbl(TextBox2.Text)
TextBox3.Text = ADD(firstNumber, secondNumber).ToString
End Sub
Public Function ADD(x As Double, y As Double) As Double
ADD = x + y
End Function
End Class
You can technically do it the way you were, but only if you use an anonymous event handler for the button click event as shown below:
Public Class Form1
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TextBox1
Dim TextBox1 As New TextBox
TextBox1.Location = New Point(10, 3)
Me.Controls.Add(TextBox1)
'TextBox2
Dim TextBox2 As New TextBox
TextBox2.Location = New Point(200, 3)
Me.Controls.Add(TextBox2)
Dim TextBox3 As New TextBox
TextBox3.Location = New Point(200, 100)
Me.Controls.Add(TextBox3)
'Pushbutton
Dim PushButton As New Button()
PushButton.Text = "Add"
PushButton.Location = New Point(10, 100)
Me.Controls.Add(PushButton)
AddHandler PushButton.Click, Sub()
Dim dblA, dblB As Double
If Double.TryParse(TextBox1.Text, dblA) AndAlso Double.TryParse(TextBox2.Text, dblB) Then
TextBox3.Text = ADD(dblA, dblB)
Else
MessageBox.Show("One or more Invalid Inputs")
End If
End Sub
End Sub
Public Function ADD(x As Double, y As Double) As Double
ADD = x + y
End Function
End Class
Though I do recommend moving those control declarations out to Form level as Mary suggested.

Add Event to Picture Box dynamically vb.net

I'm trying to add pictureboxes dynamically in vb.net.
If i play with the vars, changing the "i" value i can add the images and the event to the last picturebox created (i can only click the last images).
But when i use the code below, it says the there's something out of boundaries ( Index outside the bounds of the matrix ).
What am i doing wrong? Tks
Imports System.IO
Public Class FormMain
Dim Path1 As String = Path.GetDirectoryName(Application.ExecutablePath) & "\Source\Images\1.png"
Dim Path2 As String = Path.GetDirectoryName(Application.ExecutablePath) & "\Source\Images\2.png"
Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CreateImages()
End Sub
Dim i As Integer
Dim Logo(i) As PictureBox
Sub CreateImages()
Dim i As Integer = TextBoxNumberImages.Text
For i = 0 To i - 1
Logo(i) = New PictureBox
Logo(i).Name = "Image" + Str(i)
Panel1.Controls.Add(Logo(i))
Logo(i).Image = Image.FromFile(Path1)
Logo(i).SizeMode = PictureBoxSizeMode.StretchImage
AddHandler Logo(i).Click, AddressOf _Click
Next
End Sub
'------ADD EVENT----
Dim IsImageSelected(i) As Boolean
Private Sub _Click(ByVal sender As Object, ByVal e As EventArgs)
If IsImageSelected(i) = False Then
Logo(i).Image = Image.FromFile(Path2)
IsImageSelected(i) = True
Else
Logo(i).Image = Image.FromFile(Path1)
IsImageSelected(i) = False
End If
End Sub
----EDIT----
I just changed the var declaration to inside of the function:
Sub CreateImages()
Dim i As Integer = TextBoxNumberImages.Text
Dim Logo(i) As PictureBox
For i = 0 To i - 1
Logo(i) = New PictureBox
Logo(i).Name = "Image" + Str(i)
Panel1.Controls.Add(Logo(i))
Logo(i).Image = Image.FromFile(Path1)
Logo(i).SizeMode = PictureBoxSizeMode.StretchImage
AddHandler Logo(i).Click, AddressOf _Click
Next
End Sub
Now it creates the images the way i want, but i can't access the pictureboxes in the event. Help?
Don't use an array, use a List(Of PictureBox) instead. You could also store the selected state in the Tag() of the PictureBox. To get a reference to the PictureBox that was clicked, cast the Sender parameter. All together it would look something like this:
Private Logo As New List(Of PictureBox)
Sub CreateImages()
Dim i As Integer = TextBoxNumberImages.Text
For i = 0 To i - 1
Dim pb As New PictureBox
pb = New PictureBox
pb.Tag = False ' <-- initial not selected state
pb.Name = "Image" + Str(i)
Panel1.Controls.Add(pb)
pb.Image = Image.FromFile(Path1)
pb.SizeMode = PictureBoxSizeMode.StretchImage
AddHandler pb.Click, AddressOf _Click
Logo.Add(pb)
Next
End Sub
Private Sub _Click(ByVal sender As Object, ByVal e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Dim selected As Boolean = DirectCast(pb.Tag, Boolean)
If selected = False Then
pb.Image = Image.FromFile(Path2)
Else
pb.Image = Image.FromFile(Path1)
End If
pb.Tag = Not selected ' toggle selected state
End Sub

How do I add buttons with event handlers to a form dynamically?

Is it possible to do this dynamically? How?
Code:
Public Class Form1
Dim c(40) As Integer
Dim IMG As PictureBox
Dim lbl_n(40) As Label
Dim lbl_pr(40) As Label
Dim lbl_ref(40) As Label
Dim lbl_dim(40) As Label
Dim lbl_col(40) As Label
Dim btn_add(40) As Button
Dim btn_rmv(40) As Button
Dim tb_qt(40) As TextBox
AddHandler btn_add(0).Click, AddressOf btn_add0_Click
AddHandler btn_add(1).Click, AddressOf btn_add1_Click
[...]
AddHandler btn_add(40).Click, AddressOf btn_add40_Click
Public Sub btn_add0_Click(ByVal sender As Object, ByVal e As System.EventArgs)
c(0) = c(0) + 1
tb_qt(0).Text = c(0)
End Sub
Public Sub btn_add1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
c(1) = c(1) + 1
tb_qt(1).Text = c(1)
End Sub
[...]
Public Sub btn_add40_Click(ByVal sender As Object, ByVal e As System.EventArgs)
c(40) = c(40) + 1
tb_qt(40).Text = c(40)
End Sub
These are the images with program running (they are edited):
Form1
Form2
I want to dynamically, because I could use more than 40 products! And I need to do 40 addhandlers, so that more 40 to remove!
How can I do that?
Yes, You can do that dynamically.
In this example, I put those buttons and textboxes into Panel.
There is example with comments which line is for what :
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'dynamically adding buttons (so You don't need create every button separately)
For x = 1 To 40
Dim btn As New Button 'create new button
btn.Name = "btn_add" & x.ToString 'set ID for button (example: btn_add1, btn_add2, ... btn_add40)
btn.Text = "+" 'set button text
btn.Tag = x.ToString 'set button NO. for finding corrent textbox whos belong to this button (for example: tb_qt1 belong to buttons btn_add1 and btn_rem1)
btn.Width = 24 'this is for styling
btn.Top = (x * btn.Height) + 3 'for styling, too. Top poistion of button
btn.Left = 0 'for styling, too. Left position of button
AddHandler btn.Click, AddressOf btnAdd_Click 'creating sub called btnAdd_Click (this sub will handle all, in this case 40, buttons)
Panel1.Controls.Add(btn) 'for this example I put buttons and textboxes into panel (autoscroll set to True)
btn = New Button 'same thing just for remove button
btn.Name = "btn_rem" & x.ToString
btn.Text = "-"
btn.Tag = x.ToString
btn.Width = 24
btn.Top = (x * btn.Height) + 3
btn.Left = btn.Width + 3
AddHandler btn.Click, AddressOf btnRem_Click 'creating sub called btnRem_Click (this sub will handle all, in this case 40, buttons)
Panel1.Controls.Add(btn)
Dim txt As New TextBox 'same thing for textboxes
txt.Name = "tb_qt" & x.ToString
txt.Text = "0"
txt.Tag = x.ToString
txt.Top = (x * btn.Height) + 3
txt.Left = btn.Left + btn.Width + 3
txt.TextAlign = HorizontalAlignment.Right
Panel1.Controls.Add(txt)
Next
End Sub
Public Sub btnAdd_Click(sender As Object, e As EventArgs)
Dim btn As Button = DirectCast(sender, Button) 'detect which button clicked. You can add line: MsgBox(btn.Name) to see what happening
Dim txt As TextBox = Panel1.Controls.Find("tb_qt" & btn.Tag.ToString, True)(0) 'find textbox which belong to this button. this is why set .Tag into buttons
txt.Text = CInt(txt.Text) + 1 'just do math and change value, by adding one(1), in textbox (by this way I avoid using Your Dim c(40) As Integer)
End Sub
Public Sub btnRem_Click(sender As Object, e As EventArgs)
Dim btn As Button = DirectCast(sender, Button) 'same thing like for btnAdd_Click, but we doing subtract for one(1) value in textbox
Dim txt As TextBox = Panel1.Controls.Find("tb_qt" & btn.Tag.ToString, True)(0)
txt.Text = CInt(txt.Text) - 1
End Sub
Because I use panel like container for all those buttons and textboxes, You have to set AutoScroll=True for panel.
I hope so You will understand how it's work for start.

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

How Can i target one of my pictureboxes created on runtime? VB.NET

So basically, i have successfully randomized certain pictureboxes in a grid to contain mines, and show that mine, and for testing purposes, those mines are currently showing. What do you think I need to do to be able to say:
If, you click this box and mine = 1 (there's a mine), then you lose.
Else, keep going.
simple enough, but i want to apply this to all boxes, no matter how big the grid is. (ZonesX * Zones Y)
The furthest I have gotten is being about to pop up a MsgBox() when anyone of them is clicked.
This is all created on runtime. Heres my code.
Public Class Form1
Inherits System.Windows.Forms.Form
Dim images(8) As Image 'declares image array
Dim zonesY As Integer = 10
Dim zonesX As Integer = 10
Dim Guy As Object
Dim pbxNewZone As PictureBox = DirectCast(Guy, PictureBox) 'declares pbxNewZone as a picturebox variable
Dim generator As New Random
Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
images(0) = Image.FromFile("blank.png")
images(1) = Image.FromFile("1.png")
images(2) = Image.FromFile("2.png")
images(3) = Image.FromFile("3.png")
images(4) = Image.FromFile("4.png")
images(5) = Image.FromFile("5.png")
images(6) = Image.FromFile("clear.png")
images(7) = Image.FromFile("hit.png")
images(8) = Image.FromFile("mine.png")
Dim x As Integer 'declares x as an integer variable
Dim y As Integer 'declares y as an integer variable
Me.SuspendLayout() 'suspends creation of layout
For y = 1 To zonesY 'starts a For loop (1 to zonesY number of loops)
For x = 1 To zonesX 'starts a For loop (1 to zonesX number of loops)
Dim zonesize1 As Integer
Dim zonesize2 As Integer
pbxNewZone = New PictureBox
Dim blockStatus As Integer
Dim allZones As Integer
allZones = zonesX * zonesY
blockStatus = generator.Next(0, allZones)
pbxNewZone.Name = y & ", " & x
If blockStatus < (allZones / 10) Then
pbxNewZone.Tag = True
If pbxNewZone.Tag = True Then
pbxNewZone.Image = images(8)
End If
Else
pbxNewZone.Tag = False
If pbxNewZone.Tag = False Then
pbxNewZone.Image = images(0)
End If
End If
pbxNewZone.Height = 16
pbxNewZone.Width = 16
pbxNewZone.Tag = 0
zonesize1 = pbxNewZone.Height 'sets out all of the boxes on the form.
zonesize2 = pbxNewZone.Width
pbxNewZone.Left = ((x - 1) * zonesize1 + 15)
pbxNewZone.Top = ((y - 1) * zonesize2 + 15)
Me.Controls.Add(pbxNewZone)
' Wire this control up to an appropriate event handler
AddHandler pbxNewZone.Click, AddressOf pbxNewZoneClicked
Next
Next
Me.Height = (pbxNewZone.Height * zonesY + 63) 'sets the height of fmmGame
Me.Width = (pbxNewZone.Width * zonesX + 40) 'sets the width of frmGame
End Sub
Private Sub pbxNewZoneClicked(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Dim pbTag As Boolean = DirectCast(sender, Boolean)
If pb.Tag = True Then
pb.Image = images(7) 'Hit Image
Else
pb.Image = images(6) 'Clear Image
End If
MsgBox(pb.Tag)
End Sub
End Class
A quick way to do it would be to use the Tag element of the PictureBox to keep track of whether there is a mine or not (or any of your other conditions).
pbxnewzone.Tag = 1 'can assign tags to all of your pictureboxes in a loop or at random if need be
Then, access the Tag property by casting the sender argument of your pbxNewZoneClicked method back to a PictureBox:
Dim pb As PictureBox = DirectCast(sender, PictureBox)
If (pb.Tag = 1) Then
'change game accordingly
End If
Unless I'm missing something, set minePictureBox1.Tag = true then check it on the click event. Or you could set it to 1 or whatever. Tag is an object.
Is that what you're looking for? Just a way to know if it's a mine or not?
I would think one panel for the entire grid would be easier to manage and less resource hungry then a picturebox for each and every cell.
But for your click issue:
Private Sub pbxNewZoneClicked(ByVal sender As Object, ByVal e As EventArgs)
With DirectCast(sender, PictureBox)
MsgBox(.Name)
End With
End Sub