Results 1 to 14 of 14

Thread: drawing removably in a picturebox

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Jun 2009
    Location
    Hungary
    Posts
    19

    drawing removably in a picturebox

    Hi,

    In my application there's a PictureBox with a drawing inside. I implemented a zoom function that works in the following way:

    - The user clicks somewhere in the PictureBox, and holds the button down. The program stores the cursor position.
    - The user moves the mouse, while still holding the button down. The program draws a rectangle between the original and the current cursor position.
    - The user moves the mouse further, while still holding the button down. The program deletes the last rectangle, and draws a new rectangle between the original and the current cursor position.
    - The user releases the button. The program deletes the last rectangle, and executes the zooming based on the original and the current cursor position.

    This is working fine so far.
    My problem is that I could only delete the rectangles by drawing same-sized, background-colored rectangles on top of them. But this also deleting the original drawing inside the PictureBox. Is there a way to draw "removable" rectangles?

    I know that in Delphi you can use a special brush style, that somehow combines the brush color and the canvas color for each pixel, and you can remove any shapes by drawing them again over themselves, and get the canvas back unchanged. I'm looking for something similar.

    Jimmy

  2. #2
    New Member icedtrees's Avatar
    Join Date
    Jul 2009
    Posts
    12

    Re: drawing removably in a picturebox

    The simple solution is to draw pictureboxes instead of rectangles, and use

    PictureBoxName.Dispose()

    to delete them.

    I'm not exactly sure how rectangles and graphics work on pictureboxes, but I think you can use

    GraphicsName.Dispose()

    as well to delete the rectangles you've drawn. I'm not exactly sure how this works, but the picturebox thing would certainly work.

    Also, does anyone know how you can get image transparency to come through in Visual Basic? Because if you try to put an image with some transparent sections on it on a form, the transparency turns into the form background colour (Though you could change the background image to whatever you want displayed under the image, but that's not the point) and basically I can't find any way to do irregular transparencies.
    ^^ Sorry, forgot about hijcaking threads thing
    Last edited by icedtrees; Jul 20th, 2009 at 05:57 AM.

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: drawing removably in a picturebox

    Anything you draw using GDI+ is inherently erasable. The very reason that you have to draw on the Paint event is that anything you draw will be erased at the next Paint event, so you have to draw it again. If you want to "erase" something that you've previously drawn you simply remove its data and then force a repaint. Everything gets erased and then the part you removed will not get redrawn. Try this for an example:

    1. Create a new WinForms project.
    2. Add 2 Buttons.
    3. Add this code:
    Code:
    Private rectangles As New List(Of Rectangle)
    
    Private Sub Button1_Click(ByVal sender As Object, _
                              ByVal e As EventArgs) Handles Button1.Click
        'Add a new rectangle.
        Me.rectangles.Add(Me.GetNextRectangle())
    
        'Force a repaint.
        Me.Refresh()
    End Sub
    
    Private Sub Button2_Click(ByVal sender As Object, _
                              ByVal e As EventArgs) Handles Button2.Click
        If Me.rectangles.Count > 0 Then
            'Remove the first rectangle.
            Me.rectangles.RemoveAt(0)
    
            'Force a repaint.
            Me.Refresh()
        End If
    End Sub
    
    Private Sub Form1_Paint(ByVal sender As Object, _
                            ByVal e As PaintEventArgs) Handles Me.Paint
        If Me.rectangles.Count > 0 Then
            'Draw all the rectangles.
            e.Graphics.DrawRectangles(Pens.Black, Me.rectangles.ToArray())
        End If
    End Sub
    
    Private Function GetNextRectangle() As Rectangle
        Dim nextRectangle As Rectangle
    
        If Me.rectangles.Count > 0 Then
            'Get the last rectangle.
            nextRectangle = Me.rectangles(Me.rectangles.Count - 1)
    
            'Make the next rectangle bigger than the last in both directions.
            nextRectangle.Inflate(10, 20)
        Else
            'Create a new rectangle.
            nextRectangle = New Rectangle(145, 140, 10, 20)
        End If
    
        Return nextRectangle
    End Function
    4. Run the project.
    5. Click the Buttons in different combinations.

    You'll see that each time you click Button1 a rectangle gets added and each time you click Button2 one gets removed. Now examine the code to see how it's done.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  4. #4

    Thread Starter
    Junior Member
    Join Date
    Jun 2009
    Location
    Hungary
    Posts
    19

    Re: drawing removably in a picturebox

    Quote Originally Posted by jmcilhinney View Post
    Anything you draw using GDI+ is inherently erasable. The very reason that you have to draw on the Paint event is that anything you draw will be erased at the next Paint event, so you have to draw it again.
    Yes, I've heard about how it's best practices to put everything into the Paint event, and I understand the basics. Yet I don't think it does apply to this special case, because my graphics is very complicated.

    This is still the chromatography project I wrote about in the other thread. A single chromatogram usually consists of 18000-48000 data points. Drawing a chromatogram means a loop of 5-48000 steps, depending on the current zoom state, and in each step the on-graphic coordinates of the current datapoint must be calculated, also based on the zoom state.

    Now imagine there are two, three, even five or ten chromatograms overlapped for comparison. These all get redrawn in the Paint event. Which is okay but, in my experience, takes considerable time.

    The rectangle I'm using is simply an indicator of the area the user selects for zoom. It's by definition temporary, and lasts only as long as the user keeps the mousebutton pressed. And it gets redrawn as long as the user moves the mouse. Repainting the PictureBox for each simple mousemove would mean redrawing all the chromatograms as well. It would result in a flashing graphics and very slow response for user interaction. That's why I put drawing the rectangle outside the paint event.

    Still, your example code shows some interesting tricks, so it's useful anyway.

    Jimmy
    Last edited by JimmyTheHand; Jul 20th, 2009 at 07:05 AM. Reason: correction of spelling errors

  5. #5

    Thread Starter
    Junior Member
    Join Date
    Jun 2009
    Location
    Hungary
    Posts
    19

    Re: drawing removably in a picturebox

    Quote Originally Posted by icedtrees View Post
    The simple solution is to draw pictureboxes instead of rectangles, and use

    PictureBoxName.Dispose()

    to delete them.
    I'll try this later. Thanks for the tip.

  6. #6
    PowerPoster keystone_paul's Avatar
    Join Date
    Nov 2008
    Location
    UK
    Posts
    3,327

    Re: drawing removably in a picturebox

    Also, does anyone know how you can get image transparency to come through in Visual Basic? Because if you try to put an image with some transparent sections on it on a form, the transparency turns into the form background colour (Though you could change the background image to whatever you want displayed under the image, but that's not the point) and basically I can't find any way to do irregular transparencies.
    Yes, but you shouldn't hijack another thread. Post a new question and I'll explain

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: drawing removably in a picturebox

    It sounds to me like you should be drawing your chromatograms on an Image and displaying that in the PictureBox, then drawing your rectangle onto the image itself. It's analogous to a photo in a frame where you're drawing on the glass in the frame and not affecting the photo behind it, although they appear as one picture from the front.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  8. #8

    Thread Starter
    Junior Member
    Join Date
    Jun 2009
    Location
    Hungary
    Posts
    19

    Re: drawing removably in a picturebox

    How do you draw on an Image?
    I've found no Image control in the Toolbox, and also haven't found anything among the members of PictureBox.Image that allows direct drawing on the Image.

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

    Re: drawing removably in a picturebox

    I think what jmcilhinney means is that you draw your chomatogram onto a bitmap (image), and load that bitmap as the PictureBox's Image. You can then use the Paint event to draw your rectangle as shown. The Image is not constantly re-drawn (at least not as in your 50000 step loop), so there will be little to no lag.

    EDIT
    You can draw on a bitmap by creating a graphics object from a bitmap object. For example:
    vb.net Code:
    1. Dim bmp As New Bitmap(Me.PictureBox1.Width, Me.PictureBox1.Height)
    2.         Using g As Graphics = Graphics.FromImage(bmp)
    3.             For i As Integer = 0 To 99999
    4.                 g.DrawLine(Pens.Red, 0, 10, PictureBox1.Width, 10)
    5.                 g.DrawLine(Pens.Blue, 0, 40, PictureBox1.Width, 40)
    6.                 g.DrawLine(Pens.Green, 0, 80, PictureBox1.Width, 80)
    7.                 g.DrawLine(Pens.Yellow, 0, 110, PictureBox1.Width, 110)
    8.                 g.DrawLine(Pens.Pink, 0, 140, PictureBox1.Width, 140)
    9.                 g.DrawLine(Pens.Black, 0, 180, PictureBox1.Width, 180)
    10.             Next
    11.         End Using
    12.  
    13.         PictureBox1.Image = bmp

    I'm just drawing some horizontal lines over and over and over, takes about 3/4 seconds here.

    I can then use any drawing I like in the PictureBox's Paint event, and I can invalidate the picturebox whenever I like (on MouseMove event for example), and it will not re-run that long loop.

  10. #10

    Thread Starter
    Junior Member
    Join Date
    Jun 2009
    Location
    Hungary
    Posts
    19

    Re: drawing removably in a picturebox

    That's not good.
    The application needs to be able, on users demand, to swap chromatograms in and out of the PicureBox, as well as shifting them up and down along the Y axis. Also, if I draw a bitmap image of a 18000 points chromatogram, that would be quite crude when magnified to 1000:1. I must retain the vector graphics aspect of the chromatograms.

    Anyway, in the meantime I made some progress with the "transparent picturebox as a zoom indicator" idea. It's quite promising, so I'll stick to that, unless drawing on a bitmap image has some very convincing advantages.

    EDIT
    I just noticed the EDIT you made. Seems like I need to think it over again...
    Thanks for the help.
    Last edited by JimmyTheHand; Jul 20th, 2009 at 01:44 PM.

  11. #11
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: drawing removably in a picturebox

    What nick is suggesting is probably the best method. Essentially, you need to speed things up so that the paint event doesn't recalculate positions for points which haven't moved.

    When you 'zoom' (or move), you are going to have to re-plot everything anyway. At this point, you will repaint your bitmap with everything calculated correctly. As you zoom in more and more, it'll actually get quicker and quicker as more and more points fall outside the actual drawing region (Zooming out on anything usually means things get slower and slower graphically, unless you have interpolated data points).

    When these 'chromatograms' are switched in and out, you may want to create a finite FIFO buffer of bitmaps, so that you don't destroy recently viewed bitmaps that may still be needed by the user.
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  12. #12

    Thread Starter
    Junior Member
    Join Date
    Jun 2009
    Location
    Hungary
    Posts
    19

    Re: drawing removably in a picturebox

    The "speed things up" part is already taken care of. Only that part of the graphic gets calculated and redrawn which is actually visible through the zoom "window". I'm not sure what you mean by interpolating, but you gave me an idea nevertheless. I could contract datapoints that have the same on-graphic X coordinate. I will think about such an algorithm, an maybe implement it, if it looks good.

    I'll also consider that FIFO buffer you suggested. In time. You see, this is my 1st project and 2nd week into VB, and I've never met .NET before, so I need some time to get used to all these wonders.

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

    Re: drawing removably in a picturebox

    The idea is that you are going to have to redraw your image anyway when you zoom it (correct me if I'm wrong). Whether you do that directly on to the PictureBox, or onto an Image which you then set as the PictureBox's Image, will not matter at all.

    If you draw your chromatogram onto the PictureBox directly, in the Paint event, it will get redrawn every single time the PictureBox refreshes. Since you want to draw something more on top of the PictureBox (the selection rectangle), it will get refreshed quite often. But there is no need for that!

    When you have your drawing on the Image, it will not get refreshed until you tell it to (eg, by calling the drawing function again and setting the image). Now, when you draw anything on top of the PictureBox (eg, your selection rectangle), that image is not completely redrawn from scratch again. I would call that a considerable improve in speed, even if the actual drawing takes only about a tenth of a second.

  14. #14

    Thread Starter
    Junior Member
    Join Date
    Jun 2009
    Location
    Hungary
    Posts
    19

    Re: drawing removably in a picturebox

    Yesterday I tested the transparent picturebox version vith some simple graphics, and it was promising. I never noticed the graphics repainted while resizing the selection rectangle.
    Today I reached the state where I could test it with a real (i.e. about 49200 datapoints) chromatogram behind... and it sucks.
    I'm really convinced now, that the bitmap version is better. I'll see to it soon.

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