Update Picturebox image - vb.net

I'm using a picture box as a 'preview' screen for a webbrowser control on a another winform. It works well apart from that in order to update the picturebox control I'm finding that the code needs to run twice (double click the button) linked to the below code. Any ideas why the picturebox isn't updating in the first pass to show the newly navigated page?
Private Sub mOutput_Click(sender As Object, e As EventArgs) Handles mOutput.Click
If Not mFiles.SelectedItem Is Nothing Then
Formloading.fDisplay.WebBrowser1.Navigate(folderloc.ToString & "\" & mFiles.SelectedItem.ToString)
End If
Dim Bounds As System.Drawing.Rectangle
Dim outputscreen As System.Drawing.Bitmap
Dim graph As System.Drawing.Graphics
Dim LO As Integer = 0
With Bounds
.Height = fDisplay.WebBrowser1.Height
.Width = fDisplay.WebBrowser1.Width
.X = Formloading.fDisplay.Location.X
.Y = Formloading.fDisplay.Location.Y
.Size = Formloading.fDisplay.Size
End With
outputscreen = New System.Drawing.Bitmap(Bounds.Width, Bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb)
graph = System.Drawing.Graphics.FromImage(outputscreen)
graph.CopyFromScreen(Bounds.X, Bounds.Y, 0, 0, Bounds.Size, Drawing.CopyPixelOperation.SourceCopy)
PictureBox1.Image = outputscreen
End Sub

Related

moving many controls together to represent a Seating Chart in VB.NET

Greetings,
I want To create a graphic representation of a seating chart (could be in a wedding venue or in cars...). I used a splitted panel, in the splittedPanel1 i put the buttons to create the cars, and inside the splitted panel2 i want to put the graphic representation. Inside SplittedPanel2, I've created a panel and a pictureBox (to represent some fixed areas in the real world).
I've also created a class called SimpleCar. SimpleCar is composed of 5 TextBox (es) and a PictureBox all in a panel to represent a car: the textBoses represent the passengers names and the car label, and the pictureBox to put an image representing a car (or a table). I've also made a sub to Add dynamically a SimpleCar.
2 problems occur when i want to move this new panel (dynamically created), using MouseDown and MouseUp events:
- first pb: while moving the existing panel, the screen flashes and the movement is not smooth
- second pb: i can't move a panel dynamically created
Note that moving a PictureBox by this code is very smooth but moving a panel is not user friendly.
I expect moving a dynamically created a panel smoothly, or should I reconsider displaying the cars in another way than in a panel?
Knowing that the final purpose of the code is to export a picture of all the created tables in the venue. I also tested the code with a groupBox and the results aren't good.
The simpleCar class is described in the code below:
Class SimpleCar
Public carNameBox, passengerNameBox1, passengerNameBox2,
passengerNameBox3, passengerNameBox4 As TextBox
Public carPictureBox As PictureBox
Public carGroup As Panel
Public Sub New()
carGroup = New Panel
carNameBox = New TextBox With {.Text = "carNmBx",
.BackColor = Color.Yellow,
.Name = "carNmBx"}
passengerNameBox1 = New TextBox With {.Text = "txtPassNmBx1",
.BackColor = Color.BlanchedAlmond,
.Name = "TextBox1"}
passengerNameBox2 = New TextBox With {.Text = "txtPassNmBx2",
.BackColor = Color.AliceBlue,
.Name = "TextBox2"}
passengerNameBox3 = New TextBox With {.Text = "txtPassNmBx3",
.BackColor = Color.Azure,
.Name = "TextBox3"}
passengerNameBox4 = New TextBox With {.Text = "txtPassNmBx4",
.BackColor = Color.Cyan,
.Name = "TextBox4"}
carPictureBox = New PictureBox With {.Text = "picBx1",
.BackColor = Color.BlanchedAlmond,
.Name = "picBox1"}
Dim fdialog As New OpenFileDialog()
fdialog.FileName = String.Empty
fdialog.Multiselect = True
If fdialog.ShowDialog = DialogResult.OK Then
If fdialog.FileNames.Length = 2 Then
carPictureBox.Image = Image.FromFile(fdialog.FileNames(0))
ElseIf fdialog.FileNames.Length = 1 Then
carPictureBox.Image = Image.FromFile(fdialog.FileName)
End If
End If
carGroup.Controls.Add(carPictureBox)
carGroup.Controls.Add(carNameBox)
carGroup.Controls.Add(passengerNameBox1)
carGroup.Controls.Add(passengerNameBox2)
carGroup.Controls.Add(passengerNameBox3)
carGroup.Controls.Add(passengerNameBox4)
End Sub
End Class
To Add dynamically a SimpleCar in the code below:
Public Sub Add_car()
Dim carType As SimpleCar
carType = New SimpleCar
Dim carPs1 = carType.passengerNameBox1
Dim carPs2 = carType.passengerNameBox2
Dim carPs3 = carType.passengerNameBox3
Dim carPs4 = carType.passengerNameBox4
Dim carNm = carType.carNameBox
Dim carPic = carType.carPictureBox
Dim carGroupBox = carType.carGroup
SplitContainer1.Panel2.Controls.Add(carGroupBox)
End Sub
So the problem occurs when i use this code to move a panel (if you replace PictureBox by Panel, even GroupBox) (it worked fine when I wanted to move one control: PictureBox1 in this sample):
'Drag To move PictureBox1 along with mouse-------------------------------------------
Dim oldX As Short
Dim oldY As Short
Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseDown
Dim X As Single = e.X
Dim Y As Single = e.Y
PictureBox1.Cursor = Cursors.SizeAll
oldX = CShort(X)
oldY = CShort(Y)
End Sub
Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseUp
Dim X As Single = e.X
Dim Y As Single = e.Y
PictureBox1.Cursor = Cursors.Default
End Sub
' to limit the movement within the app----------------------------------
Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseMove
If e.Button = MouseButtons.Left Then
Dim ProposedLocation As New Point(PictureBox1.Left - (oldX - e.X), PictureBox1.Top - (oldY - e.Y))
PictureBox1.Left = CInt(IIf(ProposedLocation.X < 0, 0, IIf(ProposedLocation.X > SplitContainer1.Panel2.Width - PictureBox1.Width, SplitContainer1.Panel2.Width - PictureBox1.Width, ProposedLocation.X)))
PictureBox1.Top = CInt(IIf(ProposedLocation.Y < 0, 0, IIf(ProposedLocation.Y > SplitContainer1.Panel2.Height - PictureBox1.Height, SplitContainer1.Panel2.Height - PictureBox1.Height, ProposedLocation.Y)))
End If
End Sub

Saving the image of a picturebox

So I have this code:
Private Sub button28_Click(sender As Object, e As EventArgs) Handles button28.Click
Dim bounds As Rectangle
Dim screenshot As System.Drawing.Bitmap
Dim graph As Graphics
bounds = PicOuterBorder.Bounds
screenshot = New System.Drawing.Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
picFinal.Image = screenshot
'this takes a screenshot
End Sub
PicOuterBorder is a picturebox on my form. PicFinal is another display picturebox. But this code gets me this: Which is basically a screenshot of a window in the size of PicOuterBorder starting from the origin of my screen. However, Me.Bounds instead of PicOuterBorder.Bounds works and gets a perefect screenshot of just my form. I want picFinal to have a screenshot of just PicOuterBorder
Try below code. You have to map the control coordinates to screen coordinates using PointToScreen. I have placed PicOuterBorder inside the panel PanelPicture. PanelPicture is without any border, while PicOuterBorder can have any type of border style. Below code takes the snapshot of the panel.
Private Sub button28_Click(sender As Object, e As EventArgs) Handles button28.Click
Dim graph As Graphics = Nothing
Dim bounds As Rectangle = Nothing
Dim screenshot As System.Drawing.Bitmap
Dim location As Drawing.Point = PanelPicture.PointToScreen(Drawing.Point.Empty)
screenshot = New System.Drawing.Bitmap(PanelPicture.Width, PanelPicture.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(location.X, location.Y, 0, 0, PanelPicture.Size, CopyPixelOperation.SourceCopy)
picFinal.Image = screenshot
graph.Dispose()
End Sub
Adapt your code for something like this:
Public Sub SaveImage(filename As String, image As Image, Encoder As ImageCodecInfo, EncParam As EncoderParameter)
Dim path As String = System.IO.Path.Combine(My.Application.Info.DirectoryPath, filename & ".jpg")
Dim mySource As New Bitmap(image.Width, image.Height)
Dim grfx As Graphics = Graphics.FromImage(mySource)
grfx.DrawImageUnscaled(image, Point.Empty)
grfx.Dispose()
mySource.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg)
mySource.Dispose()
End Sub

My code only works when I insert a random MsgBox

I've encountered a very bizarre problem when trying to get a screenshot of a TableLayoutPanel in my form.
I have this code (taken from another question (How to get a screenshot, only for a picturebox); code courtesy of user "Chase Rocker"):
Dim s As Size = TableLayoutPanel1.Size
Dim memoryImage = New Bitmap(s.Width, s.Height)
Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
Dim ScreenPos As Point = Me.TableLayoutPanel1.PointToScreen(New Point(0, 0))
memoryGraphics.CopyFromScreen(ScreenPos.X, ScreenPos.Y, 0, 0, s)
Form3.PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
Form3.PictureBox1.BringToFront()
Form3.PictureBox1.Image = memoryImage
Now, here comes my problem. This code gives me a blank picture. It takes the screenshot apparently, but all I can see is white. Now, I was trying to see if the size was correct, so I was messing with MsgBox. I add this line to the code:
MsgBox("Random Message")
Getting
Dim s As Size = TableLayoutPanel1.Size
MsgBox("Random Message")
Dim memoryImage = New Bitmap(s.Width, s.Height)
Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
Dim ScreenPos As Point = Me.TableLayoutPanel1.PointToScreen(New Point(0, 0))
memoryGraphics.CopyFromScreen(ScreenPos.X, ScreenPos.Y, 0, 0, s)
Form3.PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize
Form3.PictureBox1.BringToFront()
Form3.PictureBox1.Image = memoryImage
By some reason I don't know, the screenshot now works. I don't see white anymore, but the actual screenshot of the TableLayoutPanel. For me is very weird that the code only works with a MsgBox. Maybe I'm missing something. Does anyone know why this happens? Thank you!
How about if you try to make the TableLayoutPanel draw itself to a bitmap instead? This can be done using the Control.DrawToBitmap() method.
Dim s As Size = TableLayoutPanel1.Size
Dim memoryImage As New Bitmap(s.Width, s.Height)
TableLayoutPanel1.DrawToBitmap(memoryImage, New Rectangle(New Point(0, 0), s))
Form3.PictureBox1.Image = memoryImage
If the TableLayoutPanel fill happens in the same event handler where you grab the image then Windows has not draw the UI for the elements added to the TableLayoutPanel. Only when you exit from the event handler, the winforms engine has the opportunity to draw everything.
Adding a MessageBox changes everything because calling Show (a modal call that interrupts your code and pass control back to window) allows the Winform engine to draw the pending updates and your code works.
You can add a Timer control and put the code that execute the ScreenShoot in the Timer event.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
......
' code that fills the TableLayoutPanel
......
Dim tim1 = new System.Windows.Forms.Timer()
tim1.Interval = 1
AddHandler tim1.Tick, AddressOf tim1Ticked
tim1.Start()
End Sub
Private Sub tim1Ticked(sender As Object, e As EventArgs)
......
' Code that execute the screenshoot.
......
Dim t = DirectCast(sender, System.Windows.Forms.Timer)
t.Stop()
End Sub

Supressing a form with button while taking a screenshot on VB.net

I am new to VB.net and I am trying to create a screenshot capture on button click application using VB.net.
When I am trying to take a screenshot using a button click on a form in VB.net, the form is appearing in the screenshot. When I tried to hide the form using the me.hide or Me.visible=false or me.sendtoback, the form is still appearing in the screenshot. The best part is sendtoback is working in one system, but not properly in another.
Below is the code for button click
count is global integer with value 1 initialized at beginning
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
clickpicfull()
'PictureBox1.Image.Save("C:\Users\Bulusu\Desktop\Screenshots\" & count & ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
PictureBox1.Image.Save(picspath & "\" & count & ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg)
count = count + 1
Me.Controls("label1").Text = "No of Screenshots: " & count - 1
' MsgBox(count)
End Sub
and below is the code for taking the screenshot
Public Sub clickpicfull()
If count = 1 Then
Me.Size = New System.Drawing.Size(438, 300)
End If
Me.SendToBack()
Me.Hide()
Me.Opacity = 0
Form2.Hide()
Dim area As Rectangle
Dim capture As System.Drawing.Bitmap
Dim graph As Graphics
area = Screen.PrimaryScreen.Bounds
capture = New System.Drawing.Bitmap(area.Width, area.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(capture)
graph.CopyFromScreen(area.X, area.Y, 0, 0, area.Size, CopyPixelOperation.SourceCopy)
PictureBox1.Image = capture
Me.Opacity = 100
Me.Show()
Me.BringToFront()
End Sub
Thanks to #HansPassant by changing the opacity values as below gave me the desired result
Putting default opacity of the form to 99 in the designer and swapping
the opacity between 0 and 0.99 using the below
Me.Opacity = 0 and Me.Opacity = 0.99
`Public Sub clickpicfull()
' Me.Hide() 'solution 1
'Thread.Sleep(500) 'solution 1
Me.Opacity = 0 'solution 2
Form2.Hide()
Dim area As Rectangle
Dim capture As System.Drawing.Bitmap
Dim graph As Graphics
area = Screen.PrimaryScreen.Bounds
capture = New System.Drawing.Bitmap(area.Width, area.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(capture)
graph.CopyFromScreen(area.X, area.Y, 0, 0, area.Size, CopyPixelOperation.SourceCopy)
PictureBox1.Image = capture
Me.Opacity = 0.99 'solution 2
'Me.Show() 'solution 1
End Sub`
You need to let the system handle the events. When you call most of the methods on the Window class, you might want to wait for things to settle down. Try adding the delay using Application.DoEvents (be sure to read the documentation for any issues that may happen such as unintended event handlers getting called). Also, opacity should range from 0.0 to 1.0. 100% opaque is set as 1.0.
Public Sub clickpicfull()
If count = 1 Then
Me.Size = New System.Drawing.Size(438, 300)
End If
Me.SendToBack()
Me.Hide()
Me.Opacity = 0
Form2.Hide()
Application.DoEvents()
Dim area As Rectangle
Dim capture As System.Drawing.Bitmap
Dim graph As Graphics
area = Screen.PrimaryScreen.Bounds
capture = New System.Drawing.Bitmap(area.Width, area.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(capture)
graph.CopyFromScreen(area.X, area.Y, 0, 0, area.Size, CopyPixelOperation.SourceCopy)
PictureBox1.Image = capture
Me.Opacity = 1.0
Me.Show()
Me.BringToFront()
End Sub

Delete specific files from computer knowing the path

I'm using a timer to take screen captures after an amount of time and save the images to a specific path.
Private Sub tmrPS1_Tick(sender As Object, e As EventArgs) Handles tmrPS1.Tick
Dim bounds As Rectangle
Dim screenshot As System.Drawing.Bitmap
Dim graph As Graphics
bounds = Screen.PrimaryScreen.Bounds
screenshot = New System.Drawing.Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
PictureBox1.Image = screenshot
PictureBox1.Image.Save("C:\ImagesFolder\1.jpg")
tmrPS1.Enabled = False
End Sub
And I want another timer to delete them after I sent them with mail because I will have to take new ones. My question is how do I delete the images knowing the path?
Delete/recreate the folder when you are done with it?
If IO.Directory.Exists(DestinationFolder) Then IO.Directory.Delete(DestinationFolder, True)
Application.DoEvents()
IO.Directory.CreateDirectory(DestinationFolder)
This code cleans up files in "Temp" with the same extension as the file I'm saving.
With My.Computer.FileSystem
Dim s As String = Environ("temp")
For Each foundFile As String In .GetFiles(s, FileIO.SearchOption.SearchTopLevelOnly, "*.tmp.kml")
.DeleteFile(foundFile) ' clean up old output
Next
End With