Paint background image in any wxWindow, an elegant way

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
samggyy
Experienced Solver
Experienced Solver
Posts: 95
Joined: Wed Aug 15, 2007 7:34 am
Location: London, UK/ China
Contact:

Re: Paint background image in any wxWindow, an elegant way

Post by samggyy »

Hi, there:

May I ask who can explain the codes below a little bit? I do not quite understand these codes without any comments. Thanks a lot!

Does it mean that we need to use wxEraseEvent to paint the background image?

Thanks!
:wink:

Sam
Paulsen wrote:It is truth universally acknowledged, that background images in wxWindows need to be painted in the erase event handler.

Rather than deriving individually from all those classes that may be suitable to display a background image, to setup the event table etc., it is far simpler to create one event handler class once and for all, which can be used with any wxWindow derived class.

Code: Select all

class wxBackgroundBitmap : public wxEvtHandler {
    typedef wxEvtHandler Inherited;
public:
    wxBackgroundBitmap(const wxBitmap &B) : Bitmap(B), wxEvtHandler() { }
    virtual bool        ProcessEvent(wxEvent &Event);
protected:
    wxBitmap            Bitmap;
};

Code: Select all

bool                wxBackgroundBitmap::ProcessEvent(wxEvent &Event)
{
    if (Event.GetEventType() == wxEVT_ERASE_BACKGROUND) {
        wxEraseEvent &EraseEvent = dynamic_cast<wxEraseEvent &>(Event);
        wxDC *DC = EraseEvent.GetDC();
        DC->DrawBitmap(Bitmap, 0, 0, false);
        return true;
    } else return Inherited::ProcessEvent(Event);
}
To change the background of e.g. a tool bar to an image, use this class like this:

Code: Select all

ToolBarBackground = new wxBackgroundBitmap(wxBITMAP("test"));
ToolBar->PushEventHandler(ToolBarBackground);
Cheshire Cat will get Summa Cum Laude.

>>>>>>>>>>>>>>>>>>>>>>>>>>>
OS: Windows XP Pro & Linux 2.6.16
Compiler: MSVC++ 6/MSVS 2005 & linux-g++/KDevelop
wxWindows 2.8.7
Sof_T
Can't get richer than this
Can't get richer than this
Posts: 864
Joined: Thu Jul 28, 2005 9:48 pm
Location: New Forest, United Kingdom
Contact:

Post by Sof_T »

The class overloads the Erase event handler. You create a new instance of the class wxBackgroundBitmap passing it a bitmap to use for painting. Then you use PushEventHandler(); to add this instance to any wxWindow. When the window is painted it will display the bitmap in the background.

I use my modified version to paint the background of a frame.

Sof.T
The home of Sof.T http://www.sof-t.site88.net/
Author of Programming with wxDevC++
http://sourceforge.net/projects/wxdevcpp-book/
aquawicket
Earned some good credits
Earned some good credits
Posts: 103
Joined: Sun Aug 05, 2007 5:49 am

Post by aquawicket »

This code is great, one problem though is my background bitmap does not cover the intire window, so since we are overloading EraseBackground, only the bitmap get drawn. The rest of the window is not drawn. I've tried throwing in event.Skip() and a few other things. Any Ideas?
Crackeraki
In need of some credit
In need of some credit
Posts: 8
Joined: Mon Apr 30, 2012 9:18 pm

Re: Paint background image in any wxWindow, an elegant way

Post by Crackeraki »

I tested all examples in this thread, i make one small modify on 1st Paulsen's Code:

Code: Select all

wxBackgroundBitmap(const wxBitmap &B) : Bitmap(B), wxEvtHandler() { }
to
wxBackgroundBitmap(const wxBitmap &B) : wxEvtHandler(), Bitmap(B) { }
Before and after that change toolbar didn't change background. 0 Warnings after switching place of args, all running perfectly.
What can go wrong? Images of toolbar showing normaly.
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Paint background image in any wxWindow, an elegant way

Post by doublemax »

This class is 5 years old, if you're using wxWidgets 2.9.3 you should try wxCustomBackgroundWindow:
http://docs.wxwidgets.org/trunk/classwx ... indow.html

However, it's also possible that this just doesn't work for toolbars. Which platform are you using?
Use the source, Luke!
Crackeraki
In need of some credit
In need of some credit
Posts: 8
Joined: Mon Apr 30, 2012 9:18 pm

Re: Paint background image in any wxWindow, an elegant way

Post by Crackeraki »

I am new to wx, so i can use any version.
I search for examples of class you show me and didn't find anything
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Paint background image in any wxWindow, an elegant way

Post by doublemax »

Code: Select all

class MyCanvas : public wxCustomBackgroundWindow<wxPanel>
{
public:
  MyCanvas(wxWindow *parent, int id);
};

MyCanvas::MyCanvas(wxWindow *parent, int id)
{
  Create(parent, id);

  wxBitmap background_bitmap( wxT("c:\\test.png"), wxBITMAP_TYPE_PNG );
  if( background_bitmap.Ok() )
    SetBackgroundBitmap(background_bitmap);
}
Just use this class like you would with wxPanel.
Use the source, Luke!
stb
Earned a small fee
Earned a small fee
Posts: 22
Joined: Mon Aug 22, 2016 9:07 am

Re: Paint background image in any wxWindow, an elegant way

Post by stb »

Hi!

I failed to set the background of a wxDialog. I tried with the proposed custom wxBackgroundBitmap class and this basically works, but it shows the strange behaviour that it alters the top border of wxWindows shown on this wxDialog. I tried with wxBORDER_NONE and wxBORDER_SIMPLE, but it does not help:

Code: Select all

wxSizer *sizer_demo=new wxStaticBoxSizer(wxVERTICAL,this,wxT(""));
demo_large_picture=new wxWindow(this,wxID_ANY,wxDefaultPosition,wxSize(large_size,large_size),/*wxBORDER_NONE*/wxBORDER_SIMPLE);
sizer_demo->Add(demo_large_picture,0,0/*wxALIGN_CENTRE_VERTICAL*/);
I have appended two sreenshows, one with background picture, the second without, showing the different top borders. The code differs only in calling wxBackgroundBitmap/PushEventHandler or not:

Code: Select all

if(background_available)
{
    wxBackgroundBitmap *ToolBarBackground = new wxBackgroundBitmap(background_bitmap);
    PushEventHandler(ToolBarBackground);
}
Has someone an idea what causes this? - It looks like a small window title field that is visible when a background image when wxBackgroundBitmap is used. If I show the window full screen, the button even gets compressed.

Thanks
Attachments
button.png
button.png (1.83 KiB) Viewed 10220 times
with_background.png
without_background.png
without_background.png (6.63 KiB) Viewed 10220 times
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Paint background image in any wxWindow, an elegant way

Post by doublemax »

I don't see how this can be caused by adding a background bitmap. Can you create a minimal, compilable sample that shows the issue?
Use the source, Luke!
stb
Earned a small fee
Earned a small fee
Posts: 22
Joined: Mon Aug 22, 2016 9:07 am

Re: Paint background image in any wxWindow, an elegant way

Post by stb »

Hi!

I have attached four source code files: background.h/background.cpp containing the code presented here, and bg.h/bg.cpp is my source code.
May my code has some bugs that cause it...

Thanks & best regards,
Stephan
Attachments
bg.cpp
(5.18 KiB) Downloaded 225 times
background.h
(275 Bytes) Downloaded 229 times
background.cpp
(1.48 KiB) Downloaded 255 times
stb
Earned a small fee
Earned a small fee
Posts: 22
Joined: Mon Aug 22, 2016 9:07 am

Re: Paint background image in any wxWindow, an elegant way

Post by stb »

and here also bg.h
Attachments
bg.h
(747 Bytes) Downloaded 244 times
stb
Earned a small fee
Earned a small fee
Posts: 22
Joined: Mon Aug 22, 2016 9:07 am

Re: Paint background image in any wxWindow, an elegant way

Post by stb »

Hi!

Has someone compiled my code and does see the same behaviour? - I still ask myself if I have made a programming fault, but I so far do not see it.
Maybe I should post it also to another wxWidgets discussion forum, as "The Code Dump" does not really fit.

Thanks & best regards,
Stephan
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Paint background image in any wxWindow, an elegant way

Post by doublemax »

Sorry, i totally forgot about this.

This is indeed a mystery. More or less by trial-and-error in found out that the creation of the wxBufferedPaintDC is causing the strange effect (just replacing it with wxPaintDC makes it disappear). But although curious how this could affect the layout of a window, i didn't want to spend more time to get to the bottom of this.

Maybe you should look into wxCustomBackgroundWindow, it's seems like an easier and cleaner way to achieve the same:
https://docs.wxwidgets.org/trunk/classw ... indow.html
Use the source, Luke!
stb
Earned a small fee
Earned a small fee
Posts: 22
Joined: Mon Aug 22, 2016 9:07 am

Re: Paint background image in any wxWindow, an elegant way

Post by stb »

Thank you very much for your reply!
At least in my environment (wxWidgets-3.1.0, Win10 x64 1803), exchanging wxBufferedPaintDC by wxPaintDC in wxBackgroundBitmap::ProcessEvent() does not make it disapear. Makes it even stranger... - Or have you additionally changed something else?

I have also seen wxCustomBackgroundWindow, but can I use it for a wxDialog? - I have not seen how to implement it, so I decided to use the proposed code.

What I also do not understand is why

Code: Select all

wxBackgroundBitmap *ToolBarBackground = new wxBackgroundBitmap(background_bitmap);
PushEventHandler(ToolBarBackground);
must be executed at the end, and is not allowed at the beginning, for example right before top_sizer is created. - It results in being all sizers drawn in the top left corner. I have appended the adjusted version of bg.cpp to this message.
Attachments
bg.cpp
(5.46 KiB) Downloaded 204 times
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Paint background image in any wxWindow, an elegant way

Post by doublemax »

Or have you additionally changed something else?
Sorry, i couldn't reproduce it today. Maybe i was too tired last night :(

Anyway, after further investigation i'd say the gap at the top is always there, you just don't see it when there is no custom background.

I tried pretty much every alternative i could think of: wxCustomBackgroundWindow, wxGenericStaticBitmap as background, custom OnEraseBackground event handlers, etc. They all gave the same result.

The only thing i found out is that it seems to be related to a custom paint event handler in wxStaticBox which can be disabled with this line (before creating any wxStaticBox):

Code: Select all

wxSystemOptions::SetOption("msw.staticbox.optimized-paint", 0 );
But
a) it will flicker on redraw
b) the custom background will also be drawn in the background of the staticbox

The only other solution i could think of would be to not use a wxStaticBoxSizer. Instead use a wxPanel with a custom paint event handler that mimics the border of a wxStaticBox.
Use the source, Luke!
Post Reply