Drawing Rectangles on Image

Hi all!

For some tools I want to write I'd like to have the functionality of drawing rectangles onto an image, but I really can't figure out, how this could work, as the whole DC-topic makes not much sense to me.

My basic "idea" of how it should work is as follows:
1) Start the program and have a ScrolledWindow with white background as "canvas" or drawing area.
2) Load an image from the filesystem and "draw" it onto the "canvas".
3) When clicking and holding the left mouse button I want to draw a rectangle with only outlines and no filling (I guess to need wx.Pen & wx.Brush together with wx.TRANSPARENT).
4) Whenever a rectangle is complete (x, y, width and height come from MouseDown and MouseUp event coordinates, I guess?) it should be stored in a list.
5) The rectangles should be "temporarily" - I don't want them to be saved to the image, but I'd like to "pickle" the list later on.

So I think I need the following things:
an area that is displayed (my ScrolledWindow -> canvas) and "some layers" that I paint to the ScrolledWindow when it's onPaint event is fired, but I have absolutely no idea how to draw all that. There should be some layers. A base layer, a layer with all the rectangles and a layer that shows the part, when the mousebutton is pressed & the mouse is moving.
I played around a little, copied some snippets from the web without grasping it's meaning, but none of them is satisfying or nearly working the way I'd like it to. I don't know, when to use which type of DC, as there are multiple ...

Can anybody give me a little explanation and maybe hint on that?

Thank you!

PeterK

take a look in the demo for the drawing examples -- or maybe in the ScrolledWindow example -- it does all that, though with a line, rather than rectangles, but it's really similar.

Also look in the Wiki for more info on drawing.

-Chris

···

On 11/7/11 6:50 AM, Perum Bem wrote:

Can anybody give me a little explanation and maybe hint on that?

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Hi all!

For some tools I want to write I'd like to have the functionality of
drawing rectangles onto an image, but I really can't figure out, how
this could work, as the whole DC-topic makes not much sense to me.

My basic "idea" of how it should work is as follows:
1) Start the program and have a ScrolledWindow with white background as
"canvas" or drawing area.
2) Load an image from the filesystem and "draw" it onto the "canvas".
3) When clicking and holding the left mouse button I want to draw a
rectangle with only outlines and no filling (I guess to need wx.Pen &
wx.Brush together with wx.TRANSPARENT).
4) Whenever a rectangle is complete (x, y, width and height come from
MouseDown and MouseUp event coordinates, I guess?) it should be stored
in a list.
5) The rectangles should be "temporarily" - I don't want them to be
saved to the image, but I'd like to "pickle" the list later on.

So I think I need the following things:
an area that is displayed (my ScrolledWindow -> canvas) and "some
layers" that I paint to the ScrolledWindow when it's onPaint event is
fired, but I have absolutely no idea how to draw all that. There should
be some layers. A base layer, a layer with all the rectangles and a
layer that shows the part, when the mousebutton is pressed & the mouse
is moving.
I played around a little, copied some snippets from the web without
grasping it's meaning, but none of them is satisfying or nearly working
the way I'd like it to. I don't know, when to use which type of DC, as
there are multiple ...

Always use a wx.PaintDC (or something that creates a wx.PaintDC like wx.BufferedPaintDC) in EVT_PAINT handlers. Use a wx.ClientDC when drawing to the screen from outside of a EVT_PAINT handler (although if you can avoid it and do all your drawing to the screen from EVT_PAINT it would be better). And use a wx.MemoryDC when you want to do "off-screen drawing" such as when buffering a series of drawing operations into a bitmap which will later be drawn to the screen. The wx.BufferedDC and friends are basically just simple conveniences derived from wx.MemoryDC.

Can anybody give me a little explanation and maybe hint on that?

While layers are a convenient abstraction for the user of a drawing program, when you get right down to the actual drawing on the screen there is really only 1 layer per window. You need to keep track of the rest of it in your drawing code. Layers really is not much more than the order that things are drawn and the option to turn on/off parts of the drawing. Things in the lower layers are drawn first, then the next layer up and so on. To eliminate flicker from all this drawing you can use one of the various double buffering techniques shown in the demo, wx.lib or the wiki.

Temporary or Selection rectangles (a.k.a rubber-banding) can be implemented in a few different ways. The easiest is to just draw rectangles from the mouse events with the DC's logical function set to wx.XOR, which will sorta invert the pixels already there as it draws the lines. The neat thing about it is that to erase the rectangle (before drawing the next largest one for example) you just redraw the rectangle and the original pixels will be restored. I think there is an example of this in the pySketch sample.

A newer technique for doing rubber-banding or selection rectangles that would also work for placing new rectangles is to use the wx.Overlay feature. There is an example of it here wxTrac has been migrated to GitHub Issues - wxWidgets

···

On 11/7/11 6:50 AM, Perum Bem wrote:

--
Robin Dunn
Software Craftsman

Thank you both for the reply.
And thank you, Robin, for the detailed explanation. I guess this gives
me a starting point. I have tried to work with both the wxPython demo
and the excellent pySketch, but both were too much information at once
for me. I also took a look into your book, but for some reason I was
unable to understand... (maybe because I'm just a hobby programmer and
English is not my native language).

The overlay demo is quite close to what I want to have and it seems
"rubberband" was the keyword I should have had searched for.

Now I'll start playing around with this new information.

Thanks

PeterK

···

On 7 Nov., 20:31, Robin Dunn <ro...@alldunn.com> wrote:

Always use a wx.PaintDC (or something that creates a wx.PaintDC like
wx.BufferedPaintDC) in EVT_PAINT handlers. Use a wx.ClientDC when
drawing to the screen from outside of a EVT_PAINT handler (although if
you can avoid it and do all your drawing to the screen from EVT_PAINT it
would be better). And use a wx.MemoryDC when you want to do "off-screen
drawing" such as when buffering a series of drawing operations into a
bitmap which will later be drawn to the screen. The wx.BufferedDC and
friends are basically just simple conveniences derived from wx.MemoryDC.

> Can anybody give me a little explanation and maybe hint on that?

While layers are a convenient abstraction for the user of a drawing
program, when you get right down to the actual drawing on the screen
there is really only 1 layer per window. You need to keep track of the
rest of it in your drawing code. Layers really is not much more than
the order that things are drawn and the option to turn on/off parts of
the drawing. Things in the lower layers are drawn first, then the next
layer up and so on. To eliminate flicker from all this drawing you can
use one of the various double buffering techniques shown in the demo,
wx.lib or the wiki.

Temporary or Selection rectangles (a.k.a rubber-banding) can be
implemented in a few different ways. The easiest is to just draw
rectangles from the mouse events with the DC's logical function set to
wx.XOR, which will sorta invert the pixels already there as it draws the
lines. The neat thing about it is that to erase the rectangle (before
drawing the next largest one for example) you just redraw the rectangle
and the original pixels will be restored. I think there is an example
of this in the pySketch sample.

A newer technique for doing rubber-banding or selection rectangles that
would also work for placing new rectangles is to use the wx.Overlay
feature. There is an example of it herehttp://trac.wxwidgets.org/browser/wxPython/trunk/sandbox/test_Overlay.py