wxFrame or wxPanel with bitmap background?

1,956 views
Skip to first unread message

Chris MacGregor

unread,
Dec 18, 2012, 8:29:25 PM12/18/12
to wx-u...@googlegroups.com
Hi.

What I'm trying to accomplish (for an embedded device, using wxWidgets
2.9.4 on Linux) is a full-screen app, with a bitmap (e.g. wxStaticBitmap
or similar) background behind everything (all controls).

It doesn't seem to be possible to accomplish this using sizers (at least
not for the background part). I've experimented a bit, and found that
if I simply add the wxStaticBitmap directly to my wxPanel, and then put
all the controls in the wxPanel's sizer, it appears to work as I would
hope. However, the order of operations is important - not surprisingly,
if I add the wxStaticBitmap last, it winds up on top of most of the
controls, which of course is not what I want. So I need to add the
bitmap before all the controls. Unfortunately, I'm using wxFormBuilder
(nice tool!), which doesn't seem to provide a convenient way to
accomplish that, although I can think of several hacks to work around it.

I looked into control of z-order of children within a window, and found
several messages indicating quite clearly that overlapping child windows
are not supported. So maybe even if it appears to work, it won't
necessarily be reliable, or consistent across version or OS changes.
Well...okay, that's fine, but then how do I do what I'm trying to do?
What is the right solution here?

I did try adding the wxStaticBitmap to a wxFrame, and then creating a
separate wxPanel (the same size) with all the controls, and putting that
on top of the wxFrame, with a transparent background, intending that the
background show through everywhere that there isn't a control.
Unfortunately, there doesn't seem to be any such thing as a transparent
background.

There is a "right" way to do this, I imagine. What is it?

Thanks,
Chris

Vadim Zeitlin

unread,
Dec 18, 2012, 8:35:12 PM12/18/12
to wx-u...@googlegroups.com
On Tue, 18 Dec 2012 17:29:25 -0800 Chris MacGregor wrote:

CM> What I'm trying to accomplish (for an embedded device, using wxWidgets
CM> 2.9.4 on Linux) is a full-screen app, with a bitmap (e.g. wxStaticBitmap
CM> or similar) background behind everything (all controls).

See http://docs.wxwidgets.org/trunk/classwx_custom_background_window.html

CM> What is the right solution here?

Drawing the bitmap on the panel itself, as the class above does.

Regards,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/

Chris MacGregor

unread,
Dec 18, 2012, 9:13:20 PM12/18/12
to wx-u...@googlegroups.com

On 12/18/2012 05:35 PM, Vadim Zeitlin wrote:
> On Tue, 18 Dec 2012 17:29:25 -0800 Chris MacGregor wrote:
>
> CM> What I'm trying to accomplish (for an embedded device, using wxWidgets
> CM> 2.9.4 on Linux) is a full-screen app, with a bitmap (e.g. wxStaticBitmap
> CM> or similar) background behind everything (all controls).
>
> See http://docs.wxwidgets.org/trunk/classwx_custom_background_window.html
>
> CM> What is the right solution here?
>
> Drawing the bitmap on the panel itself, as the class above does.

Aha, that looks like exactly what I need (for this and a related thing -
how to draw text atop a different graphic element) - thank you!!

Cheers,
Chris

Hector

unread,
Dec 19, 2012, 6:25:24 PM12/19/12
to wx-u...@googlegroups.com
> See http://docs.wxwidgets.org/trunk/classwx_custom_background_window.html

This page says "the erase sample shows how to use it with wxScrolledWindow", but are you aware that with wxMSW and latest SVN, the erase sample gives awful results as soon as you scroll the window ? And it's even worse if you check the menu "File->Us background bitmap".

Vadim Zeitlin

unread,
Dec 20, 2012, 5:21:01 PM12/20/12
to wx-u...@googlegroups.com
On Wed, 19 Dec 2012 15:25:24 -0800 (PST) Hector wrote:

H> > See http://docs.wxwidgets.org/trunk/classwx_custom_background_window.html
H>
H> This page says "the erase sample shows how to use it with
H> wxScrolledWindow", but are you aware that with wxMSW and latest SVN, the
H> erase sample gives awful results as soon as you scroll the window ?

No, I didn't know it, but now that I tested, I can confirm this. Would you
know if this has ever worked correctly with wxScrolledWindow before (and if
so, what is the latest version in which it worked) or was it always broken?

Thanks,

Hector

unread,
Dec 20, 2012, 6:13:44 PM12/20/12
to wx-u...@googlegroups.com
> Would you know if this has ever worked correctly
> with wxScrolledWindow before

Nope, it has never worked, and it doesn't work on Mac either.

I know I should have created a bug report, but I'm sorry I was terribly busy.

Vadim Zeitlin

unread,
Dec 21, 2012, 7:19:25 PM12/21/12
to wx-u...@googlegroups.com
On Thu, 20 Dec 2012 15:13:44 -0800 (PST) Hector wrote:

H> > Would you know if this has ever worked correctly
H> > with wxScrolledWindow before
H>
H> Nope, it has never worked, and it doesn't work on Mac either.

I've created http://trac.wxwidgets.org/ticket/14917 for this but the
trouble is that it's not even just about custom backgrounds, scrolling is
broken when wxBG_STYLE_ERASE is used even without it and I'm almost sure
that at least this must have worked before. If anybody knows/remembers/can
bisect to find out which change broke this, I'd really like to hear about
it.

Regards,

Hector

unread,
Dec 22, 2012, 6:35:43 AM12/22/12
to wx-u...@googlegroups.com
Thank you very much, Vadim.

Unfortunately, I don't have the answer to your question.

Chris MacGregor

unread,
Dec 28, 2012, 2:26:26 AM12/28/12
to wx-u...@googlegroups.com, Vadim Zeitlin
On 12/18/2012 05:35 PM, Vadim Zeitlin wrote:
> On Tue, 18 Dec 2012 17:29:25 -0800 Chris MacGregor wrote:
>
> CM> What I'm trying to accomplish (for an embedded device, using wxWidgets
> CM> 2.9.4 on Linux) is a full-screen app, with a bitmap (e.g. wxStaticBitmap
> CM> or similar) background behind everything (all controls).
>
> See http://docs.wxwidgets.org/trunk/classwx_custom_background_window.html
>
> CM> What is the right solution here?
>
> Drawing the bitmap on the panel itself, as the class above does.

Hello again. Okay, wxCustomBackgroundWindow does seem to address this
(although I haven't tried it on Mac or Windows yet; apparently that's
not going to be pretty), although it's a bit finicky w.r.t. ordering of
operations and class hierarchy, such that in order to use it with
wxformbuilder-generated classes I had to use a gross hack involving
#define-ing wxPanel to wxPanelWithBackground and introducing "class
wxPanelWithBackground : public wxCustomBackgroundWindow <wxPanel>"...

However, there's a bit more to it. What I'm trying to build is a UI
wherein there is a constant top status bar (sorry, not a wxStatusBar,
just a little horizontal sizer with a clock and a battery icon and such)
and a constant bitmap background, and then various different pages
(sets, arrangements, etc.) of buttons and other controls. Imagine a
main menu page with a bunch of buttons, and when you click one the main
menu disappears and other buttons and controls appear, and so on across
many such pages. The only thing that is the same across all these pages
is the top status bar and the background.

I expected to be able to create a wxFrame with the top status bar and
the background, and then swap the various other pages in and out with
just one or two operations - hiding/showing or adding/removing a panel
or sizer or whatever. However, I've run into a few issues:

1. I can't put the background on the wxFrame (at least, not if I want to
use wxPanel for the pages), because the wxPanel's background covers up
the wxFrame's bitmap background. So apparently I would need to
separately put the background on each such wxPanel (each page in the
UI). Yuck. Do-able, yes, but yuck. I'm assuming I can at least share
the wxBitmap used for the purpose and the memory won't be consumed 30x
for 30 pages - if not, that's a big problem, because this is an embedded
device with limited RAM. It would be much better if I could just put
the background on one wxFrame and swap controls in and out of the frame
in groups (contained in a sizer would be fine, but then I think I'd run
into the issue in #3, below).

2. I tried using Hide() and Show() on the wxPanels containing the pages
of controls. There seems to be some kind of bug (or else I'm doing
something stupid, but this part is pretty straightforward, and I don't
see much I could be doing wrong), because when I hide one such panel and
show the other (both having been added to a sizer which also contains
the top status bar, or to a separate sizer added to the top level sizer
- it happens either way), showing the panel which was not originally
shown causes the top status bar to be hidden (as if I told it to hide
the whole sizer or something). OTOH, this is currently inside a
wxScrolledWindow ... hmmm. (Checking...) Well, okay, when I eliminate
the wxScrolledWindow (which is only used when simulating the device
target on a Linux desktop or Mac/Windows machine), that problem goes
away. So I guess this is related to the problem Hector noted - never mind.

3. I tried using Detach() and Add() to remove one panel (page of
controls) from the sizer and add another, but that seemed to just not
work. I'm guessing it's because I have a wxPanel that is a child of the
wxFrame but isn't included in the wxFrame's sizer, and as a result the
wxPanel that isn't in the sizer just gets displayed always, at (0,0).
So apparently this is not the right way to do things. (I'm a little
more accustomed to the GTK+ approach, wherein the VBoxes and HBoxes
(their sizers) are first-class controls, rather than completely
different objects.)

Overall, I'm getting the distinct impression that there should be - and
probably is - a "better" and easier way to accomplish what I'm trying to
do. Any clues would be appreciated.

Again, I just want an easy way to change out sets of controls in the
middle of the wxFrame en masse, ideally while maintaining a bitmap
background behind everything. The erase sample doesn't provide much
guidance for my problem, and it's the only sample that uses
wxCustomBackgroundWindow. The various BookCtrl flavors don't seem
suitable, because there shouldn't be an explicit page selector (tabs or
a listbox or anything of the sort). I don't see any other samples or
classes which seem to address the kind of thing I'm trying to do,
although it doesn't seem so unusual to me...but I may have overlooked a
relevant item, or overestimated the typical-ness of my application.

Happy holidays, and many thanks for any help,
Chris MacGregor (in Seattle, WA, USA)

Steve Barnes

unread,
Dec 28, 2012, 3:31:02 AM12/28/12
to wx-u...@googlegroups.com
Hi Chris,
Try something like the following, (extremely psudo-code):
#UI Structure
Frame:
   Panel with Bitmap on it:
       TopSizer (wxBoxSizer(VERTICAL)):
           TopOfScreenControls # Probably in a sizer of their own
           Page1Sizer:
               Page1 Controls
           Page2Sizer:
               Page2 Controls
           BottomOfScreenControls # Probably in a sizer of their own

OnSelectPage(Page):
    for page in pages:
         PageSizer.show(page == Page)
    # May need to call TopSizer.layout()

You will then have I panel with one bitmap and the top and bottom controls showing and a single sizer of page controls shown at any one time.

--
Steve Gadget Barnes

Chris MacGregor

unread,
Dec 28, 2012, 5:50:31 PM12/28/12
to wx-u...@googlegroups.com, Steve Barnes
On 12/28/2012 12:31 AM, Steve Barnes wrote:
On 28/12/12 07:26, Chris MacGregor wrote:
...

However, there's a bit more to it.  What I'm trying to build is a UI wherein there is a constant top status bar (sorry, not a wxStatusBar, just a little horizontal sizer with a clock and a battery icon and such) and a constant bitmap background, and then various different pages (sets, arrangements, etc.) of buttons and other controls.  Imagine a main menu page with a bunch of buttons, and when you click one the main menu disappears and other buttons and controls appear, and so on across many such pages.  The only thing that is the same across all these pages is the top status bar and the background.

I expected to be able to create a wxFrame with the top status bar and the background, and then swap the various other pages in and out with just one or two operations - hiding/showing or adding/removing a panel or sizer or whatever.  However, I've run into a few issues:

...

Overall, I'm getting the distinct impression that there should be - and probably is - a "better" and easier way to accomplish what I'm trying to do.  Any clues would be appreciated.

Again, I just want an easy way to change out sets of controls in the middle of the wxFrame en masse, ideally while maintaining a bitmap background behind everything.  The erase sample doesn't provide much guidance for my problem, and it's the only sample that uses wxCustomBackgroundWindow.  The various BookCtrl flavors don't seem suitable, because there shouldn't be an explicit page selector (tabs or a listbox or anything of the sort).  I don't see any other samples or classes which seem to address the kind of thing I'm trying to do, although it doesn't seem so unusual to me...but I may have overlooked a relevant item, or overestimated the typical-ness of my application.

Hi Chris,
Try something like the following, (extremely psudo-code):
#UI Structure
Frame:
   Panel with Bitmap on it:
       TopSizer (wxBoxSizer(VERTICAL)):
           TopOfScreenControls # Probably in a sizer of their own
           Page1Sizer:
               Page1 Controls
           Page2Sizer:
               Page2 Controls
           BottomOfScreenControls # Probably in a sizer of their own

OnSelectPage(Page):
    for page in pages:
         PageSizer.show(page == Page)
    # May need to call TopSizer.layout()

You will then have I panel with one bitmap and the top and bottom controls showing and a single sizer of page controls shown at any one time.

Thanks.  I think I considered that at one point, but rejected it because of what I observed (which later turned out to apparently be wxScrolled-related bugs).

There isn't a wxSizer::Show(bool) method, but I can do TopSizer.Hide(Page1Sizer, true), where the 'true' indicates a recursive hide.  With that tweak, the approach you suggested does work, on Linux/GTK+, Mac/Cocoa, and Win7.  (No noticeable issues with scrolling, either. ??)

As I play with this approach, though, I run into a couple of issues:

A. It makes it hard to use wxFormBuilder to do the layout, unless I do hacky post-processing of the generated code - that's do-able, though, and Perl is very good at that sort of thing.

B. I guess I wind up with one monster wxPanel-derived class containing *all* the controls for *every* page of the UI.  That is tolerable if necessary, I guess, but again not exactly ideal...

Apparently what I really want is a wxPanel with a transparent-with-respect-to-siblings background.  But that would require wxWidgets to support overlapped child windows, which I gather is explicitly a non-goal.

Still, if this is the best option, I guess I can work with it.  Thanks!  If anyone has a suggestion that addresses issues A and/or B above, please LMK.

Cheers,
    Chris

Vadim Zeitlin

unread,
Dec 28, 2012, 6:38:30 PM12/28/12
to wx-u...@googlegroups.com
On Thu, 27 Dec 2012 23:26:26 -0800 Chris MacGregor wrote:

CM> 1. I can't put the background on the wxFrame (at least, not if I want to
CM> use wxPanel for the pages), because the wxPanel's background covers up
CM> the wxFrame's bitmap background. So apparently I would need to
CM> separately put the background on each such wxPanel (each page in the
CM> UI).

Yes, wxPanel is not transparent itself so you'd need to do it like this.
I'm not sure if it would make sense to have a transparent wxPanel...

CM> Yuck. Do-able, yes, but yuck. I'm assuming I can at least share
CM> the wxBitmap used for the purpose and the memory won't be consumed 30x
CM> for 30 pages

Yes, wxBitmap should be shared.

CM> It would be much better if I could just put the background on one
CM> wxFrame and swap controls in and out of the frame in groups

You could do this, of course, except you should still use wxPanel as the
controls parent because wxPanel provides TAB navigation among the controls.
I.e. you should create a single root wxPanel as wxFrame child and then you
should create all the controls as children of this panel and show/hide them
as necessary.

CM> 2. I tried using Hide() and Show() on the wxPanels containing the pages
CM> of controls. There seems to be some kind of bug (or else I'm doing
CM> something stupid, but this part is pretty straightforward, and I don't
CM> see much I could be doing wrong), because when I hide one such panel and
CM> show the other (both having been added to a sizer which also contains
CM> the top status bar, or to a separate sizer added to the top level sizer
CM> - it happens either way), showing the panel which was not originally
CM> shown causes the top status bar to be hidden (as if I told it to hide
CM> the whole sizer or something). OTOH, this is currently inside a
CM> wxScrolledWindow ... hmmm. (Checking...) Well, okay, when I eliminate
CM> the wxScrolledWindow (which is only used when simulating the device
CM> target on a Linux desktop or Mac/Windows machine), that problem goes
CM> away. So I guess this is related to the problem Hector noted - never mind.

I don't think it's related. That problem arise when you scroll this window
and messes up its (bitmap) background and you seem to be speaking about
something quite different. But I don't know what could explain what you see
neither, as always a minimal example showing the problem would be helpful.

OTOH I also don't know why would you use wxScrolledWindow here, isn't the
status bar supposed to always be shown on top, i.e. be fixed, instead of
being scrolled away?

CM> 3. I tried using Detach() and Add() to remove one panel (page of
CM> controls) from the sizer and add another, but that seemed to just not
CM> work.

This definitely should work, however you should understand that by "work"
we mean that the detached window is not handled by the sizer any more, it
doesn't do anything else. I.e. you still need to hide it.

But then by default you don't even need to Detach() a hidden window as
it's not taken into account for the layout. So it's perfectly fine to have
all your controls managed by the sizer and just hide those of them that
shouldn't be currently visible.

Although, again, detaching them should work too.

CM> Again, I just want an easy way to change out sets of controls in the
CM> middle of the wxFrame en masse, ideally while maintaining a bitmap
CM> background behind everything.

Look at wxSimplebook implementation at

http://trac.wxwidgets.org/browser/wxWidgets/trunk/include/wx/simplebook.h

It was only added relatively recently but its implementation is trivial,
especially if you disregard the effects stuff. So you could just do the
same thing or maybe simply take this header and use it in your program (of
course, you won't need it any more once you upgrade to 2.9.5).

You would need, of course, to set the custom background for each page you
add to it but IMHO it's not a huge problem.

Steve Barnes

unread,
Dec 28, 2012, 6:38:34 PM12/28/12
to wx-u...@googlegroups.com
--
Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.
 
To unsubscribe, send email to wx-users+u...@googlegroups.com
or visit http://groups.google.com/group/wx-users
Re A): Several of the GUI layout tools suffer this drawback whenever you get beyond simple layouts - you almost always end up doing things by hand.

Re B): You could always have each of the pages as their own class, passed the parent panel in the constructor when used in your full application.  You could then lay each out, possibly with a temporary, named, panel for layout and standalone testing and use a script to switch out the named panel. (Naming the panel will make it easy to find for your script).
 

--
Steve Gadget Barnes

Hakki Dogusan

unread,
Dec 29, 2012, 3:23:27 AM12/29/12
to wx-u...@googlegroups.com
Hi,

29-12-2012 00:50 tarihinde, Chris MacGregor yazdı:
> On 12/28/2012 12:31 AM, Steve Barnes wrote:
>> On 28/12/12 07:26, Chris MacGregor wrote:
>>> ...
>>>
>>> However, there's a bit more to it. What I'm trying to build is a UI
>>> wherein there is a constant top status bar (sorry, not a wxStatusBar,
>>> just a little horizontal sizer with a clock and a battery icon and
>>> such) and a constant bitmap background, and then various different
>>> pages (sets, arrangements, etc.) of buttons and other controls.
>>> Imagine a main menu page with a bunch of buttons, and when you click
>>> one the main menu disappears and other buttons and controls appear,
>>> and so on across many such pages. The only thing that is the same
>>> across all these pages is the top status bar and the background.
>>>
>>> [snip]


I've used wxSwitcher and a toolbar for a similar -web browser like-
design. It seems Vadim's suggestion of wxSimplebook is similar to
wxSwitcher. Though, I didn't use a background image.


>
> Cheers,
> Chris
>


--
Regards,
Hakki Dogusan


Reply all
Reply to author
Forward
0 new messages