Image won't change in picturebox, vb.net - vb.net

I'm trying to code it so that i can create a picture box from a method in a class. However when my picture box is drawn it doesn't display any image, it only shows a white square of the specified dimensions in the specified location.
Here is the code which i am using to create said picture box:
Public Sub DrawEnemy(ByRef formInstance)
Dim enemypic As New PictureBox
enemypic.Image = Image.FromFile("C:\fboi1\Enemy.Png")
enemypic.Width = 64
enemypic.Height = 64
enemypic.Location = New Point(Me.EnemyPosX, EnemyPosY)
enemypic.Visible = True
formInstance.Controls.Add(enemypic)
End Sub
And here is where i am calling the method from:
Dim Enemy1 As New computerControlled(1, 1)
Enemy1.DrawEnemy(Me)

Please add the following code in your DrawEnemy() method:
enemypic.SizeMode = PictureBoxSizeMode.StretchImage

When i drag the console window suddenly the white box turns into the image i wanted.
Aha! This means the code is not causing the form to be repainted. We can trigger that by calling the Invalidate() function.
Public Sub DrawEnemy(formInstance As Form)
Dim enemypic As New PictureBox
enemypic.Image = Image.FromFile("C:\fboi1\Enemy.Png")
enemypic.Width = 64
enemypic.Height = 64
enemypic.Location = New Point(Me.EnemyPosX, EnemyPosY)
enemypic.Visible = True
formInstance.Controls.Add(enemypic)
formInstance.Invalidate()
End Sub
If you're calling this several times in a loop, you would instead handle this after the loop, where you also block repainting (to prevent flickering) until the loop is finished.
form.SuspendLayout()
For Each enemy In ...
'...
DrawEnemy(form)
Next
form.Invalidate()
form.ResumeLayout()
It's also possible you only need to Invalidate() the picturebox.

Related

VSTO VB tree view Node = Sheet tab color

I'm building a VSTO project with a simple action pane containing a treeview. Coming from VBA, things are similar, but not the same and I'm a bit confused.
What I want to do is load all sheets to the tree view, and give each node the color of the respective sheet. I'm getting an error at the commented line below, I believe the error is coming from the fact that the N.BackColor is in RGB and SH.Tab.Color is in colorcode.
The question is should I use a different property to get the same color type, or do I need to cast it. If I need to cast it please help me with this, as most of the documentation is in C#, and I'm not sure where to look for an answer
Private Sub ActionPane_SheetSearch_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim SH As Excel.Worksheet, N As TreeNode
With Me
.Width = 200
End With
With Me.TreeView1
.ItemHeight = 20
For Each SH In Globals.ThisWorkbook.Sheets
N = .Nodes.Add(SH.Name)
N.Tag = SH.CodeName
'N.BackColor = SH.Tab.Color
Next
End With
End Sub
Also with .Width = 200 i'm trying to customize the with of the action pane, but it's ignoring the code or I'm not doing it correclty.
I tried setting the starting width at the begining as well, it does not respond.
Please let me know how can I set the starting with, and also set the default position to left instead of right.
Private Sub ThisWorkbook_Startup() Handles Me.Startup
Globals.ThisWorkbook.ActionsPane.Controls.Add(taskPane)
Globals.ThisWorkbook.Application.DisplayDocumentActionTaskPane = True
taskPane.Width = 400
taskPane.Show()
End Sub
Use the Custom task panes instead. The DockPosition property sets an enumerated value specifying the docked position of a CustomTaskPane object. The Width property sets the width of the task pane specified by the CustomTaskPane object.

Accessing multiple PictureBoxes (or any form control) in Visual Basic?

So I'm making a game in VB for learning purposes and now I'm struggling with this problem:
I'm trying to do a For loop that draws the level map. However, I just can't seem to figure out it. This is an example of what I'm trying to do:
For index as integer = 1 to 192
PictureBox(index).Image = bg(map(x,y)) 'this is causing me problems
x=x+1
if x=16 then
x=0
y=y+1
End If
Next
But since PictureBox(index).Image doesn't seem to be the correct answer, it simply throws me an error.
Is there any way to do this?
EDIT:
Shortly, I need to set PictureBox.Image's from 1 to 192 like this without having 192 lines of code:
PictureBox1.Image = bg(map(0,0))
PictureBox2.Image = bg(map(1,0))
PictureBox3.Image = bg(map(2,0))
PictureBox4.Image = bg(map(3,0))
'etc....
Instead I wan't to set them in a For loop. I don't want to have extra lines of code.
EDIT2:
The PictureBoxes are added in the editor.
In the designer set the property Tag of each PictureBox to the string value composed by the x and y required to pass to the map function
For example:
PictureBox1 should have the Tag property set to "0,0"
PictureBox2 set the Tag property to "1,0",
....
PictureBox17 will have the Tag property set to "0,1"
and so on until you have mapped all your pictureboxes with the correct values.
Then your code could be changed to
' Assuming the PictureBox are all childs of the Form
For Each pic in Me.Controls.OfType(Of PictureBox)()
Dim tag = pic.Tag
' You could omit this check if you have only the pictureboxes
' set with a valid Tag property
if Not string.IsNullOrEmpty(tag) Then
Dim xyCoords = tag.ToString().Split(","c)
pic.Image = bg(map(Convert.ToInt32(xyCoords(0),
Convert.ToInt32(xyCoords(1))))
End if
Next
I'm going to make a huge assumption here and assume that you already have the PictureBox's on the form prior to reaching this code and they have Id's PictureBox1 through PictureBox192. The code would look like the following. You need to:
1. Retrieve the element by its ID
2. Cast/convert it from an object to a PictureBox
3. Set it's Image property appropriately.
Dim pBox As PictureBox ' To store each pic box in
For index as integer = 1 to 192
pBox = Me.Controls.Find(PictureBox&&index) ' Try to find pic box by ID
If Not pBox Is Nothing Then ' If able to find element by this ID
DirectCast(pBox, PictureBox).Image = bg(map(x,y))
End If
x=x+1
if x=16 then
x=0
y=y+1
End If
Next

How to get Winforms Panel to correctly layout many items?

I've got a WinForms Panel control which holds a large number of child controls. Each child is left docked, causing the horizontal width of the contents to grow. The containing Panel has its AutoScroll property set so that you can get to all the contents.
I'm running into a problem when the total width of the contents gets too large. Once you've hit this maximum width, additional content elements are placed on top of existing contents instead of being placed to the right. But, if I resize the Panel after it has done its initial layout, it corrects itself by expanding its logical width and placing each content element in the correct location. How do I get it to layout correctly before the user resizes the window?
Here's a simple example:
Form1.vb
Public Class Form1
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
For i As Integer = 1 To 200
Dim gb As New GroupBox
gb.Text = "Box " & i.ToString
gb.Width = 250
gb.Dock = DockStyle.Left
Panel1.Controls.Add(gb)
gb.BringToFront()
Next
End Sub
End Class
Form1.Designer.vb
Partial Class Form1
Inherits System.Windows.Forms.Form
Private Sub InitializeComponent()
Me.Panel1 = New System.Windows.Forms.Panel()
Me.SuspendLayout()
'
'Panel1
'
Me.Panel1.AutoScroll = True
Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill
Me.Panel1.Location = New System.Drawing.Point(0, 0)
Me.Panel1.Name = "Panel1"
Me.Panel1.Size = New System.Drawing.Size(284, 262)
Me.Panel1.TabIndex = 0
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(284, 262)
Me.Controls.Add(Me.Panel1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
Friend WithEvents Panel1 As System.Windows.Forms.Panel
End Class
This is what the window looks like when it first comes up, scrolled nearly to the end so you can see the problem area. Notice that Box 183 to 199 are missing because they are placed on top of each other. This is not right.
This is what the window looks like after you manually resize it, scrolled nearly to the end. The panel fixed itself in response to the resize; the total logical width of the panel was automatically extended enough to hold all the contents. This is what I want it to look like when it first comes up.
I've tried manually setting the location of each box, and I've tried calling PerformLayout() and several other functions. Nothing seems to work. So far I haven't found the magic combination to get the good layout. Does anyone know how to fix this?
Edit:
Here's a screenshot that might make the issue more obvious. I adjusted the box widths and the number of boxes to show the problem better. See how the last box overlaps box 656? Every box from 657 to 700 has the same incorrect location. Turning off docking and setting the location myself doesn't help.
Looks like a bug with the scrolling information. If you call PerformLayout when the Panel is scrolled all the way to the right, it correctly places the controls in the proper place. That requires some code in the OnShown method:
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
Panel1.AutoScroll = True
Panel1.SuspendLayout()
For i As Integer = 1 To 200
Dim gb As New GroupBox
gb.Text = "Box " & i.ToString
gb.Width = 250
gb.Dock = DockStyle.Left
Panel1.Controls.Add(gb)
gb.BringToFront()
Next
Panel1.ResumeLayout(False)
End Sub
Protected Overrides Sub OnShown(e As EventArgs)
MyBase.OnShown(e)
Panel1.AutoScrollPosition = New Point(Panel1.HorizontalScroll.Maximum - _
Panel1.HorizontalScroll.LargeChange, 0)
Panel1.PerformLayout()
Panel1.AutoScrollPosition = Point.Empty
End Sub
Of course, having over 200 container controls on the form is never recommended.
AutoScroll is not AutoPositionMyChildren. From MSDN:
When adding controls programmatically to a form, use the AutoScrollPosition property to position the control either inside or outside of the current viewable scroll area.
If you looped thru the controls, to print their location, you's see at some point (probably around 130) that Location.Y becomes fixed at 32767 probably some default unscrolled max. This is also the point they start stacking because they in fact have the same initial location. Some of the code you have makes up for that but it isnt quite right. Once you scroll it, the panel fixes the coords on the child controls.
First, I would suggest that you set Panel1.AutoScrollMinSize to something like {480, 0} so that the HScroll bar appears at design time; this allows you to calc a good height for the boxes which wont cause a VScroll as you add controls.
Dim gb As GroupBox
' only 150 because problem is when (i * width) > 32k
For i As Integer = 0 To 150
gb = New GroupBox
gb.Name = i.ToString ' added
gb.Text = "Box " & i.ToString
gb.Width = 250
' no docking so set the height
gb.Height = Panel1.Bounds.Height - 30 ' trying to avoid the VSCroll
' set location explicitly
gb.Location = NewCtlLocation(Panel1.Controls.Count,
Panel1.AutoScrollPosition.X)
' Dock and Anchor mess up the AutoScroll
'gb.Dock = DockStyle.Left
Panel1.Controls.Add(gb)
' allow panel to update its scroll positions
Panel1.ScrollControlIntoView(gb)
' not needed; seems to offset something with Dock
' changing ZOrder may not always be desirable
'gb.BringToFront()
' debug illumination
Console.WriteLine("{0} {1} {2}", i.ToString,
Panel1.AutoScrollPosition.X.ToString,
gb.Location.X.ToString)
Next
'Go back to start
Panel1.ScrollControlIntoView(Panel1.Controls("0"))
Location helper so you can tweak gutters or margins (dock replacement):
Friend Function NewCtlLocation(ByVal n As Integer,
ByVal ScrollPosX As Integer) As Point
Const TopMargin As Integer = 5
Const LeftMargin As Integer = 5
Return New Point((n * 250) + ScrollPosX, 0)
End Function
Notes:
I have a vertical scroller which repeatedly adds up to 120 user controls which works well but it does not need/use ScrollControlIntoView and they never stack up like yours do. I suspect maybe because they are smaller. There is also at least a second or two before the next one can be added, which may matter. But, good to know.
It might be possible to use the ControlAdded event of the panel to do something, but it would likely amount to ScrollControlIntoView. Doing it once at the end only doesnt work, so using it as they are added is allowing something to get updated as you go.
With the right fiddling, you might be able to get Dock to work, but I suspect it may be part of the problem such as Height and Left set this way dont update the panel's internal scroll map.
Your boxes actually look narrower than 250 - is autosize on?
Suspend/Resume Layout hurt rather than help - they prevent the control from doing anything about the virtual area being populated. It should happen fast enough that no one will see anything. Results:
Works on My SystemTM

Picturebox location change 20 times per second not redrawing

I'm trying to make a few images do the nice slidey thingy that I've seen lots of Microsoft applications use. The one where the movement starts slow speeds up half way there and then comes to a nice slow stop in it's new location. I've got all the calculations figured out, getting and setting the picture box locations, Confirmation using console.writeline that the image locations are correct, and even a test run that works in a simplified format.
But in the full blown version It's not repainting the image. In fact, it looks like nothing has happened at all while the script is running. I've tried Me.Refresh(), Invalidate(), Timer.Enabled = True/False, and Me.Update(). None of which have worked. The last step is the most frustrating: I'm calling my SetPanelLocation() method at the end to ensure that the panel ends up in the final location regardless of if the movement worked. Nothing happens on this call either, even though immediately after this routine fails I can call the same method from another user event and it starts working again like nothing was wrong.
I'm creating my own PictureBox class called clsFeedImageBox which inherits PictureBox that includes this functionality (along with other features). Each image is only 300x225 pixels so they're not massive images that take a lot of time to redraw. Each instance of this class is in a common Forms.SplitterPanel. I use a lot of comments out of habit so i left them in here, maybe they'll add some light.
Public Class clsFeedImgBox
Inherits PictureBox
Private iRank As Integer 'rank in whatever feed this file gets put in
Private iRankTarget As Integer 'rank to move to when rank feed event starts
Private iTopStart As Integer 'starting top location before feed event
Private iTopTarget As Integer 'final Top location after feed event
Private WithEvents tMyTimer As New System.Timers.Timer
Private WithEvents oParent As FeedBase 'splitter panel, all location info comes from the parent
Public Sub New(ByRef sender As FeedBase, ByVal rank as Integer)
'set objects
oParent = sender
'set .Image property to pre-made thumbnail
Image.FromFile(ThumbPath) 'ThumbPath is a property which is set by this point (some code has been removed)
'setup initial position
setPanelLocation(rank)
'set autosize
Me.SizeMode = PictureBoxSizeMode.StretchImage
'set Image Scroll timer interval to 20 fps (1000 / 20 = 50)
tMyTimer.Interval = 50
End Sub
Public Sub scroll(ByVal newRank As Integer)
'setPanelLocation(newRank) <== this works, timed movements don't
iRankTarget = newRank
iTopStart = Me.Top
iTopTarget = oParent.ImgTop(newRank) 'gets an integer for the new Top location
tMyTimer.Start()
End Sub
Private Sub myScrollStep() Handles tMyTimer.Elapsed
'tMyTimer.Enabled = False 'this idea with the enabled = True at the end didn't work
iTickCount += 1
Dim iScrollPerc As Integer 'scroll % between Start and End * 100
iScrollPerc = oParent.ScrollStep(iTickCount, Rank) 'this part works
Console.WriteLine(strThumbName & " scrollPerc: " & iScrollPerc.ToString)
If iScrollPerc >= 100 Then
'scroll event complete
Console.WriteLine(strThumbName & " SetFinalLocation")
Me.setPanelLocation(iRankTarget) '<== This line doesn't work here, but works when called by other means
'stop Feed updates
tMyTimer.Stop()
'reset iTickCount for next movement
iTickCount = 0
Else
'scrolling still going
Dim newTop As Integer
newTop = Math.Round(iTopTarget - (((100 - iScrollPerc) * (iTopTarget - iTopStart)) / 100)) 'this part works
'Console.WriteLine(strThumbName & " TopTarget: " & newTop)
Me.Top = newTop 'Nothing happens here
End If
'Me.Left = oParent.ImgLeft
'Me.Width = oParent.ImgWidth
'Me.Height = oParent.ImgHeight 'that didn't work
'Me.Refresh() 'this didn't work
'Invalidate() 'this didn't do much good either
'Me.Update() 'Aaaaand no cigar, time for StackOverflow
'tMyTimer.Enabled = True
End Sub
Public Sub setPanelLocation(ByVal rank As Integer)
iRank = rank
Me.MyRePaint()
End Sub
Public Sub MyRePaint()
'repaint image box with everything in it's current rank
Me.Left = oParent.ImgLeft
Me.Top = oParent.ImgTop(iRank)
Me.Width = oParent.ImgWidth
Me.Height = oParent.ImgHeight
End Sub
End Class
What gives? There must be some inner workings of VB.NET that will help me figure this out. I'm using VS 2012 and Win8
You could make a WPF application and use a Slider control instead of "manually" making a slider with planes, picture boxes, etc, etc.

Dynamic PictureBox in Visual Basic

I've created a form with a PictureBox on it and would like to dynamically create another PictureBox on the form while the program runs (to the left of the static one). I've written this code:
Dim temp As PictureBox
temp = New PictureBox
temp.Image = StaticPictureBox.Image
temp.Visible = True
temp.Top = StaticPictureBox.Top
temp.Width = StaticPictureBox.Width
temp.Height = StaticPictureBox.Height
temp.Left = StaticPictureBox.Left - 20
temp.BringToFront()
When I run this code I can detect that the temp PictureBox does get created. However, it is not rendered onto the form. It seems like it's there but is invisible.
Does anyone have an idea of what I'm doing wrong?
You need to add it to the form's control collection:
Me.Controls.Add(temp)
Why don't you just remove that code and place a picturebox next to the other one and set:
newpicturebox.visible = false
Then whenever you have the action completed you have it change:
newpicturebox.visible = true
I know this is old but... you got an error here:
temp.Left = StaticPictureBox.Left - 20
should be:
temp.Left = StaticPictureBox.right + 20
or:
temp.Left = StaticPictureBox.right
hope it helped.