Using OnTimer and OnPaint together

Hello,

I'd like to redraw some graphics at regular intervals for a dashboard
app, using OnTimer together with OnPaint. When running the example
code below, I get an error message "wxPaintDC may be created only in
EVT_PAINT handler!".

This is basically my first wxPython project - any help appreciated!

Thanks,
Kevin

import random
import wx
import time

# Using Ontimer and OnPaint together to redraw at scheduled intervals

# snippet modified from http://www.daniweb.com/code/snippet216648.html

class MyPanel(wx.Panel):
    """ class MyPanel creates a panel to draw on, inherits wx.Panel """
    def __init__(self, parent, id):
        # create a panel
        wx.Panel.__init__(self, parent, id)
        self.SetBackgroundColour("white")

        # start the paint event for DrawRectangle() and FloodFill()
        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.timer = wx.Timer(self)
        self.timer.Start(1000) # 1000 milliseconds = 1 second
        self.Bind(wx.EVT_TIMER, self.OnTimer)

    def OnTimer(self, evt):
        self.draw_rectangle()

    def OnPaint(self, evt):
        self.draw_rectangle()

    def draw_rectangle(self):

        """set up the device context (DC) for painting"""
        self.dc = wx.PaintDC(self)
        self.dc.Clear()
        self.dc.BeginDrawing()
        self.dc.SetPen(wx.Pen("BLACK",1))
        # draw a random rectangle ...

        # set random RGB color for brush
        r = random.randrange(256)
        g = random.randrange(256)
        b = random.randrange(256)
        self.dc.SetBrush(wx.Brush((r, g, b), wx.SOLID))
        # set random x, y, w, h for rectangle
        w = random.randint(10, width1/2)
        h = random.randint(10, height1/2)
        x = random.randint(0, width1 - w)
        y = random.randint(0, height1 - h)
        self.dc.DrawRectangle(x, y, w, h)

        self.dc.EndDrawing()
        # free up the device context now
        del self.dc

height1 = 350
width1 = 400

app = wx.PySimpleApp()
# create a window/frame, no parent, -1 is default ID
frame = wx.Frame(None, -1, "Draw a rectangle using Timer ...", size =
(width1, height1))
# call the derived class, -1 is default ID
MyPanel(frame,-1)
# show the frame
frame.Show(True)
# start the event loop
app.MainLoop()

Kevin Carlson wrote:

I'd like to redraw some graphics at regular intervals for a dashboard
app, using OnTimer together with OnPaint. When running the example
code below, I get an error message "wxPaintDC may be created only in
EVT_PAINT handler!".

right -- listen the message -- don't do that!

The right way to do what you want is to call:

def OnTimer(self, evt):
     self.Refresh()
     self.Update()

That will force a Paint event -- which can then handle in a Paint handler.

You can also use a wx.ClientDC, but these days it's considered better to do the above -- it lets the OS handle the timing of screen drawing itself.

Search through the Wiki for various examples of useing teh DCs.

Also, I don't know what you're doing, but you may want to check out:

wx.lib.floatcanvas

It handles a lot of the drawing details for you.

-Chris

···

This is basically my first wxPython project - any help appreciated!

Thanks,
Kevin

import random
import wx
import time

# Using Ontimer and OnPaint together to redraw at scheduled intervals

# snippet modified from wxPython DrawRectangle Experiment | DaniWeb

class MyPanel(wx.Panel):
    """ class MyPanel creates a panel to draw on, inherits wx.Panel """
    def __init__(self, parent, id):
        # create a panel
        wx.Panel.__init__(self, parent, id)
        self.SetBackgroundColour("white")

        # start the paint event for DrawRectangle() and FloodFill()
        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.timer = wx.Timer(self)
        self.timer.Start(1000) # 1000 milliseconds = 1 second
        self.Bind(wx.EVT_TIMER, self.OnTimer)

    def OnTimer(self, evt):
        self.draw_rectangle()

    def OnPaint(self, evt):
        self.draw_rectangle()

    def draw_rectangle(self):

        """set up the device context (DC) for painting"""
        self.dc = wx.PaintDC(self)
        self.dc.Clear()
        self.dc.BeginDrawing()
        self.dc.SetPen(wx.Pen("BLACK",1))
        # draw a random rectangle ...

        # set random RGB color for brush
        r = random.randrange(256)
        g = random.randrange(256)
        b = random.randrange(256)
        self.dc.SetBrush(wx.Brush((r, g, b), wx.SOLID))
        # set random x, y, w, h for rectangle
        w = random.randint(10, width1/2)
        h = random.randint(10, height1/2)
        x = random.randint(0, width1 - w)
        y = random.randint(0, height1 - h)
        self.dc.DrawRectangle(x, y, w, h)

        self.dc.EndDrawing()
        # free up the device context now
        del self.dc

height1 = 350
width1 = 400

app = wx.PySimpleApp()
# create a window/frame, no parent, -1 is default ID
frame = wx.Frame(None, -1, "Draw a rectangle using Timer ...", size =
(width1, height1))
# call the derived class, -1 is default ID
MyPanel(frame,-1)
# show the frame
frame.Show(True)
# start the event loop
app.MainLoop()

--
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

Kevin, You won't find this anywhere in the docs: Avoiding redraw
flicker may a big problem, but it's very platform-dependent. It has to
do with the underlying OS's particular graphics refresh system.

With MS Windows using a wx.PaintDC may cause a very annoying "flash"
or "flicker" on each redraw. I've had success using a wx.ClientDC
instead to draw at any time at all instead of a wx.PaintDC (only) on
OnPaint events. Other platforms get flicker if a wx.PaintDC is NOT
used ! I've read that using a wx.ClientDC or a
wx.BufferedDC( wx.ClientDC() ) might be the ticket there.

Always use a sub-class of wx.DC and not a wx.DC, itself. There are
(too) many subclassed DC's and almost no useful guidelines about which
one will work best for you. So, start by using a wx.PaintDC and if you
get redraw flicker try a wx.ClientDC. Keep experimenting until it
works right.

Ray

···

On Jul 16, 2:05 pm, Kevin Carlson <kevinlcarl...@gmail.com> wrote:

Hello,

I'd like to redraw some graphics at regular intervals for a dashboard
app, using OnTimer together with OnPaint. When running the example
code below, I get an error message "wxPaintDC may be created only in
EVT_PAINT handler!".

This is basically my first wxPython project - any help appreciated!

Thanks,
Kevin

import random
import wx
import time

# Using Ontimer and OnPaint together to redraw at scheduled intervals

# snippet modified fromhttp://www.daniweb.com/code/snippet216648.html

class MyPanel(wx.Panel):
""" class MyPanel creates a panel to draw on, inherits wx.Panel """
def __init__(self, parent, id):
# create a panel
wx.Panel.__init__(self, parent, id)
self.SetBackgroundColour("white")

    \# start the paint event for DrawRectangle\(\) and FloodFill\(\)
    self\.Bind\(wx\.EVT\_PAINT, self\.OnPaint\)

    self\.timer = wx\.Timer\(self\)
    self\.timer\.Start\(1000\) \# 1000 milliseconds = 1 second
    self\.Bind\(wx\.EVT\_TIMER, self\.OnTimer\)

def OnTimer\(self, evt\):
    self\.draw\_rectangle\(\)

def OnPaint\(self, evt\):
    self\.draw\_rectangle\(\)

def draw\_rectangle\(self\):

    &quot;&quot;&quot;set up the device context \(DC\) for painting&quot;&quot;&quot;
    self\.dc = wx\.PaintDC\(self\)
    self\.dc\.Clear\(\)
    self\.dc\.BeginDrawing\(\)
    self\.dc\.SetPen\(wx\.Pen\(&quot;BLACK&quot;,1\)\)
    \# draw a random rectangle \.\.\.

    \# set random RGB color for brush
    r = random\.randrange\(256\)
    g = random\.randrange\(256\)
    b = random\.randrange\(256\)
    self\.dc\.SetBrush\(wx\.Brush\(\(r, g, b\), wx\.SOLID\)\)
    \# set random x, y, w, h for rectangle
    w = random\.randint\(10, width1/2\)
    h = random\.randint\(10, height1/2\)
    x = random\.randint\(0, width1 \- w\)
    y = random\.randint\(0, height1 \- h\)
    self\.dc\.DrawRectangle\(x, y, w, h\)

    self\.dc\.EndDrawing\(\)
    \# free up the device context now
    del self\.dc

height1 = 350
width1 = 400

app = wx.PySimpleApp()
# create a window/frame, no parent, -1 is default ID
frame = wx.Frame(None, -1, "Draw a rectangle using Timer ...", size =
(width1, height1))
# call the derived class, -1 is default ID
MyPanel(frame,-1)
# show the frame
frame.Show(True)
# start the event loop
app.MainLoop()

Thanks for your help, guys! Coming from a VB background, I'm still
wrapping my head around things like when to use "self" as a parameter
or prefix, manually coding handler bindings, etc...

How about that "wxPython in Action" book - any good? Any other resources?

Thanks again,
Kevin

···

On 7/17/10, WinCrazy <pascor@verizon.net> wrote:

Kevin, You won't find this anywhere in the docs: Avoiding redraw
flicker may a big problem, but it's very platform-dependent. It has to
do with the underlying OS's particular graphics refresh system.

With MS Windows using a wx.PaintDC may cause a very annoying "flash"
or "flicker" on each redraw. I've had success using a wx.ClientDC
instead to draw at any time at all instead of a wx.PaintDC (only) on
OnPaint events. Other platforms get flicker if a wx.PaintDC is NOT
used ! I've read that using a wx.ClientDC or a
wx.BufferedDC( wx.ClientDC() ) might be the ticket there.

Always use a sub-class of wx.DC and not a wx.DC, itself. There are
(too) many subclassed DC's and almost no useful guidelines about which
one will work best for you. So, start by using a wx.PaintDC and if you
get redraw flicker try a wx.ClientDC. Keep experimenting until it
works right.

Ray

On Jul 16, 2:05 pm, Kevin Carlson <kevinlcarl...@gmail.com> wrote:

Hello,

I'd like to redraw some graphics at regular intervals for a dashboard
app, using OnTimer together with OnPaint. When running the example
code below, I get an error message "wxPaintDC may be created only in
EVT_PAINT handler!".

This is basically my first wxPython project - any help appreciated!

Thanks,
Kevin

import random
import wx
import time

# Using Ontimer and OnPaint together to redraw at scheduled intervals

# snippet modified fromhttp://www.daniweb.com/code/snippet216648.html

class MyPanel(wx.Panel):
""" class MyPanel creates a panel to draw on, inherits wx.Panel """
def __init__(self, parent, id):
# create a panel
wx.Panel.__init__(self, parent, id)
self.SetBackgroundColour("white")

    \# start the paint event for DrawRectangle\(\) and FloodFill\(\)
    self\.Bind\(wx\.EVT\_PAINT, self\.OnPaint\)

    self\.timer = wx\.Timer\(self\)
    self\.timer\.Start\(1000\) \# 1000 milliseconds = 1 second
    self\.Bind\(wx\.EVT\_TIMER, self\.OnTimer\)

def OnTimer\(self, evt\):
    self\.draw\_rectangle\(\)

def OnPaint\(self, evt\):
    self\.draw\_rectangle\(\)

def draw\_rectangle\(self\):

    &quot;&quot;&quot;set up the device context \(DC\) for painting&quot;&quot;&quot;
    self\.dc = wx\.PaintDC\(self\)
    self\.dc\.Clear\(\)
    self\.dc\.BeginDrawing\(\)
    self\.dc\.SetPen\(wx\.Pen\(&quot;BLACK&quot;,1\)\)
    \# draw a random rectangle \.\.\.

    \# set random RGB color for brush
    r = random\.randrange\(256\)
    g = random\.randrange\(256\)
    b = random\.randrange\(256\)
    self\.dc\.SetBrush\(wx\.Brush\(\(r, g, b\), wx\.SOLID\)\)
    \# set random x, y, w, h for rectangle
    w = random\.randint\(10, width1/2\)
    h = random\.randint\(10, height1/2\)
    x = random\.randint\(0, width1 \- w\)
    y = random\.randint\(0, height1 \- h\)
    self\.dc\.DrawRectangle\(x, y, w, h\)

    self\.dc\.EndDrawing\(\)
    \# free up the device context now
    del self\.dc

height1 = 350
width1 = 400

app = wx.PySimpleApp()
# create a window/frame, no parent, -1 is default ID
frame = wx.Frame(None, -1, "Draw a rectangle using Timer ...", size =
(width1, height1))
# call the derived class, -1 is default ID
MyPanel(frame,-1)
# show the frame
frame.Show(True)
# start the event loop
app.MainLoop()

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

Kevin Carlson wrote:

Thanks for your help, guys! Coming from a VB background, I'm still
wrapping my head around things like when to use "self" as a parameter
or prefix, manually coding handler bindings, etc...

How about that "wxPython in Action" book - any good?

yes.

Any other resources?

This list, the Wiki, and assorted Blogs -- Mike Driscoll's has some good stuff.

Though note something on the Wiki's "how to learn wxPython" page:

"First: Learn Python" -- you need to understand python OO structure to use wxPython -- so a little more work on general Python docs and tutorials is a good idea -- I like "Dive into Python", but there are lots of good ones.

-Chris

···

Thanks again,
Kevin

On 7/17/10, WinCrazy <pascor@verizon.net> wrote:

Kevin, You won't find this anywhere in the docs: Avoiding redraw
flicker may a big problem, but it's very platform-dependent. It has to
do with the underlying OS's particular graphics refresh system.

With MS Windows using a wx.PaintDC may cause a very annoying "flash"
or "flicker" on each redraw. I've had success using a wx.ClientDC
instead to draw at any time at all instead of a wx.PaintDC (only) on
OnPaint events. Other platforms get flicker if a wx.PaintDC is NOT
used ! I've read that using a wx.ClientDC or a
wx.BufferedDC( wx.ClientDC() ) might be the ticket there.

Always use a sub-class of wx.DC and not a wx.DC, itself. There are
(too) many subclassed DC's and almost no useful guidelines about which
one will work best for you. So, start by using a wx.PaintDC and if you
get redraw flicker try a wx.ClientDC. Keep experimenting until it
works right.

Ray

On Jul 16, 2:05 pm, Kevin Carlson <kevinlcarl...@gmail.com> wrote:

Hello,

I'd like to redraw some graphics at regular intervals for a dashboard
app, using OnTimer together with OnPaint. When running the example
code below, I get an error message "wxPaintDC may be created only in
EVT_PAINT handler!".

This is basically my first wxPython project - any help appreciated!

Thanks,
Kevin

import random
import wx
import time

# Using Ontimer and OnPaint together to redraw at scheduled intervals

# snippet modified fromhttp://www.daniweb.com/code/snippet216648.html

class MyPanel(wx.Panel):
    """ class MyPanel creates a panel to draw on, inherits wx.Panel """
    def __init__(self, parent, id):
        # create a panel
        wx.Panel.__init__(self, parent, id)
        self.SetBackgroundColour("white")

        # start the paint event for DrawRectangle() and FloodFill()
        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.timer = wx.Timer(self)
        self.timer.Start(1000) # 1000 milliseconds = 1 second
        self.Bind(wx.EVT_TIMER, self.OnTimer)

    def OnTimer(self, evt):
        self.draw_rectangle()

    def OnPaint(self, evt):
        self.draw_rectangle()

    def draw_rectangle(self):

        """set up the device context (DC) for painting"""
        self.dc = wx.PaintDC(self)
        self.dc.Clear()
        self.dc.BeginDrawing()
        self.dc.SetPen(wx.Pen("BLACK",1))
        # draw a random rectangle ...

        # set random RGB color for brush
        r = random.randrange(256)
        g = random.randrange(256)
        b = random.randrange(256)
        self.dc.SetBrush(wx.Brush((r, g, b), wx.SOLID))
        # set random x, y, w, h for rectangle
        w = random.randint(10, width1/2)
        h = random.randint(10, height1/2)
        x = random.randint(0, width1 - w)
        y = random.randint(0, height1 - h)
        self.dc.DrawRectangle(x, y, w, h)

        self.dc.EndDrawing()
        # free up the device context now
        del self.dc

height1 = 350
width1 = 400

app = wx.PySimpleApp()
# create a window/frame, no parent, -1 is default ID
frame = wx.Frame(None, -1, "Draw a rectangle using Timer ...", size =
(width1, height1))
# call the derived class, -1 is default ID
MyPanel(frame,-1)
# show the frame
frame.Show(True)
# start the event loop
app.MainLoop()

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

--
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

Thanks for your help, guys! Coming from a VB background, I'm still
wrapping my head around things like when to use "self" as a parameter
or prefix, manually coding handler bindings, etc...

I think VB's "this" is mostly equivalent with Python's "self"...if
that helps.

How about that "wxPython in Action" book - any good? Any other resources?

Thanks again,
Kevin

That book is great! It's by Robin, the guy who basically created
wxPython. The index isn't the best and it's kind of old, but most of
the information in it is still relevant.

···

On Jul 19, 12:19 pm, Kevin Carlson <kevinlcarl...@gmail.com> wrote:

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

I’d add ShowMeDo.com and search for wxPython related videos.

And don’t forget the wxPython demo, in case you haven’t been trying it.

···

On Mon, Jul 19, 2010 at 1:19 PM, Kevin Carlson kevinlcarlson@gmail.com wrote:

Thanks for your help, guys! Coming from a VB background, I’m still

wrapping my head around things like when to use “self” as a parameter

or prefix, manually coding handler bindings, etc…

How about that “wxPython in Action” book - any good? Any other resources?

Kevin,

How about that "wxPython in Action" book - any good?

Highly recommended!!!

Malcolm

Absolutely first, you need a good Python "bible".

I've been using "Python in a Nutshell" by Martelli and love it. It is
indispensable to me because it has all the basics and a good index.
Besides, I don't have a great memory so I keep referring to it
regularly. I scribble in the margins and the inside covers Python
usage "tricks" that I come across that aren't listed there (or any
other published book). I've permanently bookmarked the sections on the
built-ins os, sys, string, dictionary, os.path and shutil because I
use different their meithods over and over again.

Last week I picked up the 2nd edition (2006) (used paperback, "very
good" condition) for under twenty bucks, US, delivered, from Amazon to
a state in the the "lower 48".

···

--------------
I think of the wx "self" value as a reference to: "the instantiated wx
object that was created using this class definition". It's like the C+
+ class value "this" except that its name is better chosen. A more
descriptive name would have been "thisInstantiation", but that's too
long.

Ray Pasco

On Jul 19, 1:19 pm, Kevin Carlson <kevinlcarl...@gmail.com> wrote:

Thanks for your help, guys! Coming from a VB background, I'm still
wrapping my head around things like when to use "self" as a parameter
or prefix, manually coding handler bindings, etc...

How about that "wxPython in Action" book - any good? Any other resources?

Thanks again,
Kevin

On 7/17/10, WinCrazy <pas...@verizon.net> wrote:

> Kevin, You won't find this anywhere in the docs: Avoiding redraw
> flicker may a big problem, but it's very platform-dependent. It has to
> do with the underlying OS's particular graphics refresh system.

> With MS Windows using a wx.PaintDC may cause a very annoying "flash"
> or "flicker" on each redraw. I've had success using a wx.ClientDC
> instead to draw at any time at all instead of a wx.PaintDC (only) on
> OnPaint events. Other platforms get flicker if a wx.PaintDC is NOT
> used ! I've read that using a wx.ClientDC or a
> wx.BufferedDC( wx.ClientDC() ) might be the ticket there.

> Always use a sub-class of wx.DC and not a wx.DC, itself. There are
> (too) many subclassed DC's and almost no useful guidelines about which
> one will work best for you. So, start by using a wx.PaintDC and if you
> get redraw flicker try a wx.ClientDC. Keep experimenting until it
> works right.

> Ray

> On Jul 16, 2:05 pm, Kevin Carlson <kevinlcarl...@gmail.com> wrote:
>> Hello,

>> I'd like to redraw some graphics at regular intervals for a dashboard
>> app, using OnTimer together with OnPaint. When running the example
>> code below, I get an error message "wxPaintDC may be created only in
>> EVT_PAINT handler!".

>> This is basically my first wxPython project - any help appreciated!

>> Thanks,
>> Kevin

>> import random
>> import wx
>> import time

>> # Using Ontimer and OnPaint together to redraw at scheduled intervals

>> # snippet modified fromhttp://www.daniweb.com/code/snippet216648.html

>> class MyPanel(wx.Panel):
>> """ class MyPanel creates a panel to draw on, inherits wx.Panel """
>> def __init__(self, parent, id):
>> # create a panel
>> wx.Panel.__init__(self, parent, id)
>> self.SetBackgroundColour("white")

>> # start the paint event for DrawRectangle() and FloodFill()
>> self.Bind(wx.EVT_PAINT, self.OnPaint)

>> self.timer = wx.Timer(self)
>> self.timer.Start(1000) # 1000 milliseconds = 1 second
>> self.Bind(wx.EVT_TIMER, self.OnTimer)

>> def OnTimer(self, evt):
>> self.draw_rectangle()

>> def OnPaint(self, evt):
>> self.draw_rectangle()

>> def draw_rectangle(self):

>> """set up the device context (DC) for painting"""
>> self.dc = wx.PaintDC(self)
>> self.dc.Clear()
>> self.dc.BeginDrawing()
>> self.dc.SetPen(wx.Pen("BLACK",1))
>> # draw a random rectangle ...

>> # set random RGB color for brush
>> r = random.randrange(256)
>> g = random.randrange(256)
>> b = random.randrange(256)
>> self.dc.SetBrush(wx.Brush((r, g, b), wx.SOLID))
>> # set random x, y, w, h for rectangle
>> w = random.randint(10, width1/2)
>> h = random.randint(10, height1/2)
>> x = random.randint(0, width1 - w)
>> y = random.randint(0, height1 - h)
>> self.dc.DrawRectangle(x, y, w, h)

>> self.dc.EndDrawing()
>> # free up the device context now
>> del self.dc

>> height1 = 350
>> width1 = 400

>> app = wx.PySimpleApp()
>> # create a window/frame, no parent, -1 is default ID
>> frame = wx.Frame(None, -1, "Draw a rectangle using Timer ...", size =
>> (width1, height1))
>> # call the derived class, -1 is default ID
>> MyPanel(frame,-1)
>> # show the frame
>> frame.Show(True)
>> # start the event loop
>> app.MainLoop()

> --
> To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
> or visithttp://groups.google.com/group/wxPython-users?hl=en

You can easily get the same, or even worse, flicker using a ClientDC. It is not a magic bullet.

Flicker on MSW typically comes from two things. 1) Clearing the window before drawing, and 2) allowing partially completed drawing steps to be visible on the screen before the whole set of drawing operations is completed.

Number 1 can be eliminated by catching EVT_ERASE_BACKGROUND and doing nothing in the handler. This prevents the default handler from being called which will clear the widget. You should also be able to accomplish the same thing by calling theWindow.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) although it's not clear if that works on all platforms in 2.8. BTW, if you are not going to be drawing the entire contents of the window in your EVT_PAINT then you probably do not want to prevent the background from being cleared and you will need to deal with this differently.

Number 2 can be solved by using a double buffered drawing technique. Essentially you do all your drawing steps into a bitmap the same size as the window and then when you are all done you draw that bitmap to the screen. That way there are no partially completed drawing steps that are visible to the user, there is just one step that they can see and that is the completed drawing. There are a couple different approaches that can be used for double buffering. The first is to (re)create the bitmap each time you need to update the screen and draw the whole content to it each time and the throw it away when you are done with that paint event. The other is to keep the bitmap around and only update the parts of it that have changed. There are also some DC classes which derive from wx.MemoryDC that help you to do double buffered drawing: wx.BufferedDC and wx.BufferedPaintDC. There are some examples in the demo and the wiki.

···

On 7/17/10 9:59 AM, WinCrazy wrote:

Kevin, You won't find this anywhere in the docs: Avoiding redraw
flicker may a big problem, but it's very platform-dependent. It has to
do with the underlying OS's particular graphics refresh system.

With MS Windows using a wx.PaintDC may cause a very annoying "flash"
or "flicker" on each redraw. I've had success using a wx.ClientDC
instead to draw at any time at all instead of a wx.PaintDC (only) on
OnPaint events. Other platforms get flicker if a wx.PaintDC is NOT
used ! I've read that using a wx.ClientDC or a
wx.BufferedDC( wx.ClientDC() ) might be the ticket there.

Always use a sub-class of wx.DC and not a wx.DC, itself. There are
(too) many subclassed DC's and almost no useful guidelines about which
one will work best for you. So, start by using a wx.PaintDC and if you
get redraw flicker try a wx.ClientDC. Keep experimenting until it
works right.

--
Robin Dunn
Software Craftsman

Cool, advice direct from the author! :slight_smile:

Thanks to ALL for their good advice... I'll be looking into the
suggested reading and learning all that I can...

Take care,
Kevin

···

On 7/19/10, Robin Dunn <robin@alldunn.com> wrote:

On 7/17/10 9:59 AM, WinCrazy wrote:

Kevin, You won't find this anywhere in the docs: Avoiding redraw
flicker may a big problem, but it's very platform-dependent. It has to
do with the underlying OS's particular graphics refresh system.

With MS Windows using a wx.PaintDC may cause a very annoying "flash"
or "flicker" on each redraw. I've had success using a wx.ClientDC
instead to draw at any time at all instead of a wx.PaintDC (only) on
OnPaint events. Other platforms get flicker if a wx.PaintDC is NOT
used ! I've read that using a wx.ClientDC or a
wx.BufferedDC( wx.ClientDC() ) might be the ticket there.

Always use a sub-class of wx.DC and not a wx.DC, itself. There are
(too) many subclassed DC's and almost no useful guidelines about which
one will work best for you. So, start by using a wx.PaintDC and if you
get redraw flicker try a wx.ClientDC. Keep experimenting until it
works right.

You can easily get the same, or even worse, flicker using a ClientDC. It
is not a magic bullet.

Flicker on MSW typically comes from two things. 1) Clearing the window
before drawing, and 2) allowing partially completed drawing steps to be
visible on the screen before the whole set of drawing operations is
completed.

Number 1 can be eliminated by catching EVT_ERASE_BACKGROUND and doing
nothing in the handler. This prevents the default handler from being
called which will clear the widget. You should also be able to
accomplish the same thing by calling
theWindow.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) although it's not clear
if that works on all platforms in 2.8. BTW, if you are not going to be
drawing the entire contents of the window in your EVT_PAINT then you
probably do not want to prevent the background from being cleared and
you will need to deal with this differently.

Number 2 can be solved by using a double buffered drawing technique.
Essentially you do all your drawing steps into a bitmap the same size as
the window and then when you are all done you draw that bitmap to the
screen. That way there are no partially completed drawing steps that
are visible to the user, there is just one step that they can see and
that is the completed drawing. There are a couple different approaches
that can be used for double buffering. The first is to (re)create the
bitmap each time you need to update the screen and draw the whole
content to it each time and the throw it away when you are done with
that paint event. The other is to keep the bitmap around and only
update the parts of it that have changed. There are also some DC
classes which derive from wx.MemoryDC that help you to do double
buffered drawing: wx.BufferedDC and wx.BufferedPaintDC. There are some
examples in the demo and the wiki.

--
Robin Dunn
Software Craftsman
http://wxPython.org

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en