Can't clear Clipping region in PaintDC

Hi all,

I really thought that I "got" wx.DCs, but this one has me stumped. I'm hoping I'm missing something obvious.

it appears that the wx.PaintDC is setting a clipping region, and only drawing to the new part of the Windows on re-size. However, when I call:

dc.GetClippingBox()

IU get (0,0,0,0)

and calling:

dc.DestroyClippingRegion()

seems to have no effect. What am I missing?

Python 2.4.3, wxPython 2.6.3.3, wxGTK unicode on Fedora core 4.

sample enclosed -- try resizing the frame, and see what happens -- I want a single rectangle with a gradient of color.

Thanks,

-Chris

ScaleWindow2.py (6.68 KB)

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

Christopher Barker wrote:

Hi all,

I really thought that I "got" wx.DCs, but this one has me stumped. I'm hoping I'm missing something obvious.

it appears that the wx.PaintDC is setting a clipping region, and only drawing to the new part of the Windows on re-size. However, when I call:

dc.GetClippingBox()

IU get (0,0,0,0)

It's not a clipping region, but an update region, and is set by the platform when the native paint event is sent. It includes the regions recently exposed, or damaged, plus any rectangles that have been passed to Refresh or RefreshRect since the last paint event.

As Paul mentioned you can get the update region, and convert it to a rectangle that encloses all of the region with:

  rgn = self.GetUpdateRegion()
  box = rgn.GetBox()

And you can also iterate through each individual rectangle in the region with something like this:

  rgniter = wx.RegionIterator(rgn)
  while rgniter:
    rect = rgniter.GetRect()
    # do something with rect
    rgniter.Next()

If you want to always paint the whole window after resize events then you can use the wx.FULL_REPAINT_ON_RESIZE style when creating the window.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Thanks Robin (and Paul)

Robin Dunn wrote:

It's not a clipping region, but an update region,

Ahh! perhaps an editing of the docs is in order:

"""
Using wxPaintDC within OnPaint is important because it automatically sets the clipping area to the damaged area of the window. Attempts to draw outside this area do not appear.
"""

That text used the term Clipping, so that's where I was looking...

As Paul mentioned you can get the update region, and convert it to a rectangle that encloses all of the region with:

    rgn = self.GetUpdateRegion()
    box = rgn.GetBox()

Is there a way to set the Update Region?

If you want to always paint the whole window after resize events then you can use the wx.FULL_REPAINT_ON_RESIZE style when creating the window.

That's the solution I've chosen. Which brings up:

Is there a clean way to pass through all the style flags, while adding one? I've done this, but it just feels like too much code for Python:

class ScaleWindow(wx.Panel):
     def __init__(self, Colormap, *args, **kwargs):
         flags = kwargs.get('style', 0)
         flags |= wx.FULL_REPAINT_ON_RESIZE
         kwargs['style'] = flags

         wx.Panel.__init__(self, *args, **kwargs)

I looked for a AddStyle() method in wx.Window, but didn't find one.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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 Chris,

Is there a clean way to pass through all the style flags, while adding
one? I've done this, but it just feels like too much code for Python:

class ScaleWindow(wx.Panel):
    def __init__(self, Colormap, *args, **kwargs):
        flags = kwargs.get('style', 0)
        flags |= wx.FULL_REPAINT_ON_RESIZE
        kwargs['style'] = flags

        wx.Panel.__init__(self, *args, **kwargs)

I looked for a AddStyle() method in wx.Window, but didn't find one.

Maybe SetWindowStyleFlag(yourStyle) can do what you are asking for? I
don't know if wx.FULL_REPAINT_ON_RESIZE can be assigned even after
creation, but it's worth trying...

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.virgilio.it/infinity77/

Andrea Gavana wrote:

I looked for a AddStyle() method in wx.Window, but didn't find one.

Maybe SetWindowStyleFlag(yourStyle) can do what you are asking for? I
don't know if wx.FULL_REPAINT_ON_RESIZE can be assigned even after
creation,

No, apparently not, at least not on GTK. Darn. Thanks for the pointer, though. wx.Window has so many methods, I missed that one.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

Christopher Barker wrote:

Is there a clean way to pass through all the style flags, while adding one? I've done this, but it just feels like too much code for Python:

class ScaleWindow(wx.Panel):
    def __init__(self, Colormap, *args, **kwargs):
        flags = kwargs.get('style', 0)
        flags |= wx.FULL_REPAINT_ON_RESIZE
        kwargs['style'] = flags

        wx.Panel.__init__(self, *args, **kwargs)

I looked for a AddStyle() method in wx.Window, but didn't find one.

Given that you may or may not have specified flags in the original method, you have to do that set of tasks. But you can do it in one line if you want:

        # make sure the FULL_REPAINT_ON_RESIZE flag is on
        kwargs['style'] = kwargs.get('style', 0) | wx.FULL_REPAINT_ON_RESIZE

This may or may not feel "better" to you. Personally, I prefer it.

          Kent

···

--
------------------------------------------------------------
Kent Quirk I'm making a game about global warming.
Game Architect Track the progress at:
CogniToy cognitoy.com - Diese Website steht zum Verkauf! - Informationen zum Thema cognitoy.

Andrea Gavana wrote:

Hi Chris,

Is there a clean way to pass through all the style flags, while adding
one? I've done this, but it just feels like too much code for Python:

class ScaleWindow(wx.Panel):
    def __init__(self, Colormap, *args, **kwargs):
        flags = kwargs.get('style', 0)
        flags |= wx.FULL_REPAINT_ON_RESIZE
        kwargs['style'] = flags

        wx.Panel.__init__(self, *args, **kwargs)

I looked for a AddStyle() method in wx.Window, but didn't find one.

Maybe SetWindowStyleFlag(yourStyle) can do what you are asking for? I
don't know if wx.FULL_REPAINT_ON_RESIZE can be assigned even after
creation, but it's worth trying...

It can't. For example on MSW it chooses a different WndClass (a win32 api thing) for the window based on the value of this flag, so it can't be changed after the window has been created.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Christopher Barker wrote:

Thanks Robin (and Paul)

Robin Dunn wrote:

It's not a clipping region, but an update region,

Ahh! perhaps an editing of the docs is in order:

"""
Using wxPaintDC within OnPaint is important because it automatically sets the clipping area to the damaged area of the window. Attempts to draw outside this area do not appear.
"""

That text used the term Clipping, so that's where I was looking...

As Paul mentioned you can get the update region, and convert it to a rectangle that encloses all of the region with:

    rgn = self.GetUpdateRegion()
    box = rgn.GetBox()

Is there a way to set the Update Region?

I don't think so. You have to pass a rectangle to Refresh and wait for the next paint event to come through.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Kent Quirk wrote:

Given that you may or may not have specified flags in the original method, you have to do that set of tasks. But you can do it in one line if you want:

       # make sure the FULL_REPAINT_ON_RESIZE flag is on
       kwargs['style'] = kwargs.get('style', 0) | wx.FULL_REPAINT_ON_RESIZE

Yes, that's a bit cleaner. Thanks.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (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

Christopher Barker wrote:

Kent Quirk wrote:

Given that you may or may not have specified flags in the original method, you have to do that set of tasks. But you can do it in one line if you want:

       # make sure the FULL_REPAINT_ON_RESIZE flag is on
       kwargs['style'] = kwargs.get('style', 0) | wx.FULL_REPAINT_ON_RESIZE

Yes, that's a bit cleaner. Thanks.

One way this could fail is if all the parameters are passed by position. Then 'style' won't be in the kwargs, which your code will catch by using get with a default, but you will miss the value that's in args instead.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

       # make sure the FULL_REPAINT_ON_RESIZE flag is on
       kwargs['style'] = kwargs.get('style', 0) | wx.FULL_REPAINT_ON_RESIZE

One way this could fail is if all the parameters are passed by position. Then 'style' won't be in the kwargs, which your code will catch by using get with a default, but you will miss the value that's in args instead.

Darn. I always try to use keyward args, but that could be a problem. It seems that this would be a good thing for Python to have a standard way of dealing with. Or Maybe wxPython, as there arguments to wx.Window calls tend to be similar.

Another option, as style flags are really the key thing here, is to have a way to add a style flag in the constructor, before the Window gets created.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                          
NOAA/OR&R/HAZMAT (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