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
Related
I want a webbrowser control on the background and a picturebox above it where I can draw and then it will appear above the webbrowser control. It's like I am writing on some paper which already has something written on it. I have placed a webbrowser control and a picture box above it both with same dimensions.
I know similar question has been asked a lot of time on this website in different forms but none of the solutions mentioned are working for me.
The solutions mentioned are usually for picturebox over picturebox not picturebox over webbrowser control. simply putting webbrowser control instead of picture does not work. Here is the code I used. The square that should have been formed was not formed.
Public Class Form1
Dim BMP As New Drawing.Bitmap(640, 480)
Dim GFX As Graphics = Graphics.FromImage(BMP)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
PictureBox1.Controls.Add(WebBrowser1)
PictureBox1.Location = New Point(0, 0)
PictureBox1.BackColor = Color.Transparent
Dim blackPen As New Pen(Color.Black, 3)
Dim point1 As New Point(100, 100)
Dim point2 As New Point(100, 200)
Dim point3 As New Point(200, 200)
Dim point4 As New Point(200, 100)
Dim curvePoints As Point() = {point1, point2, point3, point4}
GFX.FillRectangle(Brushes.White, 0, 0, PictureBox1.Width, PictureBox1.Height)
GFX.DrawPolygon(blackPen, curvePoints)
PictureBox1.Image = BMP
End Sub
End Class
It did not work the other way around either, I mean drawing first and than making the picturebox transparent.
I am using a code that creates an image tooltip when the user hovers over the button. However, for some reason, for some of the buttons, the image gets scaled larger and doesnt completely fit in the tooltip window. I have no idea why some images are getting scaled and not others. Here is the code:
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
ToolTip1.OwnerDraw = True
For Each ctrl As Control In Controls
If TypeOf ctrl Is Button Then
ToolTip1.SetToolTip(ctrl, " ")
End If
Next
End Sub
Private Sub ToolTip1_Popup(sender As Object, e As PopupEventArgs) Handles ToolTip1.Popup
Dim oTemplate As String = e.AssociatedControl.Name
Dim ButtonPic As Image = Image.FromFile(System.IO.Path.GetFullPath("TemplatesResources\MouseHoverPics\" & oTemplate & ".png"))
e.ToolTipSize = New Size(ButtonPic.Size.Width, ButtonPic.Size.Height)
End Sub
Private Sub ToolTip1_Draw(sender As Object, e As DrawToolTipEventArgs) Handles ToolTip1.Draw
Dim oTemplate As String = e.AssociatedControl.Name
Dim ButtonPic As Image = Image.FromFile(System.IO.Path.GetFullPath("TemplatesResources\MouseHoverPics\" & oTemplate & ".png"))
e.Graphics.Clear(SystemColors.Info)
e.Graphics.DrawImage(ButtonPic, New System.Drawing.Point(0, 0))
End Sub
The results:
Looking good at first.
Scaling begins....
Even more scaling the further right I go... could it possibly have to do with the button placement? I cant see why the code would take that into consideration
Any help would be appreciated.
That happens because when you call
e.ToolTipSize = New Size(ButtonPic.Size.Width, ButtonPic.Size.Height)
you set [size of the popup = size of the image]. But what happens if you don't have enough space between your mouse cursor and the border of the window? The popup resize itself, and when you load the image inside of it, the image scale itself to match the current width/height
e.Bounds()
So all you have to do is to check the Bounds of the popup and scale manteining the ratio before call DrawImage() method.
Here's and example
Private Sub ToolTip1_Draw(sender As Object, e As DrawToolTipEventArgs) Handles ToolTip1.Draw
Dim oTemplate As String = e.AssociatedControl.Name
Dim ButtonPic As Image = Image.FromFile(System.IO.Path.GetFullPath("TemplatesResources\MouseHoverPics\" & oTemplate & ".png"))
e.Graphics.Clear(SystemColors.Info)
If ButtonPic.Width > e.Bounds.Widht Or ButtonPic.Height > e.Bounds.Height Then
[code to rescale, make it as you prefer]
End If
e.Graphics.DrawImage(ButtonPic, New System.Drawing.Point(0, 0))
End Sub
I have added some richtextboxes and some picture boxes in a panel control with scrolling option enabled. I want to capture image of Panel control along with all its child controls. I tried various solutions available on net but still not able to find perfect solution to do my job. The best one available (which dose not capture what is off the scroll bars) is given below. Please help me to do this.
Dim bmp As New Bitmap(Panel1.Width, Panel1.Height)
Using gr As Graphics = Graphics.FromImage(bmp)
gr.CopyFromScreen(Panel1.PointToScreen(Point.Empty), Point.Empty, Panel1.Size)
End Using
Private Function TakeScreenShot(ByVal Control As Control) As Bitmap
Dim tmpImg As New Bitmap(Control.Width, Control.Height)
Using g As Graphics = Graphics.FromImage(tmpImg)
G.CopyFromScreen(Panel1.PointToScreen(New Point(0, 0)), New Point(0, 0), New Size(Panel1.Width, Panel1.Height))
End Using
Return tmpImg
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TakeScreenShot(Panel1).Save("D:\Screenshot.png", System.Drawing.Imaging.ImageFormat.Png)
End Sub
I am making a program that constantly sends the key "{PRTSC}" and then sets PictureBox1.BackgroundImage = My.Computer.Clipboard.GetImage.
At first it works fine but after a min or two the picturebox goes blank and no error is given.
My code is:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If Not My.Computer.Clipboard.ContainsImage Then
SendKeys.Send("{PRTSC}")
Else
PictureBox1.BackgroundImage = My.Computer.Clipboard.GetImage
My.Computer.Clipboard.Clear()
End If
End Sub
I have tried:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
'SendKeys.Send("{PRTSC}")
'If My.Computer.Clipboard.ContainsImage Then PictureBox1.BackgroundImage = My.Computer.Clipboard.GetImage
Dim bounds As New 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.Format32bppRgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(0, 0, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
PictureBox1.BackgroundImage = screenshot
graph.Dispose()
'screenshot.Save("d:\\dcap.jpg", Imaging.ImageFormat.Bmp)
End Sub
But attempting to dispose the screenshot yields an instant error. I don't know why.
{PRTSC} grabs the active window, when it has focus, and the screen otherwise.
It's a good idea to disable the timer at the beginning of the tick event, and start it at the end. This prevents re-entry, and, depending on the type of timer (there is the timer control, system.timers.timer, and system.threading.timer, each of which is a little different), you may be required to restart the timer each tick event.
It's normal to assign an image to a picturebox image instead of the backgroundimage. If something in the application is assigning a bitmap to picturebox1.image or blanking picturebox1.image, it will overwrite the screen shot in picturebox1.backgroundimage.
Hi again my question this time its related with this piece of code, im using the visual studio beta 2012, i cant seem to find the issue, if you guys could help me out ill appreciate it
Public Class Form1
Private Sub fullScreen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles fullScreen.Click
SendKeys.SendWait("^{PRTSC}")
Dim clip As IDataObject = Clipboard.GetDataObject()
If clip.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
Dim screenCapture As Bitmap = CType(clip.GetData(GetType(System.Drawing.Bitmap)), Bitmap)
screenCapture.Save("C:\fullScreenCapture.bmp")
End If
Clipboard.Clear()
End Sub
End Class
Error :
A first chance exception of type 'System.Runtime.InteropServices.ExternalException' occurred in System.Drawing.dll
Additional information: Error genérico en GDI+.
If there is a handler for this exception, the program may be safely continued.
You can take a screen shot more easily by using the following (send keys is always hit and miss in my experience)
Private Function TakeScreenShot() As Bitmap
Dim scrn As Screen = Screen.FromControl(Me)
Dim screenSize As Size = New Size(scrn.Bounds.Width, scrn.Bounds.Height)
Dim screenGrab As New Bitmap(screenSize.Width, screenSize.Height)
Dim g As Graphics = Graphics.FromImage(screenGrab)
g.CopyFromScreen(New Point(scrn.Bounds.X, scrn.Bounds.Y), New Point(0, 0), screenSize)
Return screenGrab
End Function
Are you trying to capture the screen? Why not use VS' classes to capture the screen?
http://forum.codecall.net/topic/51761-creating-a-screen-shot-tool-vbnet