Results 1 to 14 of 14

Thread: Manipulating GDI+ Drawings

  1. #1

    Thread Starter
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    105,020

    Manipulating GDI+ Drawings

    C# version here.

    The attached project demonstrates how the user can manipulate GDI+ drawings as though they were actual objects. It was created in VS 2008 but all the code should be compatible with VS 2005.

    The application is supposed to behave, in a very rudimentary way, like the VS WinForms designer. You can click and drag to draw boxes on the form. The boxes will be drawn with an apparent z-order, where newer boxes appear to be in front of older ones. You can right-click on a box and select "Bring to Front" or "Send to Back" to change that z-order. You can also click the button on the tool bar to put the application into drag mode, which allows you to click and drag a box to move it around the form.

    For an explanation of the genesis of this code, visit my blog.
    Attached Files Attached Files
    Last edited by jmcilhinney; Oct 23rd, 2009 at 07:56 AM. Reason: Provided some explanation of how to use the app; Added blog link

  2. #2
    Hyperactive Member
    Join Date
    Mar 2009
    Posts
    462

    Re: Manipulating GDI+ Drawings

    awesome thanks

  3. #3
    Frenzied Member toecutter's Avatar
    Join Date
    Apr 2006
    Location
    Brisbane, Australia
    Posts
    1,141

    Re: Manipulating GDI+ Drawings

    Is there any terms to using this in a project as i will be able to utilize this?

    Excellent stuff

    toe

  4. #4

    Thread Starter
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    105,020

    Re: Manipulating GDI+ Drawings

    Quote Originally Posted by toecutter View Post
    Is there any terms to using this in a project as i will be able to utilize this?

    Excellent stuff

    toe
    Feel free to use it any way you see fit. I require no acknowledgement; just don't specifically claim it as your own and I'm fine.

  5. #5
    Frenzied Member toecutter's Avatar
    Join Date
    Apr 2006
    Location
    Brisbane, Australia
    Posts
    1,141

    Re: Manipulating GDI+ Drawings

    jm, i have been trying to adapt your code to allow different colored boxes to be drawn without any luck.

    I have replicated every variable and structure like so
    Code:
     Private startPoint As Point
     Private startPoint2 As Point
    'etc
        Private Sub InvalidateRectangle(ByVal box As Rectangle)
            'When invalidating a Rectangle the right-most
            'column and bottom-most row of pixels is excluded.
            'Inflate the box by 1 pixel in every direction to
            'ensure those excluded pixels are alos repainted.
            box.Inflate(1, 1)
            Me.PictureBox1.Invalidate(box)
        End Sub
    
        Private Sub InvalidateRectangle2(ByVal box2 As Rectangle)
            'When invalidating a Rectangle the right-most
            'column and bottom-most row of pixels is excluded.
            'Inflate the box by 1 pixel in every direction to
            'ensure those excluded pixels are alos repainted.
            box2.Inflate(1, 1)
            Me.PictureBox1.Invalidate(box2)
        End Sub
    'etc
    I have also used a if else statement in the PictureBox1_Paint sub for the different colored boxes

    Code:
    if label1.text = "A" then
     Dim MyBrush As New SolidBrush(Color.FromArgb(150, 120, 120, 120))
                            .FillRectangle(MyBrush, box2)
                            .DrawRectangle(Pens.Black, box2)
    else
        Dim MyBrush As New SolidBrush(Color.FromArgb(100, 200, 255, 220))
                            .FillRectangle(MyBrush, box)
                            .DrawRectangle(Pens.Black, box)
    I am able to get different colored boxs but when i draw the second colored box all the previous box's change color to the new color during the beginning of the mouse move sub.

    Code:
        Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
            If Concrete.Visible = True Then
                If Console.lblComponentType.Text = "Beam" Then
                    Dim width As Integer = 50
                    Dim height As Integer = 50
                    Dim source As New Bitmap(width, height)
                    Try
                        Using canvas As Graphics = Graphics.FromImage(source)
                            canvas.DrawImage(Me.PictureBox1.Image, source.GetBounds(GraphicsUnit.Pixel), New RectangleF(e.X - width \ 2, e.Y - height \ 2, source.Width, source.Height), GraphicsUnit.Pixel)
                            With Windows.Forms.Cursor.Current
                                Dim hotSpot As Point = .HotSpot
                                Dim cursorSize As Size = .Size
                                .Draw(canvas, New Rectangle(width \ 2 - hotSpot.X, height \ 2 - hotSpot.Y, cursorSize.Width, cursorSize.Height))
                            End With
                        End Using
                    Catch ex As Exception
                    End Try
                    'Only do work if the left mouse button is the one and only mouse button that is depressed.
                    If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then
                        If Me.drawMode2 Then
                            'The old box area must be repainted in case the box has shrunk.
                            Me.InvalidateRectangle2(Me.GetRectangle2(Me.startPoint2, Me.endPoint2))
                            'A draw operation ends at the current mouse location.
                            Me.endPoint = e.Location
                            'The new box area must be repainted in case the box has grown.
                            Me.InvalidateRectangle2(Me.GetRectangle2(Me.startPoint2, Me.endPoint2))
                            Me.PictureBox1.Update()
                        ElseIf Me.selectedBoxIndex2 <> -1 Then
                            'Get the box that's being dragged.
                            Dim box2 As Rectangle = Me.boxes2(Me.selectedBoxIndex2)
                            Dim location2 As Point = e.Location
                            'The old box area must be repainted.
                            Me.InvalidateRectangle2(box2)
                            'Move the box the same distance as the mouse pointer has moved.
                            box2.Offset(location2.X - Me.startPoint2.X, location2.Y - Me.startPoint2.Y)
                            'The box we edited was a copy so replace the original.
                            Me.boxes2(Me.selectedBoxIndex2) = box2
                            'Reset the current location as the start point for the next drag.
                            Me.startPoint2 = location2
                            'The new box area must be repainted.
                            Me.InvalidateRectangle2(box2)
                            Me.PictureBox1.Update()
                        End If
                        RaiseEvent PreviewNeeded(Me, New ImageEventArgs(source))
                    End If
                Else
                    Dim width As Integer = 50
                    Dim height As Integer = 50
                    Dim source As New Bitmap(width, height)
                    Try
                        Using canvas As Graphics = Graphics.FromImage(source)
                            canvas.DrawImage(Me.PictureBox1.Image, source.GetBounds(GraphicsUnit.Pixel), New RectangleF(e.X - width \ 2, e.Y - height \ 2, source.Width, source.Height), GraphicsUnit.Pixel)
                            With Windows.Forms.Cursor.Current
                                Dim hotSpot As Point = .HotSpot
                                Dim cursorSize As Size = .Size
                                .Draw(canvas, New Rectangle(width \ 2 - hotSpot.X, height \ 2 - hotSpot.Y, cursorSize.Width, cursorSize.Height))
                            End With
                        End Using
                    Catch ex As Exception
                    End Try
                    'Only do work if the left mouse button is the one and only mouse button that is depressed.
                    If Control.MouseButtons = Windows.Forms.MouseButtons.Left Then
                        If Me.drawMode Then
                            'The old box area must be repainted in case the box has shrunk.
                            Me.InvalidateRectangle(Me.GetRectangle(Me.startPoint, Me.endPoint))
                            'A draw operation ends at the current mouse location.
                            Me.endPoint = e.Location
                            'The new box area must be repainted in case the box has grown.
                            Me.InvalidateRectangle(Me.GetRectangle(Me.startPoint, Me.endPoint))
                            Me.PictureBox1.Update()
                        ElseIf Me.selectedBoxIndex <> -1 Then
                            'Get the box that's being dragged.
                            Dim box As Rectangle = Me.boxes(Me.selectedBoxIndex)
                            Dim location As Point = e.Location
                            'The old box area must be repainted.
                            Me.InvalidateRectangle(box)
                            'Move the box the same distance as the mouse pointer has moved.
                            box.Offset(location.X - Me.startPoint.X, location.Y - Me.startPoint.Y)
                            'The box we edited was a copy so replace the original.
                            Me.boxes(Me.selectedBoxIndex) = box
                            'Reset the current location as the start point for the next drag.
                            Me.startPoint = location
                            'The new box area must be repainted.
                            Me.InvalidateRectangle(box)
                            Me.PictureBox1.Update()
                        End If
                        RaiseEvent PreviewNeeded(Me, New ImageEventArgs(source))
                    End If
                End If
            End If
        End Sub
    Should i be cloning all the code or is there a better way to do this?

    regards
    toe

  6. #6

    Thread Starter
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    105,020

    Re: Manipulating GDI+ Drawings

    Quote Originally Posted by toecutter View Post
    jm, i have been trying to adapt your code to allow different colored boxes to be drawn without any luck.
    You need to remember that every time a Paint event is raised you are drawing every box. If you are selecting the colour at that point and you're only using a single colour then every box will be that colour each time you draw. If you expect every box to remember the colour that was selected when it was drawn then that's exactly what you need to do: remember the colour that was selected when a box was first drawn by storing it with the box information. Then, when you loop through the boxes to be drawn in the Paint event, you'll read the colour for each box individually as well as its location and size. If you need to define your own type to store the information then so be it. Maybe a class or structure with a Rectangle property and a Color property.

  7. #7
    Addicted Member
    Join Date
    Apr 2008
    Posts
    193

    Re: Manipulating GDI+ Drawings

    John,

    Thank you for the code!
    It's exactly what I need for a recent project.

  8. #8
    Frenzied Member
    Join Date
    Aug 2000
    Posts
    1,091

    Re: Manipulating GDI+ Drawings

    Just saw this. Man, this is really cool!

    Visual Studio 2010

  9. #9
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Manipulating GDI+ Drawings

    I hope you don't mind, but I'm trying to extend this sample a bit. The most important stuff I plan to add is:
    • Multiple shapes
    • Selecting multiple shapes
    • Resizing shapes
    • Selection rectangles

    So far I got two shapes (but adding shapes is easy; all I need is to add a class that derives from the base shape and implement its own drawing method) and the selection rectangle. The selection rectangle looks similar to that in VS, but it's not functional yet (no resizing).
    Attached Images Attached Images  

  10. #10

    Thread Starter
    .NUT jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    105,020

    Re: Manipulating GDI+ Drawings

    Quote Originally Posted by NickThissen View Post
    I hope you don't mind, but I'm trying to extend this sample a bit.
    I don't mind at all. This was specifically supposed to be a base example from which useful extensions could be created. Sounds like that's just what you're doing.

  11. #11
    Frenzied Member
    Join Date
    Aug 2000
    Posts
    1,091

    Re: Manipulating GDI+ Drawings

    Quote Originally Posted by NickThissen View Post
    I hope you don't mind, but I'm trying to extend this sample a bit. The most important stuff I plan to add is:
    • Multiple shapes
    • Selecting multiple shapes
    • Resizing shapes
    • Selection rectangles

    So far I got two shapes (but adding shapes is easy; all I need is to add a class that derives from the base shape and implement its own drawing method) and the selection rectangle. The selection rectangle looks similar to that in VS, but it's not functional yet (no resizing).
    Even cooler! Do you plan on sharing this with us eventually?

    Visual Studio 2010

  12. #12
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Manipulating GDI+ Drawings

    Quote Originally Posted by dbassettt74 View Post
    Even cooler! Do you plan on sharing this with us eventually?
    Of course, that's the purpose

    I do have some plans for applications like this, but they all involve some much more complicated stuff and I've given up on them for now and decided to try just the easier stuff like this.

    What I really like to add is a zoom function, but that would radically change even the original example because it has to use vector based drawing instead of the usual 'draw the rectangle at it's current location', so I doubt I can pull that off...

  13. #13
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Manipulating GDI+ Drawings

    Just letting you know I'm still working on this, but it's taking its time. I am trying to make it look like a very rudimentary version of Visual Studio, with a 'toolbox' on the left, a list of the shapes on the right and a property grid.

    There's still some problems to be solved but I'll get there in the end.



    The 'Draw Mode' is going to have to go in the end. Shapes should be drawn by dragging them from the toolbox, as in Visual Studio, or Visio, or most other 'shape drawing' software.

  14. #14
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Manipulating GDI+ Drawings

    Hello there... I've finally got around to do some more work on this shape editor. I've decided to start from scratch as I had some concepts wrong which made it hard to fix some stuff.

    Find it here.
    Unfortunately, at the moment, it is only available in C#.NET. You can still use the shapes and canvas in a VB project, but you'll have to translate the example project to VB.NET (only a few lines of code though).

    The example is not as good as the screenshot above (yet) because it wasn't a priority. It does have a ComboBox to select the available shapes and a PropertyGrid to set the properties of the selected shape, just like in Visual Studio.

    Enjoy!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width