|
-
Jul 20th, 2009, 01:16 AM
#1
Thread Starter
Junior Member
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
-
Jul 20th, 2009, 01:31 AM
#2
New Member
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.
-
Jul 20th, 2009, 02:29 AM
#3
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.
-
Jul 20th, 2009, 04:17 AM
#4
Thread Starter
Junior Member
Re: drawing removably in a picturebox
 Originally Posted by jmcilhinney
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
-
Jul 20th, 2009, 04:20 AM
#5
Thread Starter
Junior Member
Re: drawing removably in a picturebox
 Originally Posted by icedtrees
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.
-
Jul 20th, 2009, 04:20 AM
#6
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
-
Jul 20th, 2009, 04:48 AM
#7
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.
-
Jul 20th, 2009, 12:30 PM
#8
Thread Starter
Junior Member
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.
-
Jul 20th, 2009, 01:08 PM
#9
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:
Dim bmp As New Bitmap(Me.PictureBox1.Width, Me.PictureBox1.Height) Using g As Graphics = Graphics.FromImage(bmp) For i As Integer = 0 To 99999 g.DrawLine(Pens.Red, 0, 10, PictureBox1.Width, 10) g.DrawLine(Pens.Blue, 0, 40, PictureBox1.Width, 40) g.DrawLine(Pens.Green, 0, 80, PictureBox1.Width, 80) g.DrawLine(Pens.Yellow, 0, 110, PictureBox1.Width, 110) g.DrawLine(Pens.Pink, 0, 140, PictureBox1.Width, 140) g.DrawLine(Pens.Black, 0, 180, PictureBox1.Width, 180) Next End Using 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.
Last edited by NickThissen; Jul 20th, 2009 at 01:32 PM.
-
Jul 20th, 2009, 01:40 PM
#10
Thread Starter
Junior Member
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.
-
Jul 20th, 2009, 04:18 PM
#11
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."
-
Jul 20th, 2009, 05:07 PM
#12
Thread Starter
Junior Member
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.
-
Jul 21st, 2009, 06:53 AM
#13
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.
-
Jul 21st, 2009, 08:17 AM
#14
Thread Starter
Junior Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|