Odd Control behavior Visual Basic Windows Form - vb.net

I've dynamically added a text box to my main form on a button press:
Public Widget As UUTWidgetPanel
...
Public Sub New(ByVal UnitNo As Integer)
Me.UnitNo = UnitNo
Widget = New UUTWidgetPanel(UnitNo)
End Sub
...
Public Class UUTWidgetPanel
Public ContainerWidget As New FlowLayoutPanel
Public UnitLabel as New Label
Public CurrDrawTB As New TextBox
Public Sub New(ByVal UnitNo As Integer)
With UnitLabel
.Text = "Unit " & UnitNo.ToString
.Height = 25
.Anchor = AnchorStyles.Top + AnchorStyles.Left
.TextAlign = ContentAlignment.MiddleCenter
End With
With CurrDrawTB
.Width = 123
.Height = 25
.Text = "some text"
.ReadOnly = False
.Visible = True
.ForeColor = Color.Blue
'.Text = "CurrDrawTB"
End With
With ContainerWidget
.Controls.Add(UnitLabel)
.Controls.Add(CurrDrawTB)
I add the "ContainerWidget" FlowLayoutPanel to my main form from a method called by a button click as follows:
Private Sub AddUUT() 'adds instance of TestUnit to TestUnits, then it's controls to main form's "FlowLayoutPanel1"
Dim highestArrIdx As Integer = TestUnits.Count
TestUnits.Add(New TestUnit(highestArrIdx + 1))
FlowLayoutPanel1.Controls.Add(TestUnits.Item(highestArrIdx).Widget.ContainerWidget)
End Sub
Oddly enough, when I try to retrieve the info from CurrDrawTB, I receive an empty string, rather than the value "some text":
Dim text As String
text = Me.Widget.CurrDrawTB.Text
But writing to the textbox works:
Me.Widget.CurrDrawTB.Text = "Hi!" <--I see "Hi!" in the debugger and on the form.
Thanks in advance :)

Your CurrDrawTB Text property is being overwritten. This is a very common issue. The logic that you have posted works fine apart from this.

Related

Passing a variable from class module to userform

Hej,
I am trying to design a code, where a number of commandbuttons call the same userform. I have created the class module and got it to work so that they all call the userform, but I need the name of the button passed on from the class module into the userform initialize. I have tried it with property get and a public function, but can't get it to work. The variable I want to pass is the "ScreenShotCap" as string Anyone, who can help?
CLASS MODULE CODE
Option Explicit
Public ScreenShotCap As String
Public WithEvents CmdBtn As MSForms.CommandButton
Property Set obj(btns As MSForms.CommandButton)
'Defines the property of the object called
Set CmdBtn = btns
End Property
Private Sub CmdBtn_Click()
'Gets the button caption
ScreenShotCap = CmdBtn.Name
'Loads the userform
ufScreenshot.Show
End Sub
USERFORM CODE
Private Sub UserForm_Initialize()
Dim btnNo As Variant
Dim imNo1, imNo2, imNo3 As Integer
'Gets the number of the button
btnNo = Right(ScreenShotCap, 1)
'Sets the image number
imNo1 = Int(btnNo + 2)
imNo2 = Int(btnNo + 3)
imNo3 = Int(btnNo + 4)
'Loads the image from MSForms into userform
If ScreenShotCap = Worksheets("SW_TEST").OLEObjects("CommandButton1").Name Then
Application.ScreenUpdating = False
Me.Image1.Picture = Worksheets("SW_TEST").OLEObjects("Image1").Object.Picture
Me.Image2.Picture = Worksheets("SW_TEST").OLEObjects("Image2").Object.Picture
Me.Image3.Picture = Worksheets("SW_TEST").OLEObjects("Image3").Object.Picture
Application.ScreenUpdating = True
Else
Application.ScreenUpdating = False
Me.Image1.Picture = Worksheets("SW_TEST").OLEObjects("Image" & imNo1).Object.Picture
Me.Image2.Picture = Worksheets("SW_TEST").OLEObjects("Image" & imNo2).Object.Picture
Me.Image3.Picture = Worksheets("SW_TEST").OLEObjects("Image" & imNo3).Object.Picture
'after any change vba has to be told to refresh the UserForm for the change to appear
Me.Repaint
Application.ScreenUpdating = True
End If
End Sub
Move the codes in UserForm_Initialize() to a new sub with a parameter or just rename it to:
Public Sub LoadButtonImage(ScreenShotCap As String)
Then in your CmdBtn_Click() sub:
Load ufScreenshot.Show
ufScreenshot.LoadButtonImage CmdBtn.Name
uScreenshot.Show

Grid I can paint on

So I am trying to create an application to ease creation of pixel arts (school project), what I've done so far is draw a grid in a panel, next step would be to allow the user to click on a cell and have it painted, but I can't manage to make it work, here's the code I have:
Private Sub drawGrid(g As Graphics, rows As Integer, columns As Integer)
Dim originPoint As Point = New Point(10, 2)
Dim size As Size = New Size(64, 64)
Dim left As Integer = originPoint.X
Dim up As Integer = originPoint.Y
Dim right As Integer = originPoint.X + (columns * size.Width)
Dim down As Integer = originPoint.Y + (rows * size.Height)
For y As Integer = up To down + 1 Step size.Height
Dim pt1 As New Point(left, y)
Dim pt2 As New Point(right, y)
g.DrawLine(Pens.Black, pt1, pt2)
Next
For x As Integer = left To right + 1 Step size.Width
Dim pt1 As New Point(x, up)
Dim pt2 As New Point(x, down)
g.DrawLine(Pens.Black, pt1, pt2)
Next
End Sub
This draws a grid with the amount of columns and rows the user wants, but I've been struggling to allow painting
What I've been thinking is: dispose this code, and create a 'pixel' class, create the amount of 'pixel' objects based on user rows and columns, and draw each one individually, then just change each 'pixel's' color
This is a Grid class that allows setting the color of its cells.
The Grid cell are referenced using a List(Of List(Of Class)).
The Cell class Object contains is a simple Rectagle property that measures the size of the cell, and a Color property, which allows to set the color of the single cell:
Friend Class GridCell
Public Property Cell() As Rectangle
Public Property CellColor() As Color
End Class
You can define:
The size of the Grid → ColoredGrid.GridSize = new Size(...)
The number of Columns and Rows → ColoredGrid.GridColumnsRows = new Size(...)
The position of the Grid inside the Canvas → ColoredGrid.GridPosition = New Point(...)
The color of the Grid → ColoredGrid.GridColor = Color.Gray
The BackGround color of the cells → ColoredGrid.CellColor = Color.FromArgb(32, 32, 32)
The color of a selected cell → ColoredGrid.SelectedCellColor = Color.OrangeRed
The Grid class holds a reference to the control which will be used as the Canvas for the grid painting. This reference is set in the class contructor.
The Grid registers the Canvas control Paint() and MouseClick() events to respond to the related actions automatically.
When a Mouse Click is detected on the Canvas surface, the MouseEventArgs e.Location property reports the coordinates where the Click occurred.
To identify the Grid Cell where this action is performed, the GetUpdateCell() method inspects the List(Of List(Of GridCell)) using a simple LINQ SelectMany() and identified the Cell rectangle that contains the Mouse Click coordinates (expressed as a Point() value).
This identification is performed simply checking whether the Cell Rectangle.Contains(Point()).
When the cell is identified, the Canvas Invalidate() method is called, specifing the area to repaint.
This area corresponds to the Cell Rectangle, so only this section is repainted when a Cell is colored, to save resources and time.
To test it, create a Panel and a Button in a Form:
Imports System.Drawing
'This Grid object in defined at Form Class scope
Public ColoredGrid As ColorGrid
'Button used to trigger the Grid painting
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If ColoredGrid IsNot Nothing Then
ColoredGrid.Dispose()
End If
ColoredGrid = New ColorGrid(Panel1)
ColoredGrid.GridSize = New Size(300, 300)
ColoredGrid.GridColumnsRows = New Size(10, 10)
ColoredGrid.GridPosition = New Point(10, 10)
ColoredGrid.GridColor = Color.White
ColoredGrid.CellColor = Color.FromArgb(32, 32, 32)
ColoredGrid.SelectedCellColor = Color.OrangeRed
ColoredGrid.BuildGrid()
End Sub
This is a visual sample that shows how it works:
This is the main Grid class.
The ColorGrid Class supports IDisposable, because it registers the described events. These must be unregistered when the Class is not used anymore. Weird things can happen if you don't.
Public Class ColorGrid
Implements IDisposable
Private Grid As List(Of List(Of GridCell))
Private CurrentGridSize As New Size(100, 100)
Private GridColRows As New Size(10, 10)
Private CellSize As New Size(10, 10)
Private MouseCell As Point = Point.Empty
Private Canvas As Control = Nothing
Private UpdateCell As Boolean = False
Private NewGrid As Boolean = False
Public Sub New(DrawingControl As Control)
If DrawingControl IsNot Nothing Then
Me.Canvas = DrawingControl
AddHandler Me.Canvas.Paint, New PaintEventHandler(AddressOf Me.ControlPaint)
AddHandler Me.Canvas.MouseClick, New MouseEventHandler(AddressOf Me.MouseHandler)
Me.GridPosition = New Point(10, 10)
Me.CellColor = Color.FromArgb(32, 32, 32)
End If
End Sub
Public Property GridPosition() As Point
Public Property CellColor() As Color
Public Property SelectedCellColor() As Color
Public Property GridColor() As Color
Public Property GridSize() As Size
Get
Return Me.CurrentGridSize
End Get
Set(value As Size)
Me.CurrentGridSize = value
SetCellSize()
End Set
End Property
Public Property GridColumnsRows() As Size
Get
Return Me.GridColRows
End Get
Set(value As Size)
Me.GridColRows = value
SetCellSize()
End Set
End Property
Private Property RefreshCell() As GridCell
Friend Class GridCell
Public Property Cell() As Rectangle
Public Property CellColor() As Color
End Class
Private Sub SetCellSize()
Me.CellSize = New Size((Me.CurrentGridSize.Width \ Me.GridColRows.Width),
(Me.CurrentGridSize.Height \ Me.GridColRows.Height))
If Me.CellSize.Width < 4 Then Me.CellSize.Width = 4
If Me.CellSize.Height < 4 Then Me.CellSize.Height = 4
End Sub
Public Sub BuildGrid()
If Me.Canvas Is Nothing Then Return
Me.Grid = New List(Of List(Of GridCell))()
For row As Integer = 0 To GridColumnsRows.Height - 1
Dim RowCells As New List(Of GridCell)()
For col As Integer = 0 To GridColumnsRows.Width - 1
RowCells.Add(New GridCell() With {
.Cell = New Rectangle(New Point(Me.GridPosition.X + (col * Me.CellSize.Width),
Me.GridPosition.Y + (row * Me.CellSize.Height)),
Me.CellSize),
.CellColor = Me.CellColor})
Next
Me.Grid.Add(RowCells)
Next
Me.NewGrid = True
Me.Canvas.Invalidate()
End Sub
Private Sub ControlPaint(o As Object, e As PaintEventArgs)
If Me.NewGrid Then
e.Graphics.Clear(Me.Canvas.BackColor)
Me.NewGrid = False
End If
Me.Grid.
SelectMany(Function(rowcells) rowcells).
Select(Function(colcell)
If Me.UpdateCell Then
Using brush As New SolidBrush(Me.RefreshCell.CellColor)
e.Graphics.FillRectangle(brush, Me.RefreshCell.Cell.X + 1, Me.RefreshCell.Cell.Y + 1,
Me.RefreshCell.Cell.Width - 1, Me.RefreshCell.Cell.Height - 1)
End Using
Me.UpdateCell = False
Return Nothing
Else
Using pen As New Pen(Me.GridColor)
e.Graphics.DrawRectangle(pen, colcell.Cell)
End Using
Using brush As New SolidBrush(colcell.CellColor)
e.Graphics.FillRectangle(brush, colcell.Cell.X + 1, colcell.Cell.Y + 1,
colcell.Cell.Width - 1, colcell.Cell.Height - 1)
End Using
End If
Return colcell
End Function).TakeWhile(Function(colcell) colcell IsNot Nothing).ToList()
End Sub
Private Sub MouseHandler(o As Object, e As MouseEventArgs)
Me.RefreshCell = GetUpdateCell(e.Location)
Me.RefreshCell.CellColor = Me.SelectedCellColor
Dim CellColorArea As Rectangle = Me.RefreshCell.Cell
CellColorArea.Inflate(-1, -1)
Me.UpdateCell = True
Me.Canvas.Invalidate(CellColorArea)
End Sub
Private Function GetUpdateCell(CellPosition As Point) As GridCell
Return Me.Grid.
SelectMany(Function(rowcells) rowcells).
Select(Function(gridcell) gridcell).
Where(Function(gridcell) gridcell.Cell.Contains(CellPosition)).
First()
End Function
Public Sub Dispose() Implements IDisposable.Dispose
If Me.Canvas IsNot Nothing Then
RemoveHandler Me.Canvas.Paint, AddressOf Me.ControlPaint
RemoveHandler Me.Canvas.MouseClick, AddressOf Me.MouseHandler
Me.Grid = Nothing
End If
End Sub
End Class

Resize ToolStrip Button Image programatically at startup via toolstrip.ImageScalingSize

So I've read around this and will provide relevant properties at the end.
I'm looking to store a custom ToolStrip button image size in my.settings and load them at startup, changing them to a user set size.. The code I run at startup is:
Dim tss As New List(Of ToolStrip)
tss = GetAllControls(Me).OfType(Of ToolStrip)().ToList
For Each ts In tss
ts.BackColor = My.Settings.ToolStripBGColor
ts.ImageScalingSize = New Size(My.Settings.ToolStripImgScalingSize, My.Settings.ToolStripImgScalingSize)
ts.ResumeLayout()
ts.Invalidate()
ts.Refresh()
Next
ToolStripContainer.Invalidate()
ToolStripContainer.Refresh()
This does change the properties of all of the ToolStips. However, the images initially display at the default 16x16 UNTIL I drag them into another area of the ToolStripContainer. It then resizes correctly. This tends to imply to me that it's something to so with the draw of these containers/controls (hence the blanket bombing of .invalidate, .resumelayout and .refresh!)
Regarding proprieties, the relevant ones within designer view:
ToolStripButton
.autosize = true
.imagescaling = SizeToFit
ToolStrip
.autosize = true
.imagesclaing = 16,16 (later modified by code)
ToolStripContainer
couldn't see any that would effect this!??
This is one of those where you go round in circles for half a day over what essentially could be due to a janky aspect of .net! Could be me though...
Getting this to work with AutoSize=True is always a bit confusing. I've found that if you set it to False with layout suspended and then set it to True with layout enabled, that you can get the desired effect.
That description is probably clear as mud, so here is the code pattern.
With ToolStrip1
.SuspendLayout()
.AutoSize = False
.ImageScalingSize = New Size(40, 40)
.ResumeLayout()
.AutoSize = True
End With
Imports System.Drawing : Imports Microsoft.VisualBasic
Imports Microsoft.Win32 : Imports System
Imports System.IO : Imports System.Windows.Forms
Public Class Form1
Inherits Form
Private toolStripItem1 As ToolStripButton
Private toolStrip1 As ToolStrip
Public Sub New()
toolStrip1 = New System.Windows.Forms.ToolStrip()
toolStrip1.Size = New System.Drawing.Size(580,40)
toolStrip1.BackColor = System.Drawing.Color.MistyRose
toolStrip1.AutoSize = True
toolStripItem1 = New System.Windows.Forms.ToolStripButton()
toolStrip1.SuspendLayout()
Me.SuspendLayout()
toolStrip1.Items.AddRange(New System.Windows.Forms.ToolStripButton() _
{toolStripItem1})
toolStrip1.Location = New System.Drawing.Point(0, 0)
toolStrip1.Name = "toolStrip1"
toolStripItem1.AutoSize = False
toolStripItem1.Size = New System.Drawing.Size(110,95)
toolStripItem1.BackgroundImage = Image.FromFile("D:\Book4\Resources\icos\CUT.png")
toolStripItem1.Name = "toolStripItem1"
toolStripItem1.Text = "Cut"
toolStripItem1.Font = New System.Drawing.Font("Segoe UI", 16.0!, _
System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, _
CType(0, Byte))
toolStripItem1.TextAlign = System.Drawing.ContentAlignment.TopCenter
AddHandler Me.toolStripItem1.Click, New System.EventHandler _
(AddressOf Me.toolStripItem1_Click)
Me.AutoScaleDimensions = New System.Drawing.SizeF(6F, 13F)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(1500,900)
Me.BackColor = ColorTranslator.FromHtml("#808080")
Me.Controls.Add(Me.toolStrip1)
Me.Name = "Form1"
toolStrip1.ResumeLayout(False)
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
Public Sub Form1_Loaded(sender As Object, e As EventArgs) _
Handles MyBase.Load
Try
Dim ico As New System.Drawing.Icon("D:\Resources\icos\kvr.ico")
Me.Icon = ico
Catch ex As Exception
End Try
End Sub
Public Shared Sub Main()
Dim form1 As Form1 = New Form1()
form1.ShowDialog()
End Sub
Private Sub toolStripItem1_Click(ByVal sender As Object,ByVal e As EventArgs)
System.Windows.Forms.MessageBox.Show("Successfully enlarged ToolStripButtonImage size")
End Sub
End Class

how to keep checkedlistbox and a structure in sync

I have declared a structure
Public Structure cList
Public Name As String
Public Path As String
Public isChecked As Boolean
End Structure
And variables of it -
Public sourceList As New List(Of cList)
Public source As cList
And I have a CheckedListBox
What I want to achive is when any of element of checkedlistbox is selected or deselected it must reflact on
sourceList.isChecked = False 'When Deselected
or
sourceList.isChecked = True 'When Selected
Well this won't work here to achive this and I used a technique here in this ex.
For index = 0 To sourceList.Count - 1
source = sourceList(index)
'by this way I can access every source(item) of sourceList
source.Name = "test"
any changes
sourceList.Add(source)
'changes are reflecting to sourceList
Next
To achive sync of checkedListBox.CheckedItems and sourceList.isChecked I written this code
'First making isChecked value to false for every property in sourceList
For index = 0 To sourceList.Count - 1
source = sourceList(index)
source.isChecked = False
sourceList.Add(source)
Next
'Now assigning isChecked=true for Checked items of listbox
For Each item As String In CheckedListBox1.CheckedItems
For index = 0 To sourceList.Count - 1
source = sourceList(index)
If item = source.Name Then
source.isChecked = True
sourceList.Add(source)
End If
Next
Next
but it gives runtime errors
Every item selected or deselected didn't reflact on it's corresponding isChecked
Anyone please help??
This seems to work just fine.. The form load event handler is just there to populate the sourceList and to bind it to the CheckedListbox'. This of course populates theCheckedListBox` with the names of the Items in sourceList
The event handler is the important bit. If the Checkbox is already checked, it will uncheck it and mark the item with the same index value in sourceList's property 'isChecked` as false. If the checkbox is already unchecked, it will do the reverse.
Public Class cList
Property Name As String
Property Path As String
Property IsChecked As Boolean
End Class
Public sourceList As New List(Of cList)
Public source As cList
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
sourceList.Add(New cList With {.Name = "first", .Path = "firstpath", .IsChecked = False})
sourceList.Add(New cList With {.Name = "second", .Path = "secondpath", .IsChecked = False})
sourceList.Add(New cList With {.Name = "third", .Path = "thirdpath", .IsChecked = False})
CheckedListBox1.DataSource = sourceList
CheckedListBox1.DisplayMember = "Name"
End Sub
Private Sub CheckedListBox1_ItemCheck(sender As Object, e As ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
If e.CurrentValue = CheckState.Checked Then
e.NewValue = CheckState.Unchecked
sourceList.Item(e.Index).IsChecked = False
Else
e.NewValue = CheckState.Checked
sourceList(e.Index).IsChecked = True
End If
MessageBox.Show(sourceList(e.Index).Name & " " & sourceList(e.Index).IsChecked)
End Sub

vb.net creating a label using a class

I am new to using classes and OOP. I have created a class that will create a new label every time it is called. here is my code:
Public lbl As New Label
Public txt As New TextBox
Public controls As List(Of Control)
Public Sub New()
'Add a label
lbl.Name = "Label" & 1
lbl.Text = "Student " & 1 & ":"
lbl.Size = New Size(65, 20)
lbl.Location = New Point(10, (10 * 22) + 5)
controls.Add(lbl)
End Sub
When i call this class i get this error message:
An unhandled exception of type 'System.NullReferenceException' occurred in Project.exe Additional information: Object reference not set to an instance of an object.
The line of code the message highlights is:
controls.Add(lbl)
Any help would be appreciated, thanks.
Public lbl As New Label
Public txt As New TextBox
Public controls As List(Of Control)
Public Sub New()
'Add a label
lbl.Name = "Label" & 1
lbl.Text = "Student " & 1 & ":"
lbl.Size = New Size(65, 20)
lbl.Location = New Point(10, (10 * 22) + 5)
If (controls is nothing) = True Then controls = new list(of Control)
controls.Add(lbl)
End Sub