how to draw the image in wx.BufferedDC on the page created by AddPage of wx.Notebook

Hi everyone,

I have tried two days to figure out how to draw the image in wx.BufferedDC on the page created by AddPage of wx.Notebook but still got no clue.

The attached example is based on the example on the site:

http://wiki.wxpython.org/index.cgi/DoubleBufferedDrawing

The key part of the code is gived below. As is, everything is fine if I click menu “Draw” --> “New Drawing”. The image can move around on the frame. But If I uncomment those three commented lines to add a new page (of wx.Notebook) with a tag and modify the last line like

self.Window = DrawWindow(form2)

I can not see the image from wx.BufferedDC anywhere
and don’t know what is going on.

I need your help. Thanks a lot.

#########################################3

class TestFrame(wx.Frame):
def init(self):
wx.Frame.init(self, None, -1, “Double Buffered Test”,
wx.DefaultPosition,
size=(500,500),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)

#nb = wx.Notebook(self, -1)
#form2 = Form2(nb, -1)
#nb.AddPage(form2, “Sizers”)

    self.Window = DrawWindow(self)

#####################################################3

Ouyang

double_buffer_test.zip (21.3 KB)

···

Talk is cheap. Use Yahoo! Messenger to make PC-to-Phone calls. Great rates starting at 1¢/min.

zxo102 wrote:

Hi everyone, I have tried two days to figure out how to draw the
image in wx.BufferedDC on the page created by AddPage of wx.Notebook
but still got no clue.

You problem has nothing to do with the BufferedWindow. Your issue is that when a Frame has only one child, the child is automatically fit to the Frame. wx.Notebooks don't do the same auto-sizing, so you were getting your window, but it was tiny and up in the corner.

In situations like this, it's always a good idea to reduce the problem to it's simplest -- try putting just a blank wx.panel or something on a Notebook, and see what happens.

I've enclosed a version of the code that sort of works -- it makes the Frame too small to begin with, but if you re-size it it should work.

To do this right, you'll need to use some Sizers.

I changed a couple things in the BufferedWindow code, to make passing parameters in cleaner, so I could pass in a size parameter when creating it. I also cleaned up a few style issues -- be sure to check out:

http://wiki.wxpython.org/index.cgi/wxPython_Style_Guide

I'm sorry that the BufferedWindow code doesn't conform to that style -- I haven't had the chance to change it. Feel free to go in and fix that up in the Wiki.

Here are some comments on a few other points:

class DrawWindow(BufferedWindow):
     def __init__(self, *args, **kwargs):
         BufferedWindow.__init__(self, parent, id)

There is no reason to create an __init__ that does nothing but call the superclass __init__ it will be called anyway.

         wx.Frame.__init__(self, None, -1, "Double Buffered Test",
                          wx.DefaultPosition,
                          size=(500,500),
                          style= wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)

if you use keyword parameters, you don't need the defaults.
I think wx.NO_FULL_REPAINT_ON_RESIZE is now default, so you can do this instead:
         wx.Frame.__init__(self, None,
                           title="Double Buffered Test",
                           size=(500,500)
                           )

     str = apply(os.path.join, tuple(path.split('/')))

you don't need apply:
str = os.path.join(*(path.split('/')))

The "*" means: pass this sequence in as the arguments.

     def __init__(self, parent, id,
                  pos = wx.DefaultPosition,
                  size = wx.DefaultSize,
                  style=wx.NO_FULL_REPAINT_ON_RESIZE):
         wx.Window.__init__(self, parent, id, pos, size, style)

It's much cleaner to just do the pass-through:

     def __init__(self, *args, **kwargs):
         wx.Window.__init__(self, *args, **kwargs)

-Chris

double_buffer_operation22.py (4.4 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

Hi Chris,

I really appreciate your help. It works now.

Ouyang

···

Christopher Barker Chris.Barker@noaa.gov wrote:

zxo102 wrote:

Hi everyone, I have tried two days to figure out how to draw the
image in wx.BufferedDC on the page created by AddPage of wx.Notebook
but still got no clue.

You problem has nothing to do with the BufferedWindow. Your issue is
that when a Frame has only one child, the child is automatically fit to
the Frame. wx.Notebooks don’t do the same auto-sizing, so you were
getting your window, but it was tiny and up in the corner.

In situations like this, it’s always a good idea to reduce the problem
to it’s simplest – try putting just a blank wx.panel or something on a
Notebook, and see what
happens.

I’ve enclosed a version of the code that sort of works – it makes the
Frame too small to begin with, but if you re-size it it should work.

To do this right, you’ll need to use some Sizers.

I changed a couple things in the BufferedWindow code, to make passing
parameters in cleaner, so I could pass in a size parameter when creating
it. I also cleaned up a few style issues – be sure to check out:

http://wiki.wxpython.org/index.cgi/wxPython_Style_Guide

I’m sorry that the BufferedWindow code doesn’t conform to that style –
I haven’t had the chance to change it. Feel free to go in and fix that
up in the Wiki.

Here are some comments on a few other points:

class DrawWindow(BufferedWindow):
def init(self, *args, **kwargs):
BufferedWindow.init(self, parent, id)

There is no reason to create an init that does nothing but call the
superclass init it will be called
anyway.

wx.Frame.init(self, None, -1, “Double Buffered Test”,
wx.DefaultPosition,
size=(500,500),
style= wx.DEFAULT_FRAME_STYLE |
wx.NO_FULL_REPAINT_ON_RESIZE)

if you use keyword parameters, you don’t need the defaults.
I think wx.NO_FULL_REPAINT_ON_RESIZE is now default, so you can do this
instead:
wx.Frame.init(self, None,
title=“Double Buffered Test”,
size=(500,500)
)

str = apply(os.path.join, tuple(path.split(‘/’)))

you don’t need apply:
str = os.path.join(*(path.split(‘/’)))

The “*” means: pass this sequence in as the arguments.

def init(self, parent, id,
pos = wx.DefaultPosition,
size = wx.DefaultSize,
style=wx.NO_FULL_REPAINT_ON_RESIZE):
wx.Window.init(self, parent, id, pos, size, style)

It’s much cleaner to just do the pass-through:

def init(self, *args, **kwargs):
wx.Window.init(self, *args,
**kwargs)

-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

-- coding: iso-8859-1 --#

#!/usr/bin/env python2.2

import wx
import random
import os,time

USE_BUFFERED_DC = 1

def opj(path):
“”“Convert paths to the platform-specific separator”“”
str = str = os.path.join(*path.split(‘/’))

HACK: on Linux, a leading / gets lost…

if path.startswith(‘/’):
str = ‘/’ + str
return str

class BufferedWindow(wx.Window):
def init(self, *args, **kwargs):
wx.Window.init(self, *args, **kwargs)

self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)

self.bmp0 = wx.Image(opj(‘image.bmp’), wx.BITMAP_TYPE_BMP)
self.bmp0.SetMask(True)
self.bmp =
self.bmp0.Rotate(1.1215, (50,10), True,None)
self.bmp = self.bmp.ConvertToBitmap()
self.x = 100
self.y = 100
self.angle = 0.0
self.OnSize(None)

def Draw(self,dc):
pass

def OnPaint(self, event):
if USE_BUFFERED_DC:
dc = wx.BufferedPaintDC(self, self._Buffer)
else:
dc = wx.PaintDC(self)
dc.DrawBitmap(self._Buffer,0,0)

def OnSize(self,event):
self.Width, self.Height = self.GetClientSizeTuple()
self._Buffer = wx.EmptyBitmap(self.Width, self.Height)
self.UpdateDrawing()

def SaveToFile(self,FileName,FileType):
self._Buffer.SaveFile(FileName,FileType)

def UpdateDrawing(self):
if USE_BUFFERED_DC:
dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
self.Draw(dc)
else:

update the buffer

dc = wx.MemoryDC()
dc.SelectObject(self._Buffer)

self.Draw(dc)

update the screen

wx.ClientDC(self).Blit(0, 0, self.Width, self.Height, dc, 0, 0)

class
DrawWindow(BufferedWindow):

def Draw(self, dc):
dc.BeginDrawing()
dc.SetBackground( wx.Brush(“White”) )
dc.Clear() # make sure you clear the bitmap!
bmp = self.bmp0.Rotate(self.angle, (self.x,self.y), True,None)
bmp = bmp.ConvertToBitmap()
dc.DrawBitmap(bmp, self.x,self.y, True)
dc.EndDrawing()

class TestFrame(wx.Frame):
def init(self):
wx.Frame.init(self, None,
title=“Double Buffered Test”,
size=(500,500)
)

Set up the MenuBar

MenuBar = wx.MenuBar()
file_menu = wx.Menu()
ID_EXIT_MENU = wx.NewId()
file_menu.Append(ID_EXIT_MENU, “E&xit”,“Terminate the program”)
self.Bind(wx.EVT_MENU, self.OnQuit, id=ID_EXIT_MENU)
MenuBar.Append(file_menu, “&File”)

draw_menu = wx.Menu()
ID_DRAW_MENU = wx.NewId()
draw_menu.Append(ID_DRAW_MENU, “&New Drawing”,“Update the Drawing Data”)
self.Bind(wx.EVT_MENU, self.NewDrawing, id=ID_DRAW_MENU)
BMP_ID =
wx.NewId()
draw_menu.Append(BMP_ID,‘&Save Drawing\tAlt-I’,‘’)
self.Bind(wx.EVT_MENU, self.SaveToFile, id=BMP_ID)
MenuBar.Append(draw_menu, “&Draw”)

self.SetMenuBar(MenuBar)

nb = wx.Notebook(self, -1)
form2 = Form2(nb, -1)
nb.AddPage(form2, “Sizers”)

#self.Window = DrawWindow(self)
self.Window = DrawWindow(form2, size=(400,400))

def OnQuit(self,event):
self.Close(True)

def NewDrawing(self,event):
if event==None:
self.Window.UpdateDrawing()
else:
self.Window.y = 100
for i in range(10):
time.sleep(1)
self.Window.y = self.Window.y + 5
self.Window.angle = self.Window.angle+0.1*1
self.Window.UpdateDrawing()

def SaveToFile(self,event):
dlg = wx.FileDialog(self, “Choose a file name to save the image as a PNG to”,
defaultDir = “”,
defaultFile = “”,
wildcard = “*.png”,
style=wx.SAVE)
if dlg.ShowModal() ==
wx.ID_OK:
self.Window.SaveToFile(dlg.GetPath(),wx.BITMAP_TYPE_PNG)
dlg.Destroy()

class Form2(wx.Panel):
def init(self, parent, id):
wx.Panel.init(self, parent, -1)

class DemoApp(wx.App):
def OnInit(self):
#wx.InitAllImageHandlers() # called so a PNG can be saved
frame = TestFrame()
frame.Show(True)

frame.NewDrawing(None)

self.SetTopWindow(frame)

return True

if name == “main”:
app = DemoApp(0)
app.MainLoop()


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


How low will we go? Check out Yahoo! Messenger’s low PC-to-Phone call rates.