Base class drawing over derived class components Topic is solved

Are you writing your own components and need help with how to set them up or have questions about the components you are deriving from ? Ask them here.
Post Reply
plicatibu
In need of some credit
In need of some credit
Posts: 4
Joined: Thu May 08, 2014 2:46 pm
Location: Brazil
Contact:

Base class drawing over derived class components

Post by plicatibu »

Hi, guys.

I'm trying to make a program that will contain many panels. All of them must have a background image.

To ease my job I decided to create a base class that will be responsible for drawing this image (and for other stuff common to all derived screens).

So far, so good. The problem I'm facing is that the image that should be drawn in background is being draw on top of components in the derived class.

Shouldn't the images/components of derived class be draw on top of components from base class?

I'm struggling with this for a couple of days but I couldn't find a solution.

You can see both an image showing the problem and the source code I made.

Could someone point me what I am doing wrong?

Thanks in advance.

Image

Code: Select all

// BaseScreen.h
#ifndef _BASE_SCREEN_H
#define _BASE_SCREEN_H

#include <wx/wx.h>
#include "global_settings.h"

class BaseScreen : public wxPanel
{
	private:

	protected:
		wxStaticBitmap* m_bgImage;

	public:

		BaseScreen( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = g_AppSize, long style = wxTAB_TRAVERSAL );
		virtual ~BaseScreen();

};

#endif //_BASE_SCREEN_H

Code: Select all

// BaseScreen.cpp
#include "BaseScreen.h"

BaseScreen::BaseScreen( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) :
wxPanel( parent, id, pos, size, style )
{
	wxImage::AddHandler( new wxPNGHandler );
	wxBoxSizer* bSizer1;
	bSizer1 = new wxBoxSizer( wxVERTICAL );


	bSizer1->Add( 0, 0, 1, wxEXPAND, 5 );

	m_bgImage = new wxStaticBitmap( this, wxID_ANY, wxBitmap( g_pathToBgImage, wxBITMAP_TYPE_PNG ), wxDefaultPosition, wxDefaultSize, 0 );
	m_bgImage->SetMinSize( g_bgImageSize );
	m_bgImage->SetMaxSize( g_bgImageSize );

	bSizer1->Add( m_bgImage, 0, wxALIGN_CENTER, 5 );


	bSizer1->Add( 0, 0, 1, wxEXPAND, 5 );


	this->SetSizer( bSizer1 );
	this->Layout();
}

BaseScreen::~BaseScreen()
{
}

Code: Select all

// MainScreen.h
#ifndef _MAIN_SCREEN_H
#define _MAIN_SCREEN_H

#include <wx/wx.h>
#include "BaseScreen.h"

class MainScreen : public BaseScreen
{
	private:

	protected:
		wxStaticText *m_txtTitle;
		wxButton *m_btnFile;
		wxButton *m_btnImport;
		wxButton *m_btnExport;
		wxButton *m_btnAbout;

	public:
		MainScreen( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = g_AppSize, long style = wxTAB_TRAVERSAL );
		virtual ~MainScreen();
};

#endif // _MAIN_SCREEN_H

Code: Select all

// MainScreen.cpp
#include <wx/wx.h>
#include "MainScreen.h"

MainScreen::MainScreen( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) :
BaseScreen( parent, id, pos, size, style )
{
	this->SetForegroundColour( g_PanelForegroundColor );
	this->SetBackgroundColour( g_PanelBackroundColor );
	this->SetMinSize( wxSize( g_AppSize ) );
	this->SetMaxSize( wxSize( g_AppSize ) );

	wxBoxSizer* bSizer1;
	bSizer1 = new wxBoxSizer( wxVERTICAL );


	// Title - Start
	m_txtTitle = new wxStaticText( this, wxID_ANY, g_MainMenuTitle, wxDefaultPosition, wxDefaultSize, 0 );
	m_txtTitle->Wrap( -1 );
	m_txtTitle->SetFont( wxFont( 24, 74, 90, 92, false, wxT("Arial Black") ) );
	m_txtTitle->SetForegroundColour( g_TitleColor );
	bSizer1->Add( m_txtTitle, 0, wxALIGN_CENTER|wxALL, 5 );
	// Title - End


	// File button - Start
	wxBoxSizer* bSizer2;
	bSizer2 = new wxBoxSizer( wxHORIZONTAL );
	m_btnFile = new wxButton( this, wxID_ANY, m_btnFile, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer2->Add( m_btnFile, 1, wxALL, 5 );
	bSizer1->Add( bSizer2, 0, wxEXPAND, 5 );


	// Import button - Start
	wxBoxSizer* bSizer3;
	bSizer3 = new wxBoxSizer( wxHORIZONTAL );
	m_btnImport = new wxButton( this, wxID_ANY, m_btnImport, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer3->Add( m_btnImport, 1, wxALL, 5 );	
	bSizer1->Add( bSizer3, 0, wxEXPAND, 5 );


	// Export button - Start
	wxBoxSizer* bSizer4;
	bSizer4 = new wxBoxSizer( wxHORIZONTAL );
	m_btnExport = new wxButton( this, wxID_ANY, m_btnExport, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer4->Add( m_btnExport, 1, wxALL, 5 );
	bSizer1->Add( bSizer4, 0, wxEXPAND, 5 );


	// About button - Start
	wxBoxSizer* bSizer5;
	bSizer5 = new wxBoxSizer( wxHORIZONTAL );
	m_btnAbout = new wxButton( this, wxID_ANY, g_About, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer5->Add( m_btnAbout, 1, wxALL, 5 );

	bSizer1->Add( bSizer5, 0, wxEXPAND, 5 );
	// About button - End


	this->SetSizer( bSizer1 );
	this->Layout();
}

MainScreen::~MainScreen()
{
}
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Base class drawing over derived class components

Post by doublemax »

The wxStaticBitmap in the base class and the controls you (try to) put on top of it, all all children of the same panel. So the wxStaticBitmap and the controls are siblings. If you want to put the controls on top of the image, you have two options:

a) The controls must be children of the wxStaticBitmap

b) You don't use a wxStaticBitmap in the base class and instead of a wxPanel, you use a wxCustomBackgroundWindow< wxPanel > as base class and use SetBackgroundBitmap() to set the background image.
http://docs.wxwidgets.org/trunk/classwx ... indow.html
Use the source, Luke!
plicatibu
In need of some credit
In need of some credit
Posts: 4
Joined: Thu May 08, 2014 2:46 pm
Location: Brazil
Contact:

Re: Base class drawing over derived class components

Post by plicatibu »

Hi.

I didn't know about this.

I'll give a try and let you know.

Is there any advantage / disadvantage to use method a over b or vice-verse?

Kind regards.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Base class drawing over derived class components

Post by doublemax »

I would use b). It's cleaner and more elegant. I think it's also easier for you with your current class structure, because you won't have to change the child-parent relationships.
Use the source, Luke!
plicatibu
In need of some credit
In need of some credit
Posts: 4
Joined: Thu May 08, 2014 2:46 pm
Location: Brazil
Contact:

Re: Base class drawing over derived class components

Post by plicatibu »

doublemax, first and foremost I want to thank you for your help. I wouldn't solve the problem with your help.

I had some problems implementing the solution you pointed the way but in the end everything is working. You can see the resulting in picture below.

Image

I wrote a post about all the process showing each problem I faced and what I made to solve them. Also I published a project in github with full source code so others can use the code. I didn't posted the links here because I don't know whether it's allowed or not.

So bellow are the final source code used in hope it will be useful to others.

Once again, thank you for your help.

global_settings.h

Code: Select all

#ifndef GLOBAL_SETTINGS_H
#define GLOBAL_SETTINGS_H

#include <wx/wx.h>

// ************************************************************************
//                            SIZES
// ************************************************************************
// The size of the application window.
const wxSize g_appSize(284,400);

// The size of the image draw in the background of all screens.
const wxSize g_bgImageSize( 256,232 );

// ************************************************************************
//                            FONT NAMES
// ************************************************************************
const wxString g_fontNameTitle(_T("Arial Black"));

// ************************************************************************
//                            FONTS
// ************************************************************************
const wxFont g_fontTitle( 24, 74, 90, 92, false, g_fontNameTitle );


// ************************************************************************
//                            TEXT
// ************************************************************************
// Application name that will appear in the title bar.
const wxString g_appName(_T("Background Image"));

// Text in titles
const wxString g_mainMenuTitle(_T("Menu"));


// Text in buttons
const wxString g_txtFile(_T("&File"));
const wxString g_txtImport(_T("&Import"));
const wxString g_txtExport(_T("&Export"));
const wxString g_txtAbout(_T("&About"));

// ************************************************************************
//                            PATHS
// ************************************************************************
// Full path to image used as background in all screens.
const wxString g_pathToBgImage("images\\bg.png");



// ************************************************************************
//                            COLORS
// ************************************************************************
const wxColour g_TitleColor( 255, 0, 255 );
const wxColour g_PanelForegroundColor( 255, 255, 255 );
const wxColour g_PanelBackroundColor( 255, 255, 255 );


#endif //GLOBAL_SETTINGS_H
BaseScreen.h

Code: Select all

#ifndef BASE_SCREEN_H
#define BASE_SCREEN_H

#include <wx/wx.h>
#include <wx/custombgwin.h>

#include "global_settings.h"

class BaseScreen : public wxCustomBackgroundWindow<wxPanel>
{
    DECLARE_DYNAMIC_CLASS (BaseScreen)

	private:

	protected:
		wxBitmap m_bgImage;
		bool m_drawImage;
		int m_xPos;

	public:

		BaseScreen();
		BaseScreen( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = g_appSize, long style = wxTAB_TRAVERSAL );
		virtual ~BaseScreen();
		void OnPaint(wxPaintEvent& event);
		DECLARE_EVENT_TABLE()
};

#endif //BASE_SCREEN_H
BaseScreen.cpp

Code: Select all

#include "BaseScreen.h"


IMPLEMENT_DYNAMIC_CLASS (BaseScreen, wxCustomBackgroundWindow<wxPanel>)

BEGIN_EVENT_TABLE(BaseScreen, wxCustomBackgroundWindow<wxPanel>)
    EVT_PAINT(BaseScreen::OnPaint)
END_EVENT_TABLE()

BaseScreen::BaseScreen()
{
    m_drawImage = NULL;
    m_xPos = 0;
}

BaseScreen::BaseScreen( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style )
{
    Create( parent, id, pos, size, style );
	wxImage::AddHandler( new wxPNGHandler );
	m_drawImage = m_bgImage.LoadFile( g_pathToBgImage, wxBITMAP_TYPE_PNG );

	if (m_drawImage) {
	    wxSize imgSize = m_bgImage.GetSize();
	    m_xPos = (g_appSize.GetWidth() - imgSize.GetWidth()) / 2;
	}

	this->Layout();
}


void BaseScreen::OnPaint(wxPaintEvent& event)
{
   wxPaintDC dc(this);

   if (m_drawImage) {
       dc.DrawBitmap(m_bgImage, wxPoint(m_xPos,0));
   }

}



BaseScreen::~BaseScreen()
{
}
TransparentStaticText.h

Code: Select all

#ifndef TRANSPARENT_STATIC_TEXT_H
#define TRANSPARENT_STATIC_TEXT_H

#include <wx/wx.h>
#include "BaseScreen.h"

class TransparentStaticText: public wxStaticText {

	DECLARE_DYNAMIC_CLASS (TransparentStaticText)

	public:
		TransparentStaticText();
		TransparentStaticText(wxWindow* parent, wxWindowID id,
		                      const wxString& label, const wxPoint& pos = wxDefaultPosition,
                              const wxSize& size = wxDefaultSize, long style = 0,
                              const wxString& name = wxStaticTextNameStr);

		bool Create(wxWindow* parent, wxWindowID id, const wxString& label,
		            const wxPoint& pos = wxDefaultPosition,
		            const wxSize& size = wxDefaultSize,
		            long style = 0,
		            const wxString& name= wxStaticTextNameStr);
		   virtual void OnPaint(wxPaintEvent& event);
		   DECLARE_EVENT_TABLE()
};

#endif //TRANSPARENT_STATIC_TEXT_H
TransparentStaticText.cpp

Code: Select all

#include "TransparentStaticText.h"

IMPLEMENT_DYNAMIC_CLASS (TransparentStaticText, wxStaticText)

BEGIN_EVENT_TABLE(TransparentStaticText, wxStaticText)
    EVT_PAINT(TransparentStaticText::OnPaint)
END_EVENT_TABLE()


TransparentStaticText::TransparentStaticText()
{
}


TransparentStaticText::TransparentStaticText(wxWindow* parent, wxWindowID id, const wxString& label,
                         const wxPoint& pos, const wxSize& size, long style, const wxString& name )
{
   Create(parent, id, label, pos, size, style, name);
}


bool TransparentStaticText::Create(wxWindow* parent, wxWindowID id, const wxString& label,
                      const wxPoint& pos, const wxSize& size, long style, const wxString& name )
{
   bool ret = wxStaticText::Create(parent, id, label, pos, size, style|wxTRANSPARENT_WINDOW, name);
   return ret;
}


void TransparentStaticText::OnPaint(wxPaintEvent& event)
{
   wxPaintDC dc(this);
   dc.SetFont(GetFont());
   dc.SetTextForeground(GetForegroundColour());
   dc.DrawText(GetLabel(), 0, 0);
}
MainScreen.h

Code: Select all

#ifndef MAIN_SCREEN_H
#define MAIN_SCREEN_H

#include <wx/wx.h>
#include "global_settings.h"
#include "BaseScreen.h"

class TransparentStaticText;

class MainScreen : public BaseScreen
{
	private:

	protected:
        TransparentStaticText *m_txtTitle;
		wxButton *m_btnFile;
		wxButton *m_btnImport;
		wxButton *m_btnExport;
		wxButton *m_btnAbout;


	public:

		MainScreen( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = g_appSize, long style = wxTAB_TRAVERSAL );
		virtual ~MainScreen();

};


#endif // MAIN_SCREEN_H
MainScreen.cpp

Code: Select all

#include <wx/wx.h>
#include <wx/sizer.h>

#include "MainScreen.h"
#include "TransparentStaticText.h"

MainScreen::MainScreen( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) :
BaseScreen( parent, id, pos, size, style )
{
	// First of all I set the properties of the Panel
	this->SetForegroundColour( g_PanelForegroundColor );
	this->SetBackgroundColour( g_PanelBackroundColor );
	this->SetMinSize( wxSize( g_appSize ) );
	this->SetMaxSize( wxSize( g_appSize ) );

	//Now I start adding the components

	// This sizer is the main container (afer Panel, of course).
	// All other components go inside it.
	wxBoxSizer* bSizer1;
	bSizer1 = new wxBoxSizer( wxVERTICAL );


	// Title - Start
	m_txtTitle = new TransparentStaticText ( this, wxID_ANY, g_mainMenuTitle, wxDefaultPosition, wxDefaultSize, 0 );
	m_txtTitle->Wrap( -1 );
	m_txtTitle->SetFont( g_fontTitle );
	m_txtTitle->SetForegroundColour( g_TitleColor );

	bSizer1->Add( m_txtTitle, 0, wxALIGN_CENTER|wxALL, 5 );


	// File button - Start
	wxBoxSizer* bSizer2;
	bSizer2 = new wxBoxSizer( wxHORIZONTAL );
	m_btnFile = new wxButton( this, wxID_ANY, g_txtFile, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer2->Add( m_btnFile, 1, wxALL, 5 );

	bSizer1->Add( bSizer2, 0, wxEXPAND, 5 );



	// Import button - Start
	wxBoxSizer* bSizer3;
	bSizer3 = new wxBoxSizer( wxHORIZONTAL );
	m_btnImport = new wxButton( this, wxID_ANY, g_txtImport, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer3->Add( m_btnImport, 1, wxALL, 5 );

	bSizer1->Add( bSizer3, 0, wxEXPAND, 5 );



	// Export button - Start
	wxBoxSizer* bSizer4;
	bSizer4 = new wxBoxSizer( wxHORIZONTAL );
	m_btnExport = new wxButton( this, wxID_ANY, g_txtExport, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer4->Add( m_btnExport, 1, wxALL, 5 );

	bSizer1->Add( bSizer4, 0, wxEXPAND, 5 );



	// About button - Start
	wxBoxSizer* bSizer5;
	bSizer5 = new wxBoxSizer( wxHORIZONTAL );
	m_btnAbout = new wxButton( this, wxID_ANY, g_txtAbout, wxDefaultPosition, wxDefaultSize, 0 );
	bSizer5->Add( m_btnAbout, 1, wxALL, 5 );

	bSizer1->Add( bSizer5, 0, wxEXPAND, 5 );

	//Now that I have all components I can set the sizer and draw them in the screen.
	this->SetSizer( bSizer1 );
	this->Layout();
}

MainScreen::~MainScreen()
{
}
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Base class drawing over derived class components

Post by doublemax »

You've probably heard it before, but: Using global variables should be avoided where ever possible.

Apart from being "bad style", it especially causes problems when you're using wxWIdgets objects as global variables, because they will be constructed before wxWidgets itself is initialized.

While it may work for simple classes like wxString, but for more complex classes like wxFont, it may not:

Code: Select all

const wxFont g_fontTitle( 24, 74, 90, 92, false, g_fontNameTitle );
I'm surprised this works under Windows, but this might fail under other platforms.
Use the source, Luke!
plicatibu
In need of some credit
In need of some credit
Posts: 4
Joined: Thu May 08, 2014 2:46 pm
Location: Brazil
Contact:

Re: Base class drawing over derived class components

Post by plicatibu »

Hi.

I'm aware if that. In really I don't intend to use global variables on the final program.

It's just an easy way I'm using to determine all variables I'll need in order to customize the application. Rest assured I'll read all from configuration files in the production version.

Thank you again for take your time for helping me.
Post Reply