Picturebox will not display image - vb.net

I'm writing a program that will create and load pictureboxs at run time. The problem is that they will not show up or display anything. Not sure what i'm doing wrong. i have checked and the full path for the images are correct.
Sub DrawScreen()
'Call g.DrawImage to draw whatever you want in here
Dim layers(Me.ListBox1.Items.Count) As PictureBox
For i = 0 To ListBox1.Items.Count - 1
'Create New Layer as picturebox
layers(i) = New PictureBox
layers(i).Parent = Me.picWatch
layers(i).BackColor = Color.Transparent
layers(i).Visible = True
Select Case ListBox1.Items(i)
Case "image"
'Debug.Print(ListofLayers(i).Full_Path)
layers(i).Image = Image.FromFile(ListofLayers(i).Full_Path)
layers(i).Top = ListofLayers(i).X
picWatch.Controls.Add(layers(i))
Case "shape"
'Dim g As Graphics
'g.DrawRectangle()
Case "text"
Dim g As Graphics = layers(i).CreateGraphics
g.DrawString(ListofLayers(i).Text, New Font("Arial", 12), Brushes.White, ListofLayers(i).X, ListofLayers(i).Y)
Case Else
Debug.Print(ListBox1.Items(i))
End Select
Next
Me.Refresh()
End Sub

You never add the picture boxes to the form. Call Me.Controls.Add():
Me.Controls.Add(layers(i))
And as already pointed out by LarsTech:
You seem to have a typo here:
layers(i).Top = ListofLayers(i).X
X is the coordinate for the control's horizontal position and is the same as .Left.
Y however is the coordinate for the control's vertical position, which is the same as .Top.
Using CreateGraphics is a bad idea. For starters, what you draw with it will get removed when the control is redrawn. And since you're not disposing it you'll also have memory leaks.
Subscribe to the Paint event for each picture box instead and do all drawing in there.
Finally, just a little note: Array declarations in VB.NET does not specify how many items there are to be in the array, but to what index the array should end at. And since arrays are zero-based, this:
Dim layers(Me.ListBox1.Items.Count) As PictureBox
...is equal to this:
Dim layers(0 To Me.ListBox1.Items.Count) As PictureBox
Thus the array will contain ListBox1.Items.Count plus one since what's inside the parentheses merely specify the lower and/or upper bound.
To create an array with the "correct" amount of items you should always specify the size minus one:
Dim layers(Me.ListBox1.Items.Count - 1) As PictureBox

Related

Program first draws on invisible picturebox then picturebox becomes visible DESPITE Visibility supposed to c ome first then dynamic drawing

A snippet of my code:
Dim G As Graphics
Dim BBG As Graphics
Dim BB As Bitmap
Dim R As Rectangle
..................................................................
picMainScreen.Visible = True
G = picMainScreen.CreateGraphics
BB = New Bitmap(picMainScreen.Width, picMainScreen.Height)
For x = 0 To 256 * 3 - 1 Step 24
For y = 0 To 240 * 3 - 1 Step 24
R = New Rectangle(New Point(x, y), New Point(24, 24))
G.DrawRectangle(Pens.Black, R)
Next
Next
In this snippet of code, picMainScreen was a PictureBox that was originally not supposed to be visible.
Then through some conditions, picMainScreen was SUPPOSED to TURN Visible.
And THEN, the code draws all the rectangles onto the picture.
However, that isn't the case: the rectangles are first drawn onto the picture, and THEN the picture becomes visible.
Why does this happen? And what's the remedy?
Your rectangle instantiation is interesting since you are using two parameters of type Point.
R = New Rectangle(New Point(x, y), New Point(24, 24))
The Microsoft Docs show these parameter types;
Rectangle(Point, Size)
Initializes a new instance of the Rectangle class with the specified location and size.
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.rectangle.-ctor?view=netframework-4.7.2
I'm not sure if the parameter types are the problem; however you are mixing drawing graphics with a picture control and they might not cohabitate in the same space well.
You could try calling DoEvents() after making the picture control visible to force it to be displayed first.

Multiple textboxes with selection or focus to follow in a multiline textBox?

I have a problem with a multiline TextBox text box, which when searching for a character string, stays with its first focus on the word in the first location, but still continues to select the other words by not selecting them not !
Here is my code:
If testArray(p) / 2987 >= dub + (1787 / 2987) And testArray(p) / 2987 < dub + 1 Then
Main.TextBox31.Focus()
Main.TextBox31.SelectionStart = Main.TextBox31.Text.IndexOf(Me.TextBox1.Text)
Main.TextBox31.SelectionLength = Me.TextBox1.TextLength
Main.TextBox31.ScrollToCaret()
MsgBox("oui16")
System.Threading.Thread.Sleep(1000)
End If
The first line gives me the position of the search bytes. The TextBox31 control is the multiline control, in which I have the search bytes in the testArray (p) array. The TextBox1 control gives me the string I'm looking for.
PS:
I was able to achieve something like this with a listbox, it might translate over to textboxes too?
Dim rect As Rectangle
Dim bruh As New SolidBrush(Color.FromArgb(120, 0, 0, 225))
Dim gfx As Graphics = ListBox1.CreateGraphics
gfx.FillRectangle(bruh, rect)

How can I dynamically change record textbox hieghts in my report to the same as the highest for each record?

I have a report with two fields (txtQuestion & txtLookingFor) which is populated via a query. Sometimes txtQuestion is much longer than txtLookingFor (or vice versa) and I want the printed report to appear even, by making the shorter of the two equal in height to the longer of the two - for each record on this report.
I have some VBA which is triggered by even "Detail OnFormat" which is supposed to retrive the "height" values of each of the text boxes, find the maximum, and set both heights to this value. I cannot seem to get (read) the height values (from each record). But I can manually set the height values (per record) to some arbitrary value via VBA if I want.
I have tried all the "Can Grow" and "Can Shrink" options. My text boxes do grow to their own height (per record), but I cannot seem to read what that value is, for use in my VBA code.
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
maxheight = 100
If (Me.txtQuestion.Height > maxheight) Then
maxheight = Me.txtQuestion.Height
End If
If (Me.txtLookingFor.Height > maxheight) Then
maxheight = Me.txtLookingFor.Height
End If
Me.txtQuestion.Height = maxheight
Me.txtLookingFor.Height = maxheight
Me.txtNotes.Height = maxheight
End Sub
Here's some code I found on tek-tips that gives a general idea of how to make textboxes look the same height by drawing rectangles around them. The controls themselves are not resizable.
Private Sub Detail_Print(Cancel As Integer, PrintCount As Integer)
Dim intMaxHeight As Integer
Dim ctl As Control
'Find highest control in Detail section that has a tag property of "Border"
For Each ctl In Me.Section(0).Controls
If ctl.Tag = "Border" Then
If ctl.Height > intMaxHeight Then
intMaxHeight = ctl.Height
End If
End If
Next
'Draw a box around each control in Detail that has a tag property of "Border"
For Each ctl In Me.Section(0).Controls
If ctl.Tag = "Border" Then
Me.Line (ctl.Left, ctl.Top) - Step(ctl.Width, intMaxHeight), vbBlack, B
End If
Next
End Sub
Reference:
https://www.tek-tips.com/viewthread.cfm?qid=1676341

Flood fill algorithm for Visual Basic [duplicate]

I am an amateur in Visual Basic. I am attempting to recreate the game of Go, and I have created the board and am able to place stones on the intersections of the grid.
I now want to start capturing stones which are surrounded. I have looked online and found that flood fill is the best way to go about this. However, I have looked online for days, and I can't find anything that I can use, or manipulate to create this. I do not understand any other programming language, so I cannot use bits of code from Java, etc. And the bits of information for Visual Basic I have found do not make much sense to me as I am still a beginner.
I have attempted to start it by myself, starting off small with the situation of "If one stone were to be captured". I have two representations for the board, one is declared as "grid", and the other as "placed_stone".
"Grid" is the actual board where the users click to place their stones. placed_stone is a copy of this board, but I have used "0", "1" and "2" to represent empty, black and white respectively. I am using Windows Forms to recreate this game. This is the segment of code I have written for capturing the stones:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
' Figure out where the user clicked: min = 0, max = (gridsize - 1)
Dim pt As Point = board.PointToClient(Cursor.Position)
Dim colWidth As Integer = (1 / (GridSize + 1)) * board.Size.Width
Dim rowHeight As Integer = (1 / (GridSize + 1)) * board.Size.Height
Dim gridPosition As New Point(Math.Min(Math.Max((pt.X / colWidth) - 1, 0), GridSize - 1), Math.Min(Math.Max((pt.Y / rowHeight) - 1, 0), GridSize - 1))
Dim newcoordsx As Integer
Dim newcoordsy As Integer
' Now do something with gridPosition:
If Not Grid(gridPosition.X)(gridPosition.Y).HasValue Then 'If gird(x,y) is empty
illegalmovelbl.Hide() ' Hides the "Illegal Move" Label
If cp = True Then ' If current player is Black
This is the part where I got stuck and realised that the coding for every situation will take too long. I managed to write up the code for one situation:
newcoordsx = gridPosition.X + 1
If placed_stone(newcoordsx, gridPosition.Y) = 2 Then
newcoordsy = gridPosition.Y + 1
If placed_stone(newcoordsx, newcoordsy) = 1 Then
newcoordsy = gridPosition.Y - 1
If placed_stone(newcoordsx, newcoordsy) = 1 Then
newcoordsx = gridPosition.X + 2
If placed_stone(newcoordsx, gridPosition.Y) = 1 Then
newcoordsx = gridPosition.X + 1
Grid(gridPosition.X)(gridPosition.Y) = True 'Place a black stone at Grid(x,y)
Grid(newcoordsx)(gridPosition.Y) = Nothing
placed_stone(newcoordsx, gridPosition.Y) = 0
pass = False
cp = False
passbtn.BackColor = Color.White 'The passbutton changes colour to white
passbtn.ForeColor = Color.Black 'The passbutton font changes colour to black
End If
End If
End If
End If
'Grid(gridPosition.X)(gridPosition.Y) = True ' Place a black stone at Grid(x,y)
'placed_stone(gridPosition.X, gridPosition.Y) = 1
'pass = False
'cp = False
'passbtn.BackColor = Color.White ' The passbutton changes colour to white
'passbtn.ForeColor = Color.Black ' The passbutton font changes colour to black
ElseIf cp = False Then ' If current player is White
Grid(gridPosition.X)(gridPosition.Y) = False ' Place a white stone at Grid(x,y)
placed_stone(gridPosition.X, gridPosition.Y) = 2
pass = False
cp = True
passbtn.BackColor = Color.Black ' The passbutton changes colour to black
passbtn.ForeColor = Color.White ' The passbutton font changes colour to white
End If
ElseIf Grid(gridPosition.X)(gridPosition.Y).HasValue Then ' If gird(x,y) isn't empty
illegalmovelbl.Show() ' Shows the "Illegal Move" Label
MsgBox("Place your stone in a vacant point") ' Displays error message
End If
board.Invalidate() ' Force the board to redraw itself
End Sub
I have tried to use Wikipedia's algorithm on flood fill, and I understand the logic of how it works, but I just don't know how to program it in Visual Basic.
Flood-fill (node, target-color, replacement-color):
1. If target-color is equal to replacement-color, return.
2. If the color of node is not equal to target-color, return.
3. Set the color of node to replacement-color.
4. Perform Flood-fill (one step to the south of node, target-color, replacement-color).
Perform Flood-fill (one step to the north of node, target-color, replacement-color).
Perform Flood-fill (one step to the west of node, target-color, replacement-color).
Perform Flood-fill (one step to the east of node, target-color, replacement-color).
5. Return.
Of course, in Go, instead of colouring in the area, you have to remove the stones when capturing, and you don't start the flood fill from the stone you just placed to capture, you start from the closest stone you wish to capture.
Can you please explain how to use flood fill in Visual Basic in an easy way and how to implement it to this game of Go?
If anyone would like to look at the whole code, please let me know. I would appreciate any suggestions!
I'm not familiar with the rules/game-play of the game Go, so I'm not sure exactly what you are attempting to accomplish, but if you believe that a flood-fill type of algorithm is what you need, then I can at least offer some advice in how you could do that. The primary thing that your code needs is to be broken down into more granular methods. What are the steps that you are attempting to perform when the panel is clicked? Surely it's not just one thing. There are many different things going on--each of which could be performed by a separate dedicated method. For instance, if you had a method like this:
Private Function GetGridPosition(board As Panel, cursorPosition As Point) As Point
Dim pt As Point = board.PointToClient(Cursor.Position)
Dim colWidth As Integer = (1 / (GridSize + 1)) * board.Size.Width
Dim rowHeight As Integer = (1 / (GridSize + 1)) * board.Size.Height
Return New Point(Math.Min(Math.Max((pt.X / colWidth) - 1, 0), GridSize - 1), Math.Min(Math.Max((pt.Y / rowHeight) - 1, 0), GridSize - 1))
End Function
Then, in the Panel1_Click event handler, you could simplify the beginning of the code considerably, like this:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
Dim gridPosition As Point = GetGridPosition(board, Cursor.Position)
' ...
Sure, that makes the code more organized and easier to read, but that doesn't get you any closer to a flood fill algorithm, right? Well, yes, that's mostly true, but organization and readability are worthy goals in their own right, so lets continue anyway... The next step we need to perform is to make the player's move, and then, if the move was successful, we need to switch to the other player. So, let's first create the method to switch players:
Private Sub SwitchPlayer()
pass = False
cp = Not cp
passbtn.BackColor = GetPlayerForeColor(cp)
passbtn.ForeColor = GetPlayerBackColor(cp)
End Sub
Private Function GetPlayerForeColor(player as Boolean) As Color
If player Then
Return Color.White
Else
Return Color.Black
End If
End Function
Private Function GetPlayerBackColor(player as Boolean) As Color
If player Then
Return Color.Black
Else
Return Color.White
End If
End Function
You'll notice that I snuck (Chrome auto-spell tells me that isn't a word, but my American upbringing begs to differ) a couple other methods in there while I was at it. I'm sure their purpose is obvious. But stop right there. It's obvious? You'll notice that the comments are gone, yet the meaning of the code is still obvious. That's what we mean by self-documenting code. Comments are great when they're necessary, but it's even better when they aren't necessary at all.
So, pretend for now we have a method like this:
Private Function MakeMove(gridPosition As Grid, player As Boolean) As Boolean
' return true if the move was successful
End Function
Then the whole Panel1_Click event handler could look like this:
Private Sub Panel1_Click(sender As Object, e As EventArgs) Handles Panel1.Click
Dim board As Panel = DirectCast(sender, Panel)
Dim gridPosition As Point = GetGridPosition(board, Cursor.Position)
If MakeMove(gridPosition, cp) Then
SwitchPlayer()
Else
ShowIllegalMoveMessage()
End If
End Sub
Private Sub ShowIllegalMoveMessage()
illegalmovelbl.Show() 'Shows the "Illegal Move" Label
MsgBox("Place your stone in a vacant point") 'Displays error message
End Sub
Ok, so now we're getting to the meat of it. So, what are the steps that need to be taken when a move is being made? Well, I don't know, because I don't know the game. I leave that exercise up to you, but, if your inclinations are correct, and you need some kind of flood fill algorithm, then that probably means that you need some kind of PlaceStone action which can be repeated over and over again, so that should be its own method:
Private Sub PlaceStone(gridPosition As Point, player As Boolean)
' Do something
End Sub
Obviously the Do something is the key part of all this, and it's the one part that I can't help you with. But, if it's going to be a flood fill algorithm, I can give you a really big hint. Among all the other stuff it's going to do in there, it's going to be calling PlaceStone again, passing it a different grid position (one of the surrounding positions). So for instance, something like this:
Private Sub PlaceStone(gridPosition As Point, player As Boolean)
Dim north As Position = GetNorthPosition(gridPosition)
If Floodable(north, player) Then
PlaceStone(north, player)
End If
' ...
End Sub
When a method calls itself, like that, we call it recursion. But, until you start splitting your code up into dedicated little methods, each with its own encapsulated task, then you can't really add recursion. So, first get organized, then add recursion.

One picture box shown many times in the same form

My Goal is to create a maze in VS using VB.net, I currently have managed to make a random Generator that makes the "maze" and shows the location of the last wall made.
Horizontalwalls = Randomizer.Next(60, 91) 'Makes 60 - 90 Horizontal Walls
VirticalWalls = Randomizer.Next(60, 91) 'Makes 60 -90 Vertical Walls
Dim HLoops = 0 'counter for Horizontal walls
Dim VLoops = 0
lbxHorizontal.Items.Clear() 'empties the list box i have which stores the walls location
lbxvertical.Items.Clear()
Do While HLoops < (Horizontalwalls)
HLoops += 1 'adds to the counter
lbxHorizontal.Items.Insert(0, Randomizer.Next(0, 10))
lbxHorizontal.Items.Insert(0, Randomizer.Next(0, 10))
'Attempt at making visable walls
pbxhorizontalwall.Top = (lbxHorizontal.Items.Item(0) * GridSize - 2) 'This and next line puts the wall in desired location
pbxhorizontalwall.Left = (lbxHorizontal.Items.Item(1) * GridSize - 2)
Loop
however the only way i know to make all the walls visible is to make 90 horizontal wall pictures, go though naming them all, then GLaaa... there must be a easier way to copy the same image over the screen at the desired location.
At the moment, all i really want to know is the line of code that will copy the image (and maybe a way to mass clear them all when the maze is reset) and then i'll work out how to get it into place...
You first create the list of images with:
Dim imageList As New List(Of Bitmap)
imageList.Add("image to add") 'do it for all the images you have
Then create a bitmap:
Dim bitmapWall as Bitmap = New Bitmap(widthOfbitmap, heightofbitmap, Drawing.Imaging.PixelFormat.Format24bppRgb)
Draw the list of images to the bimap:
Dim objGraphics As Graphics = Graphics.FromImage(bitmapWall)
For i = 0 To imageList.Count
objGraphics.DrawImage(imageList(i), x, y, imageList(i).Width, imageList(i).Height)
Next
objGraphics.Dispose()
x,y is the coordinates of where your images are drawn (you should change them for every iteration)
Lastly:
Me.BackgroundImage = bitmapWall
Me.Invalidate()
Dont forget to dispose the list and the bitmap in the end.
valter