Determine tablelayoutpanel item dropped into - vb.net

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

Related

Loading up to 32768 Pictureboxes in Visual Basic

I have a app which is loading between 32^2 to 32768 8x8 px pictureboxes. All pictureboxes are on screen so I need to load them all and can't just load some.
As it stands, my program won't even run. Is there a better way to load that many pictureboxes?
I would like to share with you my project, but I don't know how to.............
Thanks though!
You'd likely run into a MemoryOverflowException with this design. From the sound of it, you're probably trying to render a map of some sort if that's the case then this answer is for you (otherwise just ignore it).
At a high level you should only create the number of PictureBox controls that can fit on the screen at any given time. You can calculate this with the following function:
Private Function CalculateSizeToFitParent(ByVal parent As Control, ByVal childSize As Size) As Size
Return New Size(parent.Width \ childSize.Width, parent.Height \ childSize.Height)
End Sub
You would implement it as such to create a PictureBox to fill up the visible area of the current Form:
Dim pictureBoxSize As Size = New Size(8, 8)
Dim visibleArea(pictureBoxSize.Width - 1, pictureBoxSize.Height - 1) As PictureBox
Dim numberOfPictureBoxes As Size = CalculateSizeToFitParent(Me, pictureBoxSize)
For x As Integer = 0 To numberOfPictureBoxes.Width - 1
For y As Integer = 0 To numberOfPictureBoxes.Height - 1
visibleArea(x, y) = New PictureBox() With {
.Location = New Point(x * pictureBoxSize.Width, y * pictureBoxSize.Height)
.Size = pictureBoxSize
}
Me.Controls.Add(visibleArea(x, y))
Next
Next
The next part is two-fold:
You need to keep track of where the top-left corner of the current visible are is
You will need to reload the images in the respective visual area of the map.
This assumes that you have a 2D array that stores your images. And please note that you don't recreate the PictureBox controls but rather you just reload the image of the existing control:
Private _currentLocation As Point = New Point(0, 0) ' If you're starting somewhere else change it here
Public Property CurrentLocation As Point
Get
Return _currentLocation
End Get
Set(ByVal value As Point)
If (value <> _currentLocation) Then
_currentLocation = value
Me.OnCurrentLocationChanged()
End If
End Set
End Property
Protected Overridable Sub OnCurrentLocationChanged()
RaiseEvent CurrentLocationChanged(Me, EventArgs.Empty)
End Sub
Public Event CurrentLocationChanged(ByVal sender As Object, ByVal e As EventArgs)
Private Sub MyForm_CurrentLocationChanged(ByVal sender As Object, ByVal e As EventArgs) Handles Me.CurrentLocationChanged
If (visibleArea Is Nothing) Then
Throw New Exception("The visible area has not been generated yet.")
End If
If (_currentLocation Is Nothing) Then
Throw New Exception("The CurrentLocation cannot be null.")
End If
Dim widthUpperBounds As Integer = My2DArrayOfImageLocations.GetUpperBounds(0) - 1
Dim heightUpperBounds As Integer = My2DArrayOfImageLocations.GetUpperBounds(1) - 1
For x As Integer = 0 To visibleArea.GetUpperBounds(0) - 1
For y As Integer = 0 To visibleArea.GetUpperBounds(1) - 1
If (x + _currentLocation.Width > widthUpperBounds OrElse y + _currentLocation.Height) Then
'This "block" is outside the view area (display a blank tile?)
Else
visibleArea(x, y).Load(My2DArrayOfImageLocations(x + _currentLocation.Width, y + _currentLocation.Height))
End If
Next
Next
End Sub
Now whenever you reset the CurrentLocation property (however you'd do that, e.g. arrow keys, asdw, etc.) it will redraw the visible area of the map.
Update
Please note that I "free-typed" this example and you may need to tweak it a bit. After some more thought, you'll probably also need to call the Refresh method of the PictureBox when you load in the image (I didn't test).

How to get a certain code for an equation

I'm a beginner working on my first application using Visual Basic in Visual Studio 2019.
I want to calculate this:
I have all Wi in (list view) and also (text box).
I have all Hi in (list view).
My problem is how could I multiply wi list view (or Wi text box) by hi list view and get this result in a third list view ?
I expect that the biggest problem you have found is getting the data from the ListViews - please note that using a Control to store data is usually a bad idea.
Note that array indexes in VB.NET (and C# and many other computer languages) start at zero (i.e. they are offsets, rather than indices as used in maths).
Once you have the data in arrays, it is easy to perform the calculation. Coming up with meaningful names for the methods and variables is also a problem.
With ListViews named ListViewW, ListViewH, and ListViewF I came up with this:
Public Class Form1
Dim rand As New Random()
Function Fvalues(Fb As Double, weights As Double(), values As Double()) As Double()
If weights.Length <> values.Length Then
Throw New ArgumentException("Number of weights does not equal number of values.")
End If
'TODO: Possibly more argument checking.
Dim total = 0.0
For i = 0 To weights.Length - 1
total += weights(i) * values(i)
Next
'TODO: Check for total = 0.
Dim F(weights.Length - 1) As Double
For i = 0 To weights.Length - 1
F(i) = Fb * weights(i) * values(i) / total
Next
Return F
End Function
Function ListViewToDoubles(lv As ListView) As Double()
Dim d As New List(Of Double)
For i = 0 To lv.Items.Count - 1
Dim dbl As Double
If Double.TryParse(lv.Items(i).Text, dbl) Then
d.Add(dbl)
End If
Next
Return d.ToArray()
End Function
Sub CreateSampleData()
For i = 1 To 5
ListViewW.Items.Add(rand.NextDouble().ToString())
ListViewH.Items.Add(rand.Next(0, 11).ToString())
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CreateSampleData()
Dim weights = ListViewToDoubles(ListViewW)
Dim values = ListViewToDoubles(ListViewH)
Dim f = Fvalues(0.5, weights, values)
For Each x In f
ListViewF.Items.Add(x.ToString())
Next
End Sub
End Class

VB.NET Filling form with graphics conundrum

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

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