I want to render a PDF page in a control in winforms and then move rectangles around over the PDF to identify user selected text strings. I'm trying to render the PDF using a WebBrowser control but WebBrowser doesn't seem to support GDI.
Can anyone suggest a better way of rendering the PDF so that I can move rectangles around on it.
If you want to continue using the WebBrowser Control you can use a transparent form that moves and resizes with the underlying form.
Create your mainform Form1 and add a Webbrowsercontrol to it. For this example set .Dock to All.
Add a second form, Form2 with nothing on it.
In Form1 you show Form2 and move it if the Form moves or resizes.
Public Class Form1
Private Sub MoveForm2()
Dim crpos As Point = Me.PointToClient(Me.DesktopLocation)
With Form2
.DesktopLocation = New Point(Me.DesktopLocation.X - crpos.X, Me.DesktopLocation.Y - crpos.Y)
.WindowState = Me.WindowState
.Size = Me.ClientSize
End With
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebBrowser1.Navigate("www.google.com")
MoveForm2()
Form2.Show(Me)
End Sub
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
MoveForm2()
End Sub
Private Sub Form1_Move(sender As Object, e As EventArgs) Handles MyBase.Move
MoveForm2()
End Sub
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
MoveForm2()
End Sub
End Class
In Form2 you use an API call to let you click through Form2 (ripped from VB.net Click through form ).
Here you also draw directly onto the form. Use TransparencyKey and BackColor to make it transparent.
Imports System.Runtime.InteropServices
Public Class Form2
<DllImport("user32.dll", EntryPoint:="GetWindowLong")> Public Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function
<DllImport("user32.dll", EntryPoint:="SetWindowLong")> Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
End Function
Private Sub Form2_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
'Draw rectangles here
Using g As Graphics = Me.CreateGraphics
g.DrawRectangle(Pens.Red, 100, 100, 100, 100)
End Using
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.BackColor = Color.Pink
Me.TransparencyKey = Color.Pink
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Dim InitialStyle As Integer
InitialStyle = GetWindowLong(Me.Handle, -20)
SetWindowLong(Me.Handle, -20, InitialStyle Or &H80000 Or &H20) 'Makes the window "click-throughable"
End Sub
End Class
This is a rather dirty hack of course but if you just want to move the rectangles yourself it should work quite well. You have to adapt this example to your needs of course.
This solution may work in the following 2 scenarios:
1- If you are generating the PDF file yourself and you are willing to switch over to PDFSharp for generating the file.
2- If you are not generating input files but you are ok with displaying a modified version that contains the rectangles that you want to be displayed.
I use PDFsharp. Is a open source .NET library for processing PDF
http://www.pdfsharp.com/PDFsharp/
Added:
Graphics
The graphical objects follow the design pattern of the .Net framework. With one set of functions you can draw on a PDF page as well as on a System.Drawing.Graphics object. Your application can render its output in a window, on the printer or in a PDF document.
Lines, polylines, arcs, Bézier splines, canonical splines
Rectangles, rounded rectangles, ellipses, polygons, pies, closed splines, paths
PDFsharp is the Open Source library that easily creates PDF documents from any .NET language.
The same drawing routines can be used to create PDF documents, draw on the screen, or send output to any printer.
PDFsharp Highlights
Creates PDF documents on the fly from any .Net language
Easy to understand object model to compose documents
One source code for drawing on a PDF page as well as in a window or on the printer
Modify, merge, and split existing PDF files
Images with transparency (color mask, monochrome mask, alpha mask)
Newly designed from scratch and written entirely in C#
PDFsharp Features
Key Features
Creates PDF documents on the fly from any .Net language
Easy to understand object model to compose documents
One source code for drawing on a PDF page as well as in a window or on the printer
Modify, merge, and split existing PDF files
Images with transparency (color mask, monochrome mask, alpha mask)
Newly designed from scratch and written entirely in C#
The graphical classes go well with .Net
Can use either GDI+ or WPF
Related
Okay, so I am trying to make a program that each time you click (doesn't matter where) a random colored, and sized circle appears where you happened to click. however, the only way I can add a shape is via Paint event. here is the code I have now:
Private Sub Form1_Paint(ByVal Sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Using Brush1 As New SolidBrush(Color.Orange)
e.Graphics.FillEllipse(Brush1, MousePosition.X, MousePosition.Y, 100, 100)
End Using
End Sub
I need to know a line of code that I can use in a mouse click event, that will re-run this sub. I know how to change the size, and make it random, I just don't know how to run this sub multiple times, more precisely; run this sub once after each mouse click. If someone can help, I would appreciate it!
Just as Plutonix explained, a refresh is handled by calling the Invalidate method.
The thing you need to remember is that whatever is painted on a surface is not persistent, so you need to redraw the whole screen every time. There are, of course, many ways in which this can be optimized for performance purposes, as this process can be extremely CPU intensive; specially, since GDI+ is not hardware accelerated.
So, what you need to do is:
Record every click (x, y position) and store it
Since the radius of each circle is random, determine the radius when the user clicks the form, then store it along with the x, y position of the click
Then, have the Paint event re-draw each stored sequence of clicks (with their respective radii) and re-draw each circle over and over.
Here's an implementation that will do the trick. Just paste this code inside any Form's class to test it:
Private Class Circle
Public ReadOnly Property Center As Point
Public ReadOnly Property Radius As Integer
Public Sub New(center As Point, radius As Integer)
Me.Center = center
Me.Radius = radius
End Sub
End Class
Private circles As New List(Of Circle)
Private radiusRandomizer As New Random()
Private Sub FormLoad(sender As Object, e As EventArgs) Handles MyBase.Load
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True) ' Not really necessary in this app...
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.ResizeRedraw, True)
Me.SetStyle(ControlStyles.UserPaint, True)
End Sub
Private Sub FormMouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
circles.Add(New Circle(New Point(e.X, e.Y), radiusRandomizer.Next(10, 100)))
Me.Invalidate()
End Sub
Private Sub FormPaint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim g As Graphics = e.Graphics
g.Clear(Color.Black)
Using p As New Pen(Color.White)
For Each c In circles
g.DrawEllipse(p, c.Center.X - c.Radius \ 2, c.Center.Y - c.Radius \ 2, c.Radius, c.Radius)
Next
End Using
End Sub
Here's what you'll get after a few clicks on the form
I'm using a web-browser to load up images from the web automatically in a VB.Net forms applications, however, there is a white background where the image doesn't fill the whole of the navigator object on the form.
How can I go about setting a transparent background for the web browser object in my application?
Thanks,
C.
Set the form's transparency key to white.
The color you choose as the transparency key is transparent-ed out. Anything on the entire form with that color is turned into transparent. As the browser's background is of white color, a white transparency key will make it transparent, you can use Windows Aero Glass DWM effect for a glassy transparency but it would only work on Windows Vista onwards, for previous version of Windows, you'll have to paint it manually which is a long job to do. The simplest and the most quickest thing for you is to set the Transparency Key to White :)
Me.TransparencyKey = Color.White
If you want to use Aero Glass DWM, use the code below:
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
Private mExtendedFrameMargins As MARGINS
Protected Overrides Sub _
OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
'use either one
e.Graphics.SmoothingMode = SmoothingMode.HighQuality
End Sub
Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
If IsGlassEnabled() Then
'You should paint the extended frame black for proper composition, but I'm painting it white as you need it
e.Graphics.FillRectangle(Brushes.White, 0, 0, Me.ClientRectangle.Width, mExtendedFrameMargins.cyTopHeight)
End If
End Sub
Private Function IsGlassEnabled() As Boolean
If Environment.OSVersion.Version.Major < 6 Then
Return False
End If
Dim isGlassSupported As Boolean = False
DwmIsCompositionEnabled(isGlassSupported)
Return isGlassSupported
End Function
<DllImport("dwmapi.dll")> _
Private Shared Function DwmIsCompositionEnabled(<MarshalAs(UnmanagedType.Bool)> ByRef pfEnabled As Boolean) As Integer
End Function
<DllImport("dwmapi.dll")> _
Private Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef pMarInset As MARGINS) As Integer
End Function
<StructLayout(LayoutKind.Sequential)> _
Private Structure MARGINS
Public cxLeftWidth As Integer
Public cxRightWidth As Integer
Public cyTopHeight As Integer
Public cyBottomHeight As Integer
End Structure
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If IsGlassEnabled() Then
mExtendedFrameMargins = New MARGINS
mExtendedFrameMargins.cyTopHeight = Me.Height 'type height here, this is going to be a number (integer)
DwmExtendFrameIntoClientArea(Me.Handle, mExtendedFrameMargins)
End If
End Sub
I've used this code in an app that I'm creating
well guys i want to know is there any way i can zoom my form in vb.net.
i could resize the form and byanchoring all controls to left top right bottom i can make it look like zoom. but it is not actually zooming. it is resizing. while font size and other formats are still as same.
also see if anyone can answer my another question..
https://stackoverflow.com/questions/9749877/need-help-doesnt-printform-work-well-on-painted-objects-or-forms
No, there is no easy way to zoom like this as far as I know. Fonts in particular have a fixed aspect so you cannot easily make them taller or wider than normal if you are re-sizing your form arbitrarily.
You can force the resize to maintain its aspect ratio, however, and then you could recursively go through all of your controls, identify their types, and scale them appropriately in the Resize event of the form - ie:
Public Class Form1
Private lblSize As Single
Private Fwid As Integer
Private Fheight As Integer
Private Sub Form1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize
Me.Height = Fheight * Me.Width / Fwid
For Each ctl In Me.Controls
If TypeOf ctl Is Label Then
Dim lbl As Label = DirectCast(ctl, Label)
Dim nFont As New Font(FontFamily.GenericSansSerif, lblSize * Me.Width / Fwid, FontStyle.Regular, GraphicsUnit.Point)
lbl.Font = nFont
End If
Next
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Fwid = Me.Width
Fheight = Me.Height
lblSize = Label1.Font.Size
End Sub
End Class
You would have to do this for every control type you use. I only did font size here but you would have to scale the position, etc, as well. The redraw on this will not be pretty but it would work. A better alternative might be to go with WPF, which has more tools available to do this sort of thing.
Also, if you have controls within controls (tab pages, groupboxes, etc) you have to use recursion to find them all - something like :
Public Shared Function GetAllControlsRecurs(ByVal list As List(Of Control), ByVal parent As Control, ByVal ctrlType As System.Type) As List(Of Control)
If Parent Is Nothing Then Return list
If Parent.GetType Is ctrlType Then
list.Add(Parent)
End If
For Each child As Control In Parent.Controls
GetAllControlsRecurs(list, child, ctrlType)
Next
Return list
End Function
where you would use the above function like :
Dim buttonList As New List(Of Control)
Dim checkboxList As New List(Of Control)
'etc...
For Each ctl As Button In GetAllControlsRecurs(buttonList, Me, GetType(Button))
' Do something...
Next
For Each ctl As CheckBox In GetAllControlsRecurs(checkboxList, Me, GetType(CheckBox))
' Do Something...
Next
Also - accepting answers will probably encourage people to help you.
I looked at "How do I place an image with a mouse-click in Javascript?" but it had a small snippet of Java; immensely larger than my knowledge of Java. And that is the closest I've come to finding an answer in the past week.
Here's what I would like to do (don't know if its even possible):
I have a panel and a toolstrip with 3 buttons. Each button represents a different image. I want to click on a button (once) and then move into the panel and everytime I click the mouse button it drops the image where ever I clicked. This only ends when either I click back on the same button or one of the other buttons. I do not want to drag an image into the panel each time. In other words the button stays depressed and the event/action stays active.
Any help would be greatly appreciated.
Here is an example application. It's just a form with a ToolStrip on it, along with a couple of buttons with an image added to each button. The key property for each button is CheckOnClick=True, which will keep the button pressed down.
There isn't a radio button like feature for ToolStrips, so you have to "uncheck" the other ToolStripButtons yourself, which I have handled in the ItemClicked event.
Public Class Form1
Private _ActiveImage As Image = Nothing
Private Class ImagePoint
Public Location As Point
Public Image As Image
Public Sub New(ByVal image As Image, ByVal location As Point)
Me.Image = image
Me.Location = location
End Sub
End Class
Private _Images As New List(Of ImagePoint)
Public Sub New()
InitializeComponent()
Me.DoubleBuffered = True
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
For Each imageItem As ImagePoint In _Images
e.Graphics.DrawImage(imageItem.Image, imageItem.Location)
Next
End Sub
Private Sub ToolStrip1_ItemClicked(ByVal sender As Object, ByVal e As ToolStripItemClickedEventArgs) Handles ToolStrip1.ItemClicked
For Each toolButton As ToolStripButton In ToolStrip1.Items.OfType(Of ToolStripButton)()
If toolButton.CheckOnClick Then
If e.ClickedItem.Equals(toolButton) Then
_ActiveImage = e.ClickedItem.Image
Else
toolButton.Checked = False
End If
End If
Next
End Sub
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseDown
If _ActiveImage IsNot Nothing AndAlso e.Button = MouseButtons.Left Then
_Images.Add(New ImagePoint(_ActiveImage, e.Location))
Me.Invalidate()
End If
End Sub
End Class
This example just uses a simple class to hold which image was placed at what location and the paint event just loops through the list and paints the image.
If deleting images is in your future, then you would have to call e.Graphics.Clear(Color.White) before painting any images.
For the button UI, check out the alternate style for radio buttons/check boxes. They have a "toggle button" mode which sounds like exactly what you need.
You could go through the motions of detecting mouse down events on the panel, getting the coordinates, creating an image control, and placing a copy of the image in it, but there's a better approach.
Fill the panel with a single image control (fill so that it handles resizes, the image control should always be the same size as the panel). Create a new Bitmap the same size as the image control and associate it with it (set the Image property). Obtain a Graphics object for the Bitmap (Graphics.FromImage() I think). Clear() it with the background color (Color.White?).
Preload your three images on startup and write the code to toggle between them, selecting the "active one" every time a different button is selected. On the mouse down event, you can get the coordinates of the click easily. Use myGraphics.DrawImage(...) to draw the active image at that location onto the Bitmap. You can then save the Bitmap to a file or do whatever you want with it. All of these concepts have lots of examples, Google them.
If you want to interact with the images after you "drop" them (like move them around again or something), then you will need to maintain a data structure that tracks what and where you've dropped. A simple class that has a Point and Image reference will be sufficient. Each drop should add an entry to a List(Of ...) these objects. You'll probably then need to write code such as "which image is under the current mouse location?". This can be accomplished by iterating through the list and doing point/rectangle intersection testing.
Private Sub ToolStripSound_Click(sender As Object, e As EventArgs) Handles ToolStripSound.Click
If ToolStripSound.Checked = False Then
ToolStripSound.Checked = True
Else
ToolStripSound.Checked = False
End If
End Sub
Private Sub ToolStripSound_CheckedChanged(sender As Object, e As EventArgs) Handles ToolStripSound.CheckedChanged
' ToolStripSound.Checked = True
If ToolStripSound.Checked = True Then
Me.ToolStripSound.Image = Global.Traffic_Lights.My.Resources.Resources.Oxygen_Icons_org_Oxygen_Status_audio_volume_high
Else
Me.ToolStripSound.Image = Global.Traffic_Lights.My.Resources.Resources.Oxygen_Icons_org_Oxygen_Status_audio_volume_muted
End If
End Sub
I have a VB project that is converted from VB6 to VB.NET.
In this, I have a MSFlexGrid that is used as an interop compatibiliy. That means it is somewhat converted to .NET, but internally, many of the mechanisms are still from VB6/COM.
I need to drag an image from a PictureBox (which is .NET) and drop it on the flexgrid.
This is what I do to initialize the drag:
Private Sub picStartSymbol_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picStartSymbol.MouseDown
picStartSymbol.DoDragDrop(picStartSymbol.Image, DragDropEffects.Copy)
End Sub
And this is where I catch the drop in the FlexGrid:
Private Sub flxConstructionPoints_OLEDragDrop(ByVal sender As Object, ByVal e As AxMSFlexGridLib.DMSFlexGridEvents_OLEDragDropEvent) Handles flxConstructionPoints.OLEDragDrop
Dim image As Image
Dim oleImage As Object
oleImage = e.data.GetData(2) ''This gets an object of type 2 (bitmap)
''How to convert oleImage to a .NET Image?
End Sub
I don't have VB6 anymore so I can't test this but try adding a reference to Microsoft.VisualBasic.Compatibility and then call:
Dim image as Image = Microsoft.VisualBasic.Compatibility.VB6.IPictureToImage(oleImage)
or
Dim image as Image = Microsoft.VisualBasic.Compatibility.VB6.IPictureDispToImage(oleImage)