Newbie Confusion

After a couple days of trying to get this work, looking at the samples and demos included with wxPython, I think I'm ready to admit that I need some help.

I'm simply trying to make a silly program in wxPython as an introduction to using the system. I have learned that if I wish to draw abitrary things inside of a Window object, I have to use a DC. Specifically, a ClientDC (Or a PaintDC if I'm handling an EVT_PAINT event, which I'm not at the moment.).

I can't quite seem to get a ClientDC to actually draw anything. My script runs just fine, but only returns an empty window. In frustration, I have turned to simply creating a Frame and using a ClientDC to fill it with red, to similar effect.

What I've basically done is create a class which inherits from wx.Frame, and, in its __init__ function, I have defined a ClientDC and told it to fill the frame with red. Afterwards I simply create a PySimpleApp, instantiate an instance of the class, Show the Frame, and enter the MainLoop. My code looks like this.

import wx
    
class CCFrame(wx.Frame):
  def __init__(self, parent, id=-1):
    wx.Frame.__init__(self, parent, id=-1)
    
    dc = wx.ClientDC(self)
    dc.FloodFill(0,0,(255,0,0))

def main():
  CCApp = wx.PySimpleApp()
  MainFrame = CCFrame(None)
  MainFrame.Show(True)
  CCApp.MainLoop()
  
main()

I'm running this on an Intel Mac (MacOS X 10.4.9), with Python 2.4, and wxPython 2.8.4.0.

I just get a blank window. I'm going for a window filled with red. What's going wrong here? I've also tried experimenting with moving the DC usage out into the main loop before the MainLoop is entered (dc = wx.ClientDC(MainFrame), etc). Still doesn't work.

Is there something obvious I'm missing? What do I need to do to get the DC to actually draw something?

Am I doing something altogether wrong? is there a better/easier way to accomplish drawing an image in a window than using DCs?

Hi,

All drawing is done inside a Paint event handler.
There seam to be some kind of a problem with FoodFill (I never used it )
here is your sample tweaked a little bit to work (kinda) It uses a rectangle instead of the fill.

import wx

class CCFrame(wx.Frame):
def init(self, parent, id=-1):
wx.Frame.init(self, parent, id=-1)
self.Bind(wx.EVT_PAINT, self.OnPaint)

def OnPaint(self, evt):

    dc = wx.ClientDC(self)
    dc.DrawRectangle(10,10,20,20)
    # dc.FloodFill(0,0,(255,0,0))
    evt.Skip()

def main():
CCApp = wx.PySimpleApp()
MainFrame = CCFrame(None)

   MainFrame.Show(True)
   CCApp.MainLoop()

main()

···

On 6/25/07, Nekora <nekora@comcast.net > wrote:

After a couple days of trying to get this work, looking at the
samples and demos included with wxPython, I think I’m ready to admit

that I need some help.

I’m simply trying to make a silly program in wxPython as an
introduction to using the system. I have learned that if I wish to
draw abitrary things inside of a Window object, I have to use a DC.

Specifically, a ClientDC (Or a PaintDC if I’m handling an EVT_PAINT
event, which I’m not at the moment.).

I can’t quite seem to get a ClientDC to actually draw anything. My
script runs just fine, but only returns an empty window. In

frustration, I have turned to simply creating a Frame and using a
ClientDC to fill it with red, to similar effect.

What I’ve basically done is create a class which inherits from
wx.Frame, and, in its init function, I have defined a ClientDC

and told it to fill the frame with red. Afterwards I simply create a
PySimpleApp, instantiate an instance of the class, Show the Frame,
and enter the MainLoop. My code looks like this.

import wx

class CCFrame(wx.Frame):
def init(self, parent, id=-1):
wx.Frame.init(self, parent, id=-1)

            dc = wx.ClientDC(self)
            dc.FloodFill(0,0,(255,0,0))

def main():
CCApp = wx.PySimpleApp()
MainFrame = CCFrame(None)
MainFrame.Show(True)
CCApp.MainLoop()

main()

I’m running this on an Intel Mac (MacOS X 10.4.9
), with Python 2.4,
and wxPython 2.8.4.0.

I just get a blank window. I’m going for a window filled with red.
What’s going wrong here? I’ve also tried experimenting with moving

the DC usage out into the main loop before the MainLoop is entered
(dc = wx.ClientDC(MainFrame), etc). Still doesn’t work.

Is there something obvious I’m missing? What do I need to do to get
the DC to actually draw something?

Am I doing something altogether wrong? is there a better/easier way
to accomplish drawing an image in a window than using DCs?


To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org


There is NO FATE, we are the creators.

Also,
If you want to do the drawings outside the Paint Event you should use a wx.MemoryDC
like this:

import wx

class CCFrame(wx.Frame):
def init(self, parent, id=-1):
wx.Frame._init
_(self, parent, id=-1)

    bmp = wx.EmptyBitmap(100,100)
    dc = wx.MemoryDC(bmp)
    dc.DrawRectangle(10,10,20,20)
    # bmp.SaveFile("test.png", wx.BITMAP_TYPE_PNG)
    wx.StaticBitmap(self, -1, bmp)

def main():
CCApp = wx.PySimpleApp()
MainFrame = CCFrame(None)
MainFrame.Show(True)
CCApp.MainLoop()

main()

···

On 6/25/07, Nekora nekora@comcast.net wrote:

After a couple days of trying to get this work, looking at the
samples and demos included with wxPython, I think I’m ready to admit
that I need some help.

I’m simply trying to make a silly program in wxPython as an

introduction to using the system. I have learned that if I wish to
draw abitrary things inside of a Window object, I have to use a DC.
Specifically, a ClientDC (Or a PaintDC if I’m handling an EVT_PAINT

event, which I’m not at the moment.).

I can’t quite seem to get a ClientDC to actually draw anything. My
script runs just fine, but only returns an empty window. In
frustration, I have turned to simply creating a Frame and using a

ClientDC to fill it with red, to similar effect.

What I’ve basically done is create a class which inherits from
wx.Frame, and, in its init function, I have defined a ClientDC
and told it to fill the frame with red. Afterwards I simply create a

PySimpleApp, instantiate an instance of the class, Show the Frame,
and enter the MainLoop. My code looks like this.

import wx

class CCFrame(wx.Frame):
def init(self, parent, id=-1):

            wx.Frame.__init__(self, parent, id=-1)

            dc = wx.ClientDC(self)
            dc.FloodFill(0,0,(255,0,0))

def main():
CCApp = wx.PySimpleApp()
MainFrame = CCFrame(None)

    MainFrame.Show(True)
    CCApp.MainLoop()

main()

I’m running this on an Intel Mac (MacOS X 10.4.9), with Python 2.4,
and wxPython 2.8.4.0.

I just get a blank window. I’m going for a window filled with red.

What’s going wrong here? I’ve also tried experimenting with moving
the DC usage out into the main loop before the MainLoop is entered
(dc = wx.ClientDC(MainFrame), etc). Still doesn’t work.

Is there something obvious I’m missing? What do I need to do to get
the DC to actually draw something?

Am I doing something altogether wrong? is there a better/easier way
to accomplish drawing an image in a window than using DCs?


To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org

For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org


There is NO FATE, we are the creators.

Oh… and of course,
Welcome!

···

On 6/25/07, Nekora nekora@comcast.net wrote:

After a couple days of trying to get this work, looking at the
samples and demos included with wxPython, I think I’m ready to admit
that I need some help.

I’m simply trying to make a silly program in wxPython as an

introduction to using the system. I have learned that if I wish to
draw abitrary things inside of a Window object, I have to use a DC.
Specifically, a ClientDC (Or a PaintDC if I’m handling an EVT_PAINT

event, which I’m not at the moment.).

I can’t quite seem to get a ClientDC to actually draw anything. My
script runs just fine, but only returns an empty window. In
frustration, I have turned to simply creating a Frame and using a

ClientDC to fill it with red, to similar effect.

What I’ve basically done is create a class which inherits from
wx.Frame, and, in its init function, I have defined a ClientDC
and told it to fill the frame with red. Afterwards I simply create a

PySimpleApp, instantiate an instance of the class, Show the Frame,
and enter the MainLoop. My code looks like this.

import wx

class CCFrame(wx.Frame):
def init(self, parent, id=-1):

            wx.Frame.__init__(self, parent, id=-1)

            dc = wx.ClientDC(self)
            dc.FloodFill(0,0,(255,0,0))

def main():
CCApp = wx.PySimpleApp()
MainFrame = CCFrame(None)

    MainFrame.Show(True)
    CCApp.MainLoop()

main()

I’m running this on an Intel Mac (MacOS X 10.4.9), with Python 2.4,
and wxPython 2.8.4.0.

I just get a blank window. I’m going for a window filled with red.

What’s going wrong here? I’ve also tried experimenting with moving
the DC usage out into the main loop before the MainLoop is entered
(dc = wx.ClientDC(MainFrame), etc). Still doesn’t work.

Is there something obvious I’m missing? What do I need to do to get
the DC to actually draw something?

Am I doing something altogether wrong? is there a better/easier way
to accomplish drawing an image in a window than using DCs?


To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org

For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org


There is NO FATE, we are the creators.

Thanks very much for your help! However, I still have a couple problems.

When, exactly, is an EVT_PAINT event sent? Is a regular thing called every frame? When the window knows that something inside it has changed?

The second piece of code you sent me seems to work (It displays a white square).

The first one, though, still returns a blank window for me. I'm not sure if it's a problem with the Mac version of wxPython or what. But nothing is ever drawn in the window.

However, the second piece of code is not of use to me, because for the application I want to write for practice, the bitmap needs to be changable. (The bitmap is going to change states in response to user input) So the StaticBitmap widget doesn't do it for me. I suppose that I could destroy and create a StaticBitmap every time it needs to change, but is there a better way to accomplish a bitmap that gets redrawn/updated when I need it to?

Hi,

When, exactly, is an EVT_PAINT event sent? Is a regular thing called
every frame? When the window knows that something inside it has
changed?

Usually, EVT_PAINT events are sent when a window is first exposed, or
some part of it has been covered/uncovered by other windows, when
minimizing/maximizing it, or by explicitly calling Refresh()/Update()
on your window.

The second piece of code you sent me seems to work (It displays a
white square).

The first one, though, still returns a blank window for me. I'm not
sure if it's a problem with the Mac version of wxPython or what. But
nothing is ever drawn in the window.

I don't think it's a Mac problem; in the code Peter sent to you:

class CCFrame(wx.Frame):
    def __init__(self, parent, id=-1):
        wx.Frame.__init__(self, parent, id=-1)
        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, evt):

        dc = wx.ClientDC(self)
        dc.DrawRectangle(10,10,20,20)
        # dc.FloodFill(0,0,(255,0,0))
        evt.Skip()

def main():
       CCApp = wx.PySimpleApp()
       MainFrame = CCFrame(None)
       MainFrame.Show(True)
       CCApp.MainLoop()

main()

Try to use wx.PaintDC(self) instead of wx.ClientDC(self) inside the
OnPaint event handler. It should work.

However, the second piece of code is not of use to me, because for
the application I want to write for practice, the bitmap needs to be
changable. (The bitmap is going to change states in response to user
input) So the StaticBitmap widget doesn't do it for me. I suppose
that I could destroy and create a StaticBitmap every time it needs to
change, but is there a better way to accomplish a bitmap that gets
redrawn/updated when I need it to?

Yes, use something like double-buffering to avoid flickering:

self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

def OnPaint(self, event):

    dc = wx.BufferedPaintDC(self)
    # do lots of drawings

def OnEraseBackground(self, event):

    # leave the handler *empty*
    pass

HTH.

Andrea.

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

···

On 6/25/07, Nekora wrote:

Try to use wx.PaintDC(self) instead of wx.ClientDC(self) inside the
OnPaint event handler. It should work.

Actually, I had noticed that and tried changing it. Still no dice.

It seems that the DC just...isn't doing anything for some reason. I'm not quite sure why. Checking to see if the OnPaint method (By adding a print 'Painted' line into there) was ever called, shows that it is, in fact being called. But the dc stuff just isn't doing anything.

Is there some problem with how the OnPaint method is creating the DC and calling the DC's DrawRectangle method?

Sorry, my bad… on windows it works with the ClientDC BUT, just as Andrea pointed out you should use the PaintDC.

My advice is to create the code that renders your data inside the paint event handler and simply call frame.Refresh() whenever the data changes, or, if realtime is not all that important, use a timer that fires periodically and calls frame.Refresh() (Refresh will cause the frame to redraw)

Peter.

···

On 6/25/07, Nekora nekora@comcast.net wrote:

Thanks very much for your help! However, I still have a couple
problems.

When, exactly, is an EVT_PAINT event sent? Is a regular thing called
every frame? When the window knows that something inside it has

changed?

The second piece of code you sent me seems to work (It displays a
white square).

The first one, though, still returns a blank window for me. I’m not
sure if it’s a problem with the Mac version of wxPython or what. But

nothing is ever drawn in the window.

However, the second piece of code is not of use to me, because for
the application I want to write for practice, the bitmap needs to be
changable. (The bitmap is going to change states in response to user

input) So the StaticBitmap widget doesn’t do it for me. I suppose
that I could destroy and create a StaticBitmap every time it needs to
change, but is there a better way to accomplish a bitmap that gets

redrawn/updated when I need it to?


To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org

For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org


There is NO FATE, we are the creators.

Hi,

···

On 6/25/07, Nekora wrote:

>
> Try to use wx.PaintDC(self) instead of wx.ClientDC(self) inside the
> OnPaint event handler. It should work.

Actually, I had noticed that and tried changing it. Still no dice.

It seems that the DC just...isn't doing anything for some reason.
I'm not quite sure why. Checking to see if the OnPaint method (By
adding a print 'Painted' line into there) was ever called, shows that
it is, in fact being called. But the dc stuff just isn't doing
anything.

Is there some problem with how the OnPaint method is creating the DC
and calling the DC's DrawRectangle method?

Not that I know of. By the way, have you tried to remove the
event.Skip() at the end of the OnPaint handler? If this still doesn't
work, then I really need to get a cup of coffee this morning :smiley:

Andrea.

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

Not that I know of. By the way, have you tried to remove the
event.Skip() at the end of the OnPaint handler? If this still doesn't
work, then I really need to get a cup of coffee this morning :smiley:

And that did it! Thanks for the help. I'll have to look up exactly what event.Skip does just to make sure I don't do that improperly myself.

Thanks again!

Just out of curiosity, is there any way at all to do drawing outside of an event handler for EVT_PAINT?

Looking at the documentation, it appears that ClientDC -ought- to be able to paint on a window at any time, outside of an event handler, but it seems to be broken, from what you guys have told me. Now that I got the PaintDC working inside of the event handler, ClientDCs outside of it just don't want to work at all.

Is ClientDC's documentation just wrong? (As in, It cannot actually paint on a window outside of an event handler?)

Hi,

Just out of curiosity, is there any way at all to do drawing outside
of an event handler for EVT_PAINT?

Looking at the documentation, it appears that ClientDC -ought- to be
able to paint on a window at any time, outside of an event handler,
but it seems to be broken, from what you guys have told me. Now that
I got the PaintDC working inside of the event handler, ClientDCs
outside of it just don't want to work at all.

Is ClientDC's documentation just wrong? (As in, It cannot actually
paint on a window outside of an event handler?)

No, wx.ClientDC just works. It really depends on what you need to do
with your painting things. I mean, wx.ClientDC can be used wherever
you want (inside a timer event handler, an idle event handler, calling
it yourself, etc...). obviously, it will work *after* a window is
exposed, so it's pretty useless to call it in the __init__ method to
do drawings. There are some examples in the wxPython demo, and you
might find a good reference of the wx.ClientDC use in the wx.lib
custom controls (i.e., FlatNotebook uses a lot of wx.ClientDC).
However, if you are having problems, please post your code and I am
sure someone will help you :smiley:

Andrea.

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

···

On 6/25/07, Nekora wrote:

Nekora wrote:

Not that I know of. By the way, have you tried to remove the
event.Skip() at the end of the OnPaint handler? If this still doesn't
work, then I really need to get a cup of coffee this morning :smiley:

And that did it! Thanks for the help. I'll have to look up exactly what event.Skip does just to make sure I don't do that improperly myself.

It tells the event system to act as if no event binding was found and to keep looking for a handler. In this case on Mac that causes the default paint handler for the widget to still be called, which will overwrite the drawing that you did.

···

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

Andrea Gavana wrote:

Hi,

Just out of curiosity, is there any way at all to do drawing outside
of an event handler for EVT_PAINT?

Looking at the documentation, it appears that ClientDC -ought- to be
able to paint on a window at any time, outside of an event handler,
but it seems to be broken, from what you guys have told me. Now that
I got the PaintDC working inside of the event handler, ClientDCs
outside of it just don't want to work at all.

Is ClientDC's documentation just wrong? (As in, It cannot actually
paint on a window outside of an event handler?)

No, wx.ClientDC just works. It really depends on what you need to do
with your painting things. I mean, wx.ClientDC can be used wherever
you want (inside a timer event handler, an idle event handler, calling
it yourself, etc...). obviously, it will work *after* a window is
exposed, so it's pretty useless to call it in the __init__ method to
do drawings. There are some examples in the wxPython demo, and you
might find a good reference of the wx.ClientDC use in the wx.lib
custom controls (i.e., FlatNotebook uses a lot of wx.ClientDC).
However, if you are having problems, please post your code and I am
sure someone will help you :smiley:

Actually there have been recent changes on Mac that influence wx.ClientDC. Since wxMac is now using the CoreGrpahics library it is best to do all drawing from EVT_PAINT handlers because of how the CG drawing pipeline works. In order to make wx.ClientDC drawing work it has to drop anything that is currently in the pipeline, do an out-of-order draw, and then restart the pipeline. This imposes a lot of overhead, and often still doesn't work depending on if the pipeline will overdraw what was just drawn with the wx.ClientDC anyway.

So instead of using wx.ClientDC for drawing (measuring text extents and such is still ok) you're much better off to just change some internal program state and call Refresh and wait to do the drawing in the EVT_PAINT handler. Another approach that works well is to use a bitmap buffer and draw to it for your out-of-order drawing. Then your EVT_PAINT handler just needs to draw the bitmap.

···

On 6/25/07, Nekora wrote:

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