Problem drawing a selection rectangle in canvas

I am trying to draw a selection rectangle with ogl. I can draw the
rectangle but I cannot delete it in each OnDragLeft event, so I obtain many
selection rectangles (one for each OnDragLeftEvent), as can be seen in the
attached example. How could I delete this rectangles to obtain only one
selection rectangle?

Thank you in advance for your help,

Adrián Morales Torres

Test rect select.py (1.47 KB)

Adri�n Morales Torres wrote:

I am trying to draw a selection rectangle with ogl. I can draw the
rectangle but I cannot delete it in each OnDragLeft event, so I obtain
many selection rectangles (one for each OnDragLeftEvent), as can be seen
in the attached example. How could I delete this rectangles to obtain
only one selection rectangle?

How about instead of creating a new rectangle in each drag event, just create one at the beginning (like in the left-down or the first drag-left) and then update its size and position as needed in the drag events. Then when you are done with it you just need to delete the one rectangle.

···

--
Robin Dunn
Software Craftsman

Thank you for your help,

Adrián Morales Torres

···

El martes, 29 de enero de 2013 18:27:24 UTC+1, Robin Dunn escribió:

Adri�n Morales Torres wrote:

I am trying to draw a selection rectangle with ogl. I can draw the

rectangle but I cannot delete it in each OnDragLeft event, so I obtain

many selection rectangles (one for each OnDragLeftEvent), as can be seen

in the attached example. How could I delete this rectangles to obtain

only one selection rectangle?

How about instead of creating a new rectangle in each drag event, just
create one at the beginning (like in the left-down or the first
drag-left) and then update its size and position as needed in the drag
events. Then when you are done with it you just need to delete the one
rectangle.

In the example I have uploaded in the previous post, I am creating the rectangle
in the event OnBeginDragLeft and changing its size and position in the event OnDragLeft
with the commands move and setsize. But I still have the same problem and the
previous selection rectangle is not deleted when I change the size and position.

Adri�n Morales Torres wrote:

El martes, 29 de enero de 2013 18:27:24 UTC+1, Robin Dunn escribi�:

    Adri�n Morales Torres wrote:
     > I am trying to draw a selection rectangle with ogl. I can draw the
     > rectangle but I cannot delete it in each OnDragLeft event, so I
    obtain
     > many selection rectangles (one for each OnDragLeftEvent), as can
    be seen
     > in the attached example. How could I delete this rectangles to
    obtain
     > only one selection rectangle?

    How about instead of creating a new rectangle in each drag event, just
    create one at the beginning (like in the left-down or the first
    drag-left) and then update its size and position as needed in the drag
    events. Then when you are done with it you just need to delete the one
    rectangle.

    --

    In the example I have uploaded in the previous post, I am creating
    the rectangle in the event OnBeginDragLeft and changing its size and position in
    the event OnDragLeft with the commands move and setsize. But I still have the same
    problem and the previous selection rectangle is not deleted when I change the size
    and position.

Thank you for your help,

Sorry, I looked at your example code too quickly and I misread it.

The OnDragLeft method is actually called twice for each mouse motion event, once for you to erase the shape at the old position and once to move/draw it at the new position. The draw parameter is what tells you if you should draw or erase. For example:

     def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
         dc = wx.ClientDC(self)
         if draw:
             self.selec.SetSize(abs(x-self.xini), abs(y-self.yini))
             self.selec.Move(dc, (self.xini+x)/2,(self.yini+y)/2)
         else:
             self.selec.Erase(dc)

This has a couple problems though. Erase just draws a rectangle using the canvas background color, so it will also erase any shapes under your selection rectangle, which is probably not what you want. Also on Windows doing separate draw operations to erase and clear can be flickery. One possible alternative would be to just refresh the affected rectangles and then let them be redrawn later in the paint event. See my attached modification of your script for a simple example.

TestRectSelect.py (2.34 KB)

···

--
Robin Dunn
Software Craftsman

I think the "right" way to do this these days is with an wx.Overlay.

Not sure if there are any issues with doing with with OGL though.

Example enclosed (tested on wxMac wxPython 2.8)

-Chris

Overlaytest2.py (2.99 KB)

···

On Wed, Jan 30, 2013 at 1:57 PM, Robin Dunn <robin@alldunn.com> wrote:

One
possible alternative would be to just refresh the affected rectangles and
then let them be redrawn later in the paint event.

--

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

With an wx.Overlay it works properly. Thank you for your help.

Adrián Morales

···

El jueves, 31 de enero de 2013 00:57:26 UTC+1, Chris Barker - NOAA Federal escribió:

On Wed, Jan 30, 2013 at 1:57 PM, Robin Dunn ro...@alldunn.com wrote:

One

possible alternative would be to just refresh the affected rectangles and

then let them be redrawn later in the paint event.

I think the “right” way to do this these days is with an wx.Overlay.

Not sure if there are any issues with doing with with OGL though.

Example enclosed (tested on wxMac wxPython 2.8)

-Chris

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....@noaa.gov

Hi Robin

I have some questions about your attachment file:TestRectSelect.py

Q1: Why you write ogl.OGLInitialize()? Is it a must to write this when
using wx.lib.ogl? But I found some other demos, there isn't such code.
class App(wx.App):
    def OnInit(self):
        *ogl.OGLInitialize()*
        frame = MainFrame()
        frame.Show()
        return True

Q2:
    def OnDragLeft(self, draw, x, y, keys = 0, attachment = 0):
        def _getRect(shape):
            x = shape.GetX()
            y = shape.GetY()
            w = shape.GetWidth()
            h = shape.GetHeight()
            x = x - w / 2
            y = y - h / 2
            rect = wx.Rect(x, y, w, h)
            *rect.Inflate(2,2)*
            #Inflate(self, dx, dy) Increases the size of the rectangle.
            return rect
            
        if draw:
            dc = wx.MemoryDC(wx.EmptyBitmap(1,1)) # a dummy DC to make OGL
happy
            self.selec.SetSize(abs(x-self.xini), abs(y-self.yini))
           * self.selec.Move(dc, (self.xini+x)/2,(self.yini+y)/2)*
            self.RefreshRect(_getRect(self.selec), False)
        else:
            self.RefreshRect(_getRect(self.selec), False)

rect.Inflate(2,2) . I can see the difference if I set Inflate(0,0), but I
can't tell the differenct if I set Inflate(5,5). In doc, it tells this
method is used to increase the size of rectangle, but I can't understand it
well...Could you explain it in detail ?

Thank you !

···

--
View this message in context: http://wxpython-users.1045709.n5.nabble.com/Problem-drawing-a-selection-rectangle-in-canvas-tp5715808p5717167.html
Sent from the wxPython-users mailing list archive at Nabble.com.

Gabrielle wrote:

I have some questions about your attachment file:TestRectSelect.py

Q1: Why you write ogl.OGLInitialize()? Is it a must to write this when
using wx.lib.ogl? But I found some other demos, there isn't such code.

OGLInitialize sets up some things that the OGL library sometimes needs.
Not every application needs what it does, but since it costs very
little, you should get in the habit of using it every time.

Q2: ...
rect.Inflate(2,2) . I can see the difference if I set Inflate(0,0), but I
can't tell the differenct if I set Inflate(5,5). In doc, it tells this
method is used to increase the size of rectangle, but I can't understand it
well...Could you explain it in detail ?

It's not really that hard to understand, is it? A rectangle is nothing
other than a container that holds four numbers: x, y, width, and
height. That's it, nothing more. When you call rect.Inflate(2,2), you
are adding 2 to the width and to the height.

So, why didn't it make a visible difference? Take some time to read
through and understand what the code is doing, instead of just making
random changes. The rectangle you are changing is the one returned by
that _getRect function. That function is internal to the OnDragLeft
method, and it is only used in the calls to RefreshRect later.
RefreshRect is just used to tell the system that "the pixels within this
region need to be redrawn". The drawing will actually be done later.

Remember that the operating system and the graphics card don't have any
idea about shapes and circles and rectangles. When you drag a shape,
what actually happens is that you draw the shape in the new location,
and you erase the pixels where the shape used to be, by redrawing
whatever colors were underneath it. That can be an expensive operation
if the object is large, so you try to redraw as few pixels as possible.
That's what this is doing. It is coming up with the smallest region
that will make everything look up to date.

So, when you increase the size of the rectangle in that one function,
all you're doing is causing extra pixels to be redrawn that didn't
really need to be redrawn. Since those pixels haven't changed, you
won't see the effect. When you reduce the size of the rectangle, the
system doesn't know that it needs to redraw those newly exposed pixels,
so the remnants of your object will remain.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Gabrielle wrote:

Hi Robin

I have some questions about your attachment file:TestRectSelect.py

Q1: Why you write ogl.OGLInitialize()? Is it a must to write this when
using wx.lib.ogl?

Yes, it creates some pens and brushes that are used in other parts of the code.

Q2:

  rect.Inflate(2,2) . I can see the difference if I set Inflate(0,0), but I
can't tell the differenct if I set Inflate(5,5). In doc, it tells this
method is used to increase the size of rectangle, but I can't understand it
well...Could you explain it in detail ?

  >>> import wx
  >>> r = wx.Rect(5, 5, 20,30)
  >>> r
  wx.Rect(5, 5, 20, 30)
  >>> help(r.Inflate)
  Help on method Inflate in module wx._core:

  Inflate(*args, **kwargs) method of wx._core.Rect instance
     Inflate(self, int dx, int dy) -> Rect

     Increases the size of the rectangle.

     The left border is moved farther left and the right border is moved
     farther right by ``dx``. The upper border is moved farther up and the
     bottom border is moved farther down by ``dy``. (Note the the width and
     height of the rectangle thus change by ``2*dx`` and ``2*dy``,
     respectively.) If one or both of ``dx`` and ``dy`` are negative, the
     opposite happens: the rectangle size decreases in the respective
     direction.

     The change is made to the rectangle inplace, if instead you need a
     copy that is inflated, preserving the original then make the copy
     first::

         copy = wx.Rect(*original)
         copy.Inflate(10,15)

  >>> r.Inflate(2,2)
  wx.Rect(3, 3, 24, 34)

That seems pretty clear to me. The x and y positions are moved and the width and height are increased, just as the documentation specifies.

···

--
Robin Dunn
Software Craftsman

Zombie bug

If r = wx.Rect(5,5,20,30) then
r.Inflate(2,2) should result in:

wx.Rect(3,3,22,32))

as 2dx, 2dy I would think is ( 5-3=2, 5-3=2, 22-20=2, 32-30 = 2) where

(22-20) + (5-3) = 2 + 2 = 4 == 22 == 2dx where dx = 2 and

(32-30) + (5-3) = 2 + 2 = 4 == 22 == 2dy where dy = 2

a = wx.Rect(0,0, 30,30)

a.Inflate(10,10)

wx.Rect(-10, -10, 50, 50)

If I expect dx to be reduced by 10 on the left and increased by 10 on the right that would be 2*dx and result in

wx.Rect(-10,-10, 40, 40)

It seems the function is decreasing 1dx on the left and 2dx on the right for a total of 3*dx

and same goes for height.

wx.version()

‘3.0.3.dev1820+49a8884 msw (phoenix)’

···

Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:15:05) [MSC v.1600 32 bit (Intel)] on win32

On Monday, April 29, 2013 at 11:55:56 PM UTC-4, Robin Dunn wrote:

Gabrielle wrote:

Hi Robin

I have some questions about your attachment file:TestRectSelect.py

Q1: Why you write ogl.OGLInitialize()? Is it a must to write this when

using wx.lib.ogl?

Yes, it creates some pens and brushes that are used in other parts of
the code.

Q2:

rect.Inflate(2,2) . I can see the difference if I set Inflate(0,0), but I

can’t tell the differenct if I set Inflate(5,5). In doc, it tells this

method is used to increase the size of rectangle, but I can’t understand it

well…Could you explain it in detail ?

import wx

r = wx.Rect(5, 5, 20,30)

r

wx.Rect(5, 5, 20, 30)

help(r.Inflate)

Help on method Inflate in module wx._core:

Inflate(*args, **kwargs) method of wx._core.Rect instance

 Inflate(self, int dx, int dy) -> Rect



 Increases the size of the rectangle.



 The left border is moved farther left and the right border is moved

 farther right by ``dx``. The upper border is moved farther up and the

 bottom border is moved farther down by ``dy``. (Note the the width and

 height of the rectangle thus change by ``2*dx`` and ``2*dy``,

 respectively.) If one or both of ``dx`` and ``dy`` are negative, the

 opposite happens: the rectangle size decreases in the respective

 direction.



 The change is made to the rectangle inplace, if instead you need a

 copy that is inflated, preserving the original then make the copy

 first::



     copy = wx.Rect(*original)

     copy.Inflate(10,15)

r.Inflate(2,2)

wx.Rect(3, 3, 24, 34)

That seems pretty clear to me. The x and y positions are moved and the
width and height are increased, just as the documentation specifies.


Robin Dunn

Software Craftsman

http://wxPython.org

DevPlayer wrote:

Zombie bug

If r = wx.Rect(5,5,20,30) then
r.Inflate(2,2) should result in:
wx.Rect(3,3,22,32))
as 2*dx, 2*dy I would think is ( 5-3=2, 5-3=2, 22-20=2, 32-30 = 2) where
(22-20) + (5-3) = 2 + 2 = 4 == 2*2 == 2*dx where dx = 2 and
(32-30) + (5-3) = 2 + 2 = 4 == 2*2 == 2*dy where dy = 2

You are assuming that the parameters for wx.Rect are (left, top, right,
bottom), like the Windows standard. That's not correct. The parameters
are (x, y, width, height). Thus, if you inflate by 2,2, the width and
height will increase by 4 each.

Print r.right and r.bottom to prove this to yourself.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Wow I got that one wrong. I did know the 2nd set of parameters where width and height but when I applied the modified wx.Rect I applied it wrong, where the right and bottom was dx,dy further then I had expected.