VB.NET Filling form with graphics conundrum - vb.net

Afternoon, I have a maths-formula type query in VB.NET
I have a screen, it can be resized and the only input I get from the user, is the quantity of "balls" that go inside the screen.
I know I need to square root the width and height, to get my "quantity" of balls for a best-as equal rows and columns - but Im a bit stuffed on calculating:
The size of the balls.
The distance between the balls (if need-be, the balls need to be smaller)
and as per not-my example below, I need the ball start position to be at the top left corner of the form.
So, open up a copy of VS, add a new winforms project, paste the code below into the Paint event of the form and run it.
So what I need is: A indeterminate amount of balls to generate (fed by a user) to fill up the form, as equally best on the X and Y axis to fill up the form staying the same size and if possible, a little distance between them, say, a quarter of the size of the ball itself.
Feel free to resize the screen or change the _BallsInTotal variable for it to auto-generate the amount of balls.
Dim _BallsInTotal As Integer
_BallsInTotal = 100
Dim TotalColumns As Integer
Dim TotalRows As Integer
TotalColumns = Math.Sqrt(_BallsInTotal)
TotalRows = Math.Sqrt(_BallsInTotal)
Dim BallWidth As Single = 20
Dim BallHeight As Single = 20
Dim BallPositionX As Long = BallWidth * 2
Dim BallPositionY As Long = BallHeight * 2
Dim solidBrush As New SolidBrush(Color.FromArgb(255, 255, 0, 0))
Dim rows As Single
Dim columns As Single
For columns = 1 To TotalColumns
For rows = 1 To TotalRows
e.Graphics.FillEllipse(solidBrush, BallPositionX * columns, BallPositionY * rows, BallWidth , BallHeight )
Next
Next
Ive been scratching my head for the last two hour where Im at the point where its going to bleed! (seriously, its doing my head in).

What I've added is an InputBox that allows the user to specify the total number of balls. I placed the code in the OnPaint event for drawing the graphics. I've calculated the width of the columns and rows based on the form width/height. I'm using variables for the column/row in the For loops to track which column and row I'm drawing in, then using the column/row width/height to find my x and y (plus an additional .1 of the column/row width/height for spacing). And finally using .8 of the column/row width/height for how much space I want the ball to take up in the column/row.
Public Class Form1
Dim _total As Int32 = 120
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim columns As Int32 = Math.Ceiling(Math.Sqrt(_total))
Dim rows As Int32 = Math.Ceiling(Math.Sqrt(_total))
Dim width As Int32 = Me.ClientSize.Width
Dim height As Int32 = Me.ClientSize.Height
Dim columnWidth As Int32 = width / columns
Dim rowHeight As Int32 = height / rows
Dim brush As Brush = New SolidBrush(Color.FromArgb(255, 255, 0, 0))
Me.SuspendLayout()
Dim painted As Int32 = 0
For r As Int32 = 0 To rows - 1
For c As Int32 = 0 To columns - 1
Dim x As Int32 = (c * columnWidth) + (columnWidth * 0.1)
Dim y As Int32 = (r * rowHeight) + (rowHeight * 0.1)
e.Graphics.FillEllipse(brush, New Rectangle(x, y, columnWidth * 0.8, rowHeight * 0.8))
painted += 1
If painted = _total Then
Me.ResumeLayout()
Exit Sub
End If
Next
Next
End Sub
Private Sub Form1_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
Me.Invalidate()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim input As String = InputBox("Enter a total.")
Dim number As Int32 = 0
If Int32.TryParse(input, number) Then
_total = number
Me.Invalidate()
End If
End Sub
End Class

Related

Window Media player adding Grids on playing video using VB.net

I have developed coding in vb.net to insert media player and also i am able to add all features to media player like time, seek bar but for my project, it is mandatory to show flexible grid over the playing video which requires advanced level of programming.I learned to add lines grids on a form but forming grids over playing video and transform it size graphically is difficult,i would be glad if you help me...thank you in advance
the following code help in forming grids but it cannot be transformed and also it cannot be placed over media player
Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
Sub DrawGrid(g As Graphics, origin As Point, rows As Integer, columns As Integer, cellSize As Size)
Dim gridWidth As Integer = columns * cellSize.Width
Dim gridHeight As Integer = rows * cellSize.Height
Dim left As Integer = origin.X - (gridWidth \ 2)
Dim right As Integer = origin.X + (gridWidth \ 2)
Dim top As Integer = origin.Y - (gridHeight \ 2)
Dim bottom As Integer = origin.Y + (gridHeight \ 2)
For y As Integer = top To bottom + 1 Step cellSize.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 cellSize.Width
Dim pt1 As New Point(x, top)
Dim pt2 As New Point(x, bottom)
g.DrawLine(Pens.Black, pt1, pt2)
Next
g.DrawEllipse(Pens.Red, New Rectangle(origin.X - 5, origin.Y - 5, 10, 10))
End Sub
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim origin As New Point(Me.ClientRectangle.Width \ 2, Me.ClientRectangle.Height \ 2)
Dim cellSize As New Size(10, 10)
Dim rowCount As Integer = 10
Dim columnCount As Integer = 10
DrawGrid(e.Graphics, origin, rowCount, columnCount, cellSize)
End Sub
End Class

Problems with generating labels

The Problem: I'm programmatically generating labels but am having trouble referencing them in code because they don't exist at runtime.
The Context: For a game, I've generated a 10x10 grid of labels with the following:
Public lbl As Label()
Dim tilefont As New Font("Sans Serif", 8, FontStyle.Regular)
Private Sub Lucror_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim i As Integer = 0
Dim a As Integer = 0
Dim height As Integer
Dim width As Integer
height = 30
width = 30
ReDim lbl(99)
For i = 0 To 99
lbl(i) = New Label
lbl(i).Name = i
lbl(i).Size = New System.Drawing.Size(30, 30)
lbl(i).Location = New System.Drawing.Point((width), height)
lbl(i).Text = i
lbl(i).Font = tilefont
Me.Controls.Add(lbl(i))
width = width + 30
a = a + 1 'starting new line if required
If (a = 10) Then
height = height + 30
width = 30
a = 0
End If
Next
End Subenter code here
This worked fine but the labels function as tiles in the game and game tiles need to store 2-3 integers each as well as be able to be referenced through event handlers. I figured a possible way to store integers would be to generate 100 arrays, each named after a label and each holding the 2-3 integers, but that seems very redundant.
What I need:
On click and on hover event handlers for every label
An array (or dictionary?) to store 2-3 integers for every label
Labels have to reference each others names ie. do something to label with name (your name + 1).
The Question: Is there a simple way to achieve these three things with the current way I generate labels (and if so, how?) and if not, how else can I generate the 100 labels to make achieving these things possible?
Any help is much appreciated.
Your labels do exist at runtime, but not at compile time. Attaching events is a little different at runtime, you must use AddHandler.
Below is some sample code that should illustrate everything you're asking for. I've introduced inheritance as a way of saving data that is pertinent to each tile. The GameTile type behaves exactly as a label, and we've added some functionality for storing integers and naming the control.
Public Class Form1
Dim tilefont As New Font("Sans Serif", 8, FontStyle.Regular)
Public Property GameTiles As List(Of GameTile)
Private Sub Lucror_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim a As Integer = 0
Dim xPosition As Integer = 30
Dim yPosition As Integer = 30
GameTiles = New List(Of GameTile)
For i = 0 To 99
Dim gt As New GameTile(i.ToString)
gt.Size = New System.Drawing.Size(30, 30)
gt.Location = New System.Drawing.Point((yPosition), xPosition)
gt.Font = tilefont
gt.Integer1 = i + 1000
gt.Integer2 = i + 2000
gt.Integer3 = i + 3000
Me.Controls.Add(gt)
AddHandler gt.Click, AddressOf TileClickHandler
GameTiles.Add(gt)
yPosition = yPosition + 30
a = a + 1 'starting new line if required
If (a = 10) Then
xPosition = xPosition + 30
yPosition = 30
a = 0
End If
Next
End Sub
Private Sub TileClickHandler(sender As Object, e As EventArgs)
Dim gt = CType(sender, GameTile)
MsgBox("This tile was clicked: " & gt.Text &
Environment.NewLine & gt.Integer1 &
Environment.NewLine & gt.Integer2 &
Environment.NewLine & gt.Integer3)
End Sub
End Class
Public Class GameTile
Inherits Label
'this class should be in a separate file, but it's all together for the sake of clarity
Public Property Integer1 As Integer
Public Property Integer2 As Integer
Public Property Integer3 As Integer
Public Sub New(NameText As String)
MyBase.New()
Name = NameText
Text = NameText
End Sub
End Class

Pie Charts in VB.net

Im trying to create a pie chart and have seen many different ways of doing so. I am trying to do it with the seemingly simplest method that I could find however I cannot get it to work. My code is below
If chkboxPieChart.CheckState = True Then
Dim percents() As Decimal = {EStock, EWages, EAdvertising, ERent, EElectricity, ERepayments, EPackaging}
Dim colors() As Color = {Color.Blue, Color.Green, Color.Red, Color.Orange, Color.Purple, Color.Azure, Color.Chartreuse}
Dim graphics As Graphics = Me.picboxPieChart.CreateGraphics
Dim location As Point = New Point(462, 257)
Dim size As Size = New Size(200, 200)
DrawPieChart(percents, colors, graphics, location, size)
End If
With this being the code for the DrawPieChart Sub
Public Sub DrawPieChart(ByVal percents() As Decimal, ByVal colors() As Color, ByVal surface As Graphics, ByVal location As Point, ByVal pieSize As Size)
Dim sum As Integer = 0
For Each percent As Integer In percents
sum += percent
Next
Dim percentTotal As Integer = 0
For percent As Integer = 0 To percents.Length() - 1
surface.FillPie(New SolidBrush(colors(percent)), New Rectangle(location, pieSize), CType(percentTotal * 360 / 100, Single), CType(percents(percent) * 360 / 100, Single))
percentTotal += percents(percent)
Next
Return
End Sub
Any help is greatly appreciated, thanks

Fitting runtime buttons inside a form

I have a number of buttons between 5-20 and it's variable each time the form loads based on the user settings. I am trying to fit all these buttons on my form no matter what the size of the form is. The buttons are generated during runtime. I would like the first button to be 20 points from the top bar (at any size) and the rest of the buttons simply to fit in the form. This is what I have now but I have to maximize the form to view them all and also while I'm expanding the form the space between the buttons decreases and they overlap with each other whereas they should keep a relative distance. Any ideas?
Dim iButtonWidth, iButtonHeight, iVerticalSpace As Integer
If UserButtons.Count > 0 Then
iButtonHeight = Me.Size.Height - (Me.Size.Height * 0.85)
iButtonWidth = Me.Size.Width - (Me.Size.Width * 0.5)
iVerticalSpace = iButtonHeight / 3
For Each btn In UserButtons
btn.Size = New System.Drawing.Size(iButtonWidth, iButtonHeight)
btn.Location = New Point(20, 20 + btn.TabIndex * iVerticalSpace * 3)
Next
End If
Here's a quick example using the TableLayoutPanel to play with:
Public Class Form1
Private UserButtons As New List(Of Button)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Static R As New Random
Dim NumButtons As Integer = R.Next(5, 21) ' "a number of buttons between 5-20 and it's variable each time"
UserButtons.Clear()
For i As Integer = 1 To NumButtons
Dim btn As New Button()
btn.Text = i.ToString("00")
btn.Dock = DockStyle.Fill ' Optional: See how you like it with this on vs. off
UserButtons.Add(btn)
Next
DisplayButtons()
End Sub
Private Sub DisplayButtons()
TableLayoutPanel1.SuspendLayout()
TableLayoutPanel1.Controls.Clear()
TableLayoutPanel1.ColumnStyles.Clear()
TableLayoutPanel1.ColumnCount = 5 ' Fixed Number of Columns
For i As Integer = 1 To TableLayoutPanel1.ColumnCount
TableLayoutPanel1.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 911)) ' the size doesn't matter here, as long as they are all the same
Next
' Variable Number of Rows:
Dim RowsRequired As Integer = ((UserButtons.Count - 1) \ TableLayoutPanel1.ColumnCount) + 1 ' Integer Division
TableLayoutPanel1.RowStyles.Clear()
TableLayoutPanel1.RowCount = RowsRequired
For i As Integer = 1 To TableLayoutPanel1.RowCount
TableLayoutPanel1.RowStyles.Add(New RowStyle(SizeType.Percent, 911)) ' the size doesn't matter here, as long as they are all the same
Next
TableLayoutPanel1.Controls.AddRange(UserButtons.ToArray)
TableLayoutPanel1.ResumeLayout()
End Sub
End Class
First of all what kind of container are the buttons in? You should be able to set the container's AutoScroll property to true - then when controls within it spill out of the visible bounds you will get a scroll bar.
Then also what you could do is draw each button in more of a table with a certain number next to each other before dropping down to the next line (instead of just 1 button on each line). If that is an option that works for you then you could get more buttons within the visible space.
I happen to have an example to do the same thing with picture boxes (and text boxes under each picture box). Hope this helps:
Dim point As New Point(0, 0)
'create 11 picture and text boxes-you can make this number the number your user selects.
Dim box(11) As PictureBox
Dim text(11) As TextBox
Dim i As UInt16
For i = 0 To 11 'or whatever your number is
box(i) = New PictureBox
box(i).Width = 250 'your button width
box(i).Height = 170 'your button height
box(i).BorderStyle = BorderStyle.FixedSingle
box(i).Location = point
layoutsPanel.Controls.Add(box(i)) 'my container is a panel
text(i) = New TextBox
text(i).Height = 50
text(i).Width = 250
point.Y += box(i).Height
text(i).Location = (point)
layoutsPanel.Controls.Add(text(i))
point.Y -= box(i).Height 'reset Y for next picture box
'Put 4 picture boxes in a row, then move down to next row
If i Mod 4 = 3 Then
point.X = 0
point.Y += box(i).Height + text(i).Height + 4
Else
point.X += box(i).Width + 4
End If
Next

Determine tablelayoutpanel item dropped into

I am trying to determine which cell (row/column) of my TableLayoutPanel the user drops an object into. Currently I have only been able to find how to determine coordinates of where the item is dropped which is:
Dim location As Point = TableLayoutPanel1.PointToClient(New Point(e.X, e.Y))
However I can not figure out how to locate which cell that is in. I did find the command GetCellPosition and attempted that with the coordinates; however that did not work either.
TableLayoutPanel1.GetCellPosition(location)
You can try this function:
Private Function GetCellFromPoint(p As Point) As Point
Dim result As New Point(-1, -1)
Dim colWidths As Integer() = tlp.GetColumnWidths()
Dim rowHeights As Integer() = tlp.GetRowHeights()
Dim top As Integer = 0
For y As Integer = 0 To rowHeights.Length - 1
Dim left As Integer = 0
For x As Integer = 0 To colWidths.Length - 1
If New Rectangle(left, top, colWidths(x), rowHeights(y)).Contains(p) Then
result = New Point(x, y)
End If
left += colWidths(x)
Next
top += rowHeights(y)
Next
Return result
End Function
It just loops through the rows and columns to see if the passed in point is inside the existing cell. Note though, that GetColumnWidths and GetRowHeights do not appear in the intellisense dropdown.
Usage:
Private Sub tlp_MouseMove(sender As Object, e As MouseEventArgs) _
Handles tlp.MouseMove
Me.Text = GetCellFromPoint(e.Location).ToString
End Sub
BTW, GetCellPosition is expecting a control to be passed as a parameter, not a Point structure.
You can also use TableLayoutPanelCellPosition in place of Point in this function, since that is what GetCellPosition is returning in its function.
I have used this function (thanks a million) but I have found an issue. To define correctly the cell where the object is droped, we need to take into account the location of the TableLayoutPanel in the screen. I have solved this making the declaration of p (build with e.X and e.Y in the DragDrop event) and r (a reference of the location of the TableLayoutPanel in the screen).
Then you have to assing p = p - r and send that P to the function GetCellFromPoint(p).
Private Sub TableLayoutPanel1_DragDrop(sender As Object, e As DragEventArgs) Handles TableLayoutPanel1.DragDrop
Dim p As New Point(e.X, e.Y)
Dim r As Point
r = TableLayoutPanel1.PointToScreen(New Point(0, 0))
p.X = p.X - r.X
p.Y = p.Y - r.Y
MessageBox.Show(GetCellFromPoint(p).ToString)
End Sub