Drawing panel backgrounds with widgets visible on top

Hello,

1. How do you use an image as a frame or panel background, so that any already
existing wxwidgets (like statictext, buttons etc) dont get hidden under the
background image?

2. Is there a way to automatically center the image in the frame/panel, or do
you have to paint it manually at the correct position?

Thanks,
Frank

Hi Frank,

1. How do you use an image as a frame or panel background, so that any already
existing wxwidgets (like statictext, buttons etc) dont get hidden under the
background image?
2. Is there a way to automatically center the image in the frame/panel, or do
you have to paint it manually at the correct position?

I would try using wx.EVT_ERASE_BACKGROUND, something like this (self
is your panel):

self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase)

def OnErase(self, event):

    dc = event.GetDC()
    if not dc:
        dc = wx.ClientDC(self)

    panelSize = self.GetClientSize()
    bmpWidth, bmpHeight = self.theBitmap.GetWidth(), self.theBitmap.GetHeight()

    xPos = (panelSize.x - bmpWidth)/2
    yPos = (panelSize.y - bmpHeight)/2

    dc.DrawBitmap(xPos, yPos, self.theBitmap)

Absolutely untested and unchecked :smiley:

HTH.

Andrea.

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

···

On 10/17/07, Frank Aune wrote:

Sorry, DrawBitmap arguments are:

dc.DrawBitmap(self.theBitmap, xPos, yPos)

I am getting older :wink:

Andrea.

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

···

On 10/17/07, Andrea Gavana wrote:

Hi Frank,

On 10/17/07, Frank Aune wrote:
> 1. How do you use an image as a frame or panel background, so that any already
> existing wxwidgets (like statictext, buttons etc) dont get hidden under the
> background image?
> 2. Is there a way to automatically center the image in the frame/panel, or do
> you have to paint it manually at the correct position?

I would try using wx.EVT_ERASE_BACKGROUND, something like this (self
is your panel):

self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase)

def OnErase(self, event):

   dc = event.GetDC()
   if not dc:
       dc = wx.ClientDC(self)

   panelSize = self.GetClientSize()
   bmpWidth, bmpHeight = self.theBitmap.GetWidth(), self.theBitmap.GetHeight()

   xPos = (panelSize.x - bmpWidth)/2
   yPos = (panelSize.y - bmpHeight)/2

   dc.DrawBitmap(xPos, yPos, self.theBitmap)

Hello Andrea,

This actually worked almost perfect. Only problem is that the "old" background
image is not updated when resizing the application. Insted the old position
and the new position is meshed(?) together.

But when alt-tab'ing so the app window is hidden behind some other window and
re-focused again, it will display as it should.

I guess this require some sort of Update() command, but haven't found the
magic line yet :slight_smile:

-Frank

···

On Wednesday 17 October 2007 15:31:17 Andrea Gavana wrote:

On 10/17/07, Andrea Gavana wrote:
> I would try using wx.EVT_ERASE_BACKGROUND, something like this (self
> is your panel):
>
> self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase)
>
> def OnErase(self, event):
>
> dc = event.GetDC()
> if not dc:
> dc = wx.ClientDC(self)
>
> panelSize = self.GetClientSize()
> bmpWidth, bmpHeight = self.theBitmap.GetWidth(),
> self.theBitmap.GetHeight()
>
> xPos = (panelSize.x - bmpWidth)/2
> yPos = (panelSize.y - bmpHeight)/2
>
> dc.DrawBitmap(xPos, yPos, self.theBitmap)

You'll want the wx.FULL_REPAINT_ON_RESIZE flag when you're doing this
sort of full-area drawing.

···

On 10/17/07, Frank Aune <Frank.Aune@broadpark.no> wrote:

On Wednesday 17 October 2007 15:31:17 Andrea Gavana wrote:
> On 10/17/07, Andrea Gavana wrote:
> > I would try using wx.EVT_ERASE_BACKGROUND, something like this (self
> > is your panel):
> >
> > self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase)
> >
> > def OnErase(self, event):
> >
> > dc = event.GetDC()
> > if not dc:
> > dc = wx.ClientDC(self)
> >
> > panelSize = self.GetClientSize()
> > bmpWidth, bmpHeight = self.theBitmap.GetWidth(),
> > self.theBitmap.GetHeight()
> >
> > xPos = (panelSize.x - bmpWidth)/2
> > yPos = (panelSize.y - bmpHeight)/2
> >
> > dc.DrawBitmap(xPos, yPos, self.theBitmap)

Hello Andrea,

This actually worked almost perfect. Only problem is that the "old" background
image is not updated when resizing the application. Insted the old position
and the new position is meshed(?) together.

But when alt-tab'ing so the app window is hidden behind some other window and
re-focused again, it will display as it should.

I guess this require some sort of Update() command, but haven't found the
magic line yet :slight_smile:

-Frank

Just tried the code provided by Andrea on Win32, and it did not work as
expected on this plattform. I managed to tweak it slightly, but if I place
wx.StaticText labels into the panel where the background is painted, the
entire label area will block the image below.

On GNU/Linux this works as expected, and the area of the statictext labels
does not block the background image.

This is the semi-working code, which works 100% under GNU/Linux, but on win32
the area of statictext labels placed on top of the background will block the
underlying part of the background image:

···

On Wednesday 17 October 2007 16:11:01 Chris Mellon wrote:

You'll want the wx.FULL_REPAINT_ON_RESIZE flag when you're doing this
sort of full-area drawing.

---
def OnErase(self, event):
        dc = event.GetDC()
        if not dc or sys.platform == 'win32':
            dc = wx.ClientDC(self.panel)
        
        panelSize = self.panel.GetClientSize()

        bmpWidth, bmpHeight = self.theBitmap.GetWidth(),
self.theBitmap.GetHeight()
        xPos = (panelSize.x - bmpWidth)/2
        yPos = (panelSize.y - bmpHeight)/2
        dc.DrawBitmap(self.theBitmap, xPos, yPos)

        event.Skip()
---

I had to do an event.Skip() on win32, and create the dc object explicitly -
else the graphics was either totally screwed up, or the background image only
displayed shortly while resizing the window and then disappearing instantly
again.

If someone know what to do to fix this for win32, I would be very grateful. I
don't have access to a win32 computer and it's really hard to debug stuff
when you don't have access to the plattform and things just work on
GNU/Linux.

Thank you very much for valued feedback so far!

-Frank

Hi Frank,

> You'll want the wx.FULL_REPAINT_ON_RESIZE flag when you're doing this
> sort of full-area drawing.

Just tried the code provided by Andrea on Win32, and it did not work as
expected on this plattform. I managed to tweak it slightly, but if I place
wx.StaticText labels into the panel where the background is painted, the
entire label area will block the image below.

Well, I don't remember using wx.FULL_REPAINT_ON_RESIZE in my code, but
I may be wrong. I am doing exactly what you want inside
CustomTreeCtrl, which allows you to put an image as background of the
tree. As CustomTreeCtrl can hold any kind of widget in the tree nodes,
I would say that the approach I used should work also for you. You can
see what I did in this case by looking at the OnEraseBackground method
in CustomTreeCtrl.

Andrea.

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

···

On 10/18/07, Frank Aune wrote:

On Wednesday 17 October 2007 16:11:01 Chris Mellon wrote:

Frank Aune wrote:

You'll want the wx.FULL_REPAINT_ON_RESIZE flag when you're doing this
sort of full-area drawing.

Just tried the code provided by Andrea on Win32, and it did not work as expected on this plattform. I managed to tweak it slightly, but if I place wx.StaticText labels into the panel where the background is painted, the entire label area will block the image below.

Because on Windows the static text widget is a true window that has it's own background, etc.

On GNU/Linux this works as expected, and the area of the statictext labels does not block the background image.

Because there it is not a true window but is just drawn directly on the parent.

This is the semi-working code, which works 100% under GNU/Linux, but on win32 the area of statictext labels placed on top of the background will block the underlying part of the background image:
---
def OnErase(self, event):
        dc = event.GetDC()
        if not dc or sys.platform == 'win32':
            dc = wx.ClientDC(self.panel)
                panelSize = self.panel.GetClientSize()

        bmpWidth, bmpHeight = self.theBitmap.GetWidth(), self.theBitmap.GetHeight()
        xPos = (panelSize.x - bmpWidth)/2
        yPos = (panelSize.y - bmpHeight)/2
        dc.DrawBitmap(self.theBitmap, xPos, yPos)

        event.Skip()
---

I had to do an event.Skip() on win32, and create the dc object explicitly - else the graphics was either totally screwed up, or the background image only displayed shortly while resizing the window and then disappearing instantly again.

If someone know what to do to fix this for win32, I would be very grateful. I don't have access to a win32 computer and it's really hard to debug stuff when you don't have access to the plattform and things just work on GNU/Linux.

You can either draw the text yourself on the panel, or you can draw the background on the background of the static text too.

···

On Wednesday 17 October 2007 16:11:01 Chris Mellon wrote:

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

I ended up drawing both the background and the text with the Device Context,
and it works on both platforms yay! So thanks for the suggestion :slight_smile:

Only small annoyance was alot of flickering when resizing the window on win32.
I've seen people recommend using DoubleBuffering for this, but the small
attempts I did provided no improvements.

Based on the code sample provided by Andrea, how would that be extended with
double buffering to prevent flickering on win32?

Thanks,
Frank

···

On Friday 19 October 2007 07:21:35 Robin Dunn wrote:

You can either draw the text yourself on the panel, or you can draw the
background on the background of the static text too.

Frank Aune wrote:

···

On Friday 19 October 2007 07:21:35 Robin Dunn wrote:

You can either draw the text yourself on the panel, or you can draw the
background on the background of the static text too.

I ended up drawing both the background and the text with the Device Context, and it works on both platforms yay! So thanks for the suggestion :slight_smile:

Only small annoyance was alot of flickering when resizing the window on win32. I've seen people recommend using DoubleBuffering for this, but the small attempts I did provided no improvements.

Based on the code sample provided by Andrea, how would that be extended with double buffering to prevent flickering on win32?

Make a small runnable sample and we can comment better, but the key is to not clear the window and then draw. Do it all in as few steps as possible. Using a buffer bitmap enables you to do that as you first draw to the buffer then then move it to the screen in a single step.

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

Robin Dunn wrote:

Only small annoyance was alot of flickering when resizing the window on win32.

by default, Windows asks the app to re-paint itself constantly while the user is re-sizing the window. If it take a while to paint, then this will never look good, double buffering or not.

A little googling will help here, but the standard solution is to use a wx.Timer to delay the re-paint a bit, so it only happens when the user has stopped the re-size movement.

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

Another idea is to prevent the re-computation of things that stay the same.
I’ve recently discovered Trellis
http://peak.telecommunity.com/DevCenter/Trellis

It is amazing once you understand how it works…
Basically it does lazy evaluation and only computes things when elements that are involved change.

Peter

···

On 10/22/07, Christopher Barker Chris.Barker@noaa.gov wrote:

Robin Dunn wrote:

Only small annoyance was alot of flickering when resizing the window
on win32.

by default, Windows asks the app to re-paint itself constantly while the
user is re-sizing the window. If it take a while to paint, then this

will never look good, double buffering or not.

A little googling will help here, but the standard solution is to use a
wx.Timer to delay the re-paint a bit, so it only happens when the user
has stopped the re-size movement.

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


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.

Peter Damoc wrote:

Another idea is to prevent the re-computation of things that stay the same.

That's hard with re-sizing -- though at least if the window is getting smaller, there's no reason to re-paint -- if you're double buffering, you should be able to just blit when the window gets smaller -- that's N optimization I don't think I ever bothered with with FloatCanvas.

I've recently discovered Trellis
Trellis - The PEAK Developers' Center

whooa! very cool! Thanks for the tip.

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