Custom wxListBox, OnPaint doesn't call 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
xterro
In need of some credit
In need of some credit
Posts: 7
Joined: Fri Jul 19, 2013 1:59 pm

Custom wxListBox, OnPaint doesn't call

Post by xterro » Fri Jul 19, 2013 2:54 pm

Hi, I need custom wxListBox(or may be wxCheckListBox), something like this:
Без имени.png
Без имени.png (8.29 KiB) Viewed 6682 times
I wrote some code, but OnPaint method of "wxColorCheckListBox" doesn't call. (OnSize and OnMouseDown methods is ok). What could be the problem? wxWidgets version 2.8.12

Code: Select all

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



const int ID_LISTBOX = 1;

class wxColorCheckListBox : public wxListBox
{

public:
    wxColorCheckListBox(wxWindow *parent, int id );

    void OnPaint(wxPaintEvent& event);
    void OnSize(wxSizeEvent& event);
    void OnMouseDown(wxMouseEvent& event);
    void OnItemSelected(wxCommandEvent & event);

    DECLARE_EVENT_TABLE()
};


BEGIN_EVENT_TABLE(wxColorCheckListBox, wxListBox)
    EVT_LEFT_DOWN(wxColorCheckListBox::OnMouseDown)
    EVT_LISTBOX(ID_LISTBOX, wxColorCheckListBox::OnItemSelected)
    EVT_PAINT(wxColorCheckListBox::OnPaint)
END_EVENT_TABLE()


wxColorCheckListBox::wxColorCheckListBox(wxWindow *parent, int id )
    :wxListBox(parent, id, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_OWNERDRAW, wxDefaultValidator, wxT("color_check_listbox"))
{
    //Connect(ID_LISTBOX, wxEVT_PAINT, wxPaintEventHandler (wxColorCheckListBox::OnPaint));
}


void wxColorCheckListBox::OnMouseDown(wxMouseEvent & event)
{
    std::cout << "mouse down!!!\n";
    Update();
    event.Skip();
}


void wxColorCheckListBox::OnPaint(wxPaintEvent & event)
{
    std::cout << "draw!!!\n";


    wxClientDC dc(this);
    dc.SetBrush(*wxWHITE_BRUSH);
    dc.SetPen (*wxRED_PEN);
    dc.Clear();

   int size = 20;



   for (unsigned int x = 0; x < 3; x++)
   {
      dc.SetFont(*wxNORMAL_FONT);
      dc.SetBrush(wxBrush(wxColor(*wxLIGHT_GREY)));
      dc.SetPen(wxPen(wxColor(*wxBLACK)));

      dc.DrawRectangle (size + 2, x*size, size, size);

      dc.DrawText (wxT("aaaa"), (size + 2)*2, x*size);
   }


}

void wxColorCheckListBox::OnSize(wxSizeEvent& event)
{
    std::cout << "size!!!\n";
    //event.Skip();

}

void wxColorCheckListBox::OnItemSelected(wxCommandEvent & event)
{
    std::cout << "mouse selected!!!\n";
}

/////////////////////////////////////////////////////////////////////////////////
class MyApp: public wxApp
{
    bool OnInit();


public:

};

IMPLEMENT_APP(MyApp)


bool MyApp::OnInit()
{
    wxDialog * dlg = new wxDialog(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300,500));
    wxColorCheckListBox * lb = new wxColorCheckListBox(dlg, ID_LISTBOX);

    lb->Append(wxT("Item 1"));
    lb->Append(wxT("Item 2"));
    lb->Append(wxT("Item 3"));

    wxBoxSizer sizer(wxHORIZONTAL);
    sizer.Add(lb, 1, wxEXPAND|wxALL, 5);
    dlg->SetSizer(&sizer);
    dlg->Show();

    return true;
}

User avatar
doublemax
Moderator
Moderator
Posts: 14626
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Custom wxListBox, OnPaint doesn't call

Post by doublemax » Fri Jul 19, 2013 4:18 pm

For most native controls it's not possible to change their look with a custom paint event handler.

Try wxVListBox or wxHtmlListBox.
http://docs.wxwidgets.org/stable/wx_wxv ... wxvlistbox
http://docs.wxwidgets.org/stable/wx_wxh ... tmllistbox

BTW: In a paint event handler, you *must* create an instance of wxPaintDC under Windows. And you should use the wxPaintDC for drawing, not wxClientDC.
Use the source, Luke!

xterro
In need of some credit
In need of some credit
Posts: 7
Joined: Fri Jul 19, 2013 1:59 pm

Re: Custom wxListBox, OnPaint doesn't call

Post by xterro » Fri Jul 19, 2013 5:43 pm

Thank you, I'll try to use it :)

xterro
In need of some credit
In need of some credit
Posts: 7
Joined: Fri Jul 19, 2013 1:59 pm

Re: Custom wxListBox, OnPaint doesn't call

Post by xterro » Sat Jul 20, 2013 4:45 am

One more question, does somebody have an example of using wxVListBox? I have added some code, but there is nothing happening :?

Code: Select all

#include "wx/wx.h"
#include <wx/vlbox.h>
#include <iostream>



const int ID_LISTBOX = 1;

class wxColorCheckListBox : public wxVListBox
{

public:
    wxColorCheckListBox(wxWindow *parent, int id);

	 void OnDrawItem(wxDC &dc, const wxRect &rect, size_t n) const {
			
			dc.SetPen(wxPen(*wxBLACK, 2, wxSOLID));	
			dc.DrawLine(rect.x, rect.y/2, rect.width, rect.height/2);
			dc.DrawLine(0,0,10,10);
		}
	 void 		OnDrawBackground(wxDC &dc, const wxRect &rect, size_t n) { 

				//dc.SetBrush(*wxRED_BRUSH); 
				dc.SetBackground(wxBrush(*wxRED_BRUSH));
		}
	 void 		OnDrawSeparator(wxDC &dc, wxRect &rect, size_t n); 
	 wxCoord 	OnMeasureItem(size_t n) const { return 16; }

	void Append(wxString str);
};


wxColorCheckListBox::wxColorCheckListBox(wxWindow *parent, int id )
    :wxVListBox(parent, id)
{
   
}

void wxColorCheckListBox::OnDrawSeparator(wxDC &dc, wxRect &rect, size_t n)
{
	dc.SetPen(wxPen(*wxBLACK, 2, wxSOLID));	
	dc.DrawLine(rect.x, rect.y/2, rect.width, rect.height/2);
}


void wxColorCheckListBox::Append(wxString str)
{

}

/////////////////////////////////////////////////////////////////////////////////
class MyApp: public wxApp
{
    bool OnInit();


public:

};

IMPLEMENT_APP(MyApp)


bool MyApp::OnInit()
{
    wxDialog * dlg = new wxDialog(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300,500));
    wxColorCheckListBox * lb = new wxColorCheckListBox(dlg, ID_LISTBOX);

    lb->Append(wxT("Item 1"));


    wxBoxSizer sizer(wxHORIZONTAL);
    sizer.Add(lb, 1, wxEXPAND|wxALL, 5);
    dlg->SetSizer(&sizer);
    dlg->Show();

    return true;
}

User avatar
doublemax
Moderator
Moderator
Posts: 14626
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Custom wxListBox, OnPaint doesn't call

Post by doublemax » Sat Jul 20, 2013 5:13 am

Append() doesn't do anything. It's a "virtual" control, which means that you have to manage the items yourself. You call SetItemCount() with the number of items and when OnDrawItem() gets called, you have to draw the item specified with the parameter "n".
Use the source, Luke!

xterro
In need of some credit
In need of some credit
Posts: 7
Joined: Fri Jul 19, 2013 1:59 pm

Re: Custom wxListBox, OnPaint doesn't call

Post by xterro » Sat Jul 20, 2013 6:35 am

So simple, thanks again, now it's ok :)

xterro
In need of some credit
In need of some credit
Posts: 7
Joined: Fri Jul 19, 2013 1:59 pm

Re: Custom wxListBox, OnPaint doesn't call

Post by xterro » Sat Jul 20, 2013 11:49 am

It works :)
list.png
list.png (3.4 KiB) Viewed 6626 times

Code: Select all

#include "wx/wx.h"
#include <wx/vlbox.h>
#include <iostream>
#include <vector>

using namespace std;

const int ID_LISTBOX = 1;

struct ColorCheckListItem {
	public:
		ColorCheckListItem(wxString text, wxColor color, bool checked)
			: Text(text), Color(color), Checked(checked) {};

		int			TopY;
		int			Height;
		wxString 	Text;
		wxColor 	Color;
		bool 		Checked;
};


class ColorCheckListBox : public wxVListBox
{
	public:
    	ColorCheckListBox(wxWindow *parent, int id);

	 	void OnDrawItem(wxDC &dc, const wxRect &rect, size_t n) const {
						
				if(n > m_List.size()-1)
					return; 

				ColorCheckListItem item = m_List.at(n);
				if(item.TopY + item.Height > GetSize().GetHeight()) {
					return;
				}
				else {
					dc.SetPen(wxPen(*wxBLACK, 1, wxSOLID));	
					
					if(item.Checked) {
						dc.SetBrush(*wxWHITE_BRUSH);
						// draw a small triangle at the corner of the rectangle :)
						dc.DrawRectangle(wxRect(m_CheckBoxIndent.x, 
												item.TopY + m_CheckBoxIndent.y, 
												m_CheckBoxSize.x, m_CheckBoxSize.y));
						dc.SetPen(wxPen(wxColor(item.Color), 1, wxSOLID));	
						dc.SetBrush(wxBrush(item.Color));
						int s = m_CheckBoxSize.x/2;	 // side of the triangle 					
						wxPoint plist[] = {	wxPoint(m_CheckBoxIndent.x+1, item.TopY + m_CheckBoxIndent.y+1), 
											wxPoint(m_CheckBoxIndent.x+s, item.TopY + m_CheckBoxIndent.y+1),
											wxPoint(m_CheckBoxIndent.x+1, item.TopY + m_CheckBoxIndent.y+s)};
						
						dc.DrawPolygon(3, plist);
					}
					else {
						dc.SetBrush(wxBrush(item.Color));
						dc.DrawRectangle(wxRect(m_CheckBoxIndent.x, 
												item.TopY + m_CheckBoxIndent.y, 
												m_CheckBoxSize.x, m_CheckBoxSize.y));
					}
						
					int textY = item.TopY + (m_ItemHeight/2 - m_FontSize/2);
					int textX = m_CheckBoxIndent.x + m_CheckBoxSize.x + m_TextIndent;
					dc.DrawText(item.Text, textX, textY);
				}
		}

		void 		OnDrawBackground(wxDC &dc, const wxRect &rect, size_t n) {}
		wxCoord 	OnMeasureItem(size_t n) const { return m_ItemHeight; }
		void		OnLeftButtonDown(wxMouseEvent & event);

		void 		AppendItem(wxString str, wxColour color, bool checked);
		bool		CheckBoxContainsPoint(ColorCheckListItem & item, wxPoint p);
	
	private:
		int 	m_FontSize;
		wxSize 	m_CheckBoxSize;
		wxSize 	m_CheckBoxIndent;
		int		m_TextIndent;
		int		m_ItemHeight;
		vector<ColorCheckListItem> m_List;
};


ColorCheckListBox::ColorCheckListBox(wxWindow *parent, int id )
    :wxVListBox(parent, id, wxDefaultPosition, wxDefaultSize, wxLB_SINGLE)
{
	SetItemCount(0);
	wxFont font = wxFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
	
	m_FontSize 			= font.GetPointSize();	
	m_CheckBoxIndent.x 	= 3;
	m_CheckBoxIndent.y 	= 3;
	m_ItemHeight 		= m_FontSize*3 + m_CheckBoxIndent.y;
	m_CheckBoxSize.x 	= m_ItemHeight - m_CheckBoxIndent.y*2;
	m_CheckBoxSize.y 	= m_CheckBoxSize.x;
	m_TextIndent 		= 5;

	Connect(ID_LISTBOX, wxEVT_LEFT_DOWN, wxMouseEventHandler(ColorCheckListBox::OnLeftButtonDown));
}

bool ColorCheckListBox::CheckBoxContainsPoint(ColorCheckListItem & item, wxPoint p)
{
	if(p.x > m_CheckBoxIndent.x && p.x < (m_CheckBoxIndent.x + m_CheckBoxSize.x)) {
		if(p.y > (item.TopY + m_CheckBoxIndent.y) && p.y < (item.TopY + item.Height - m_CheckBoxIndent.y)) {
			return true;	
		}
	}		

	return false;
}

void ColorCheckListBox::OnLeftButtonDown(wxMouseEvent & event)
{	
	bool clicked = false;	
	
	for(vector<ColorCheckListItem>::iterator it = m_List.begin(); it != m_List.end(); it++) {    
		wxPoint point(event.GetX(), event.GetY());	
		if(CheckBoxContainsPoint(*it, point)) {
			if((*it).Checked) 
				(*it).Checked = false;
			else 
				(*it).Checked = true;				
			
			clicked = true;
			break;
		}
	}

	if(!clicked) {
		event.Skip();
	} else 
		Refresh();
}


void ColorCheckListBox::AppendItem(wxString str, wxColor color, bool checked)
{	
	ColorCheckListItem item(str, color, checked);
	
	if(m_List.size() == 0) 
		item.TopY = 0;
	else {
		ColorCheckListItem lastItem = *(m_List.end()-1); // "m_List.end()" it's not the last element  		
		item.TopY = lastItem.TopY + m_ItemHeight;
	}
	
	item.Height = m_ItemHeight;
	m_List.push_back(item);
	SetItemCount(m_List.size());
}

/////////////////////////////////////////////////////////////////////////////////
class MyApp: public wxApp
{
    bool OnInit();

public:

};

IMPLEMENT_APP(MyApp)


bool MyApp::OnInit()
{
    wxDialog * dlg = new wxDialog(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300,400));
    ColorCheckListBox * lb = new ColorCheckListBox(dlg, ID_LISTBOX);
	

    lb->AppendItem(_T("AAA"), wxColor(_T("PINK")), false);
	lb->AppendItem(_T("BBB"), wxColor(_T("LIGHT GREEN")), false);
	lb->AppendItem(_T("CCC"), wxColor(_T("LIGHT BLUE")), true);
	lb->AppendItem(_T("DDD"), wxColor(_T("ORANGE")), false);
	lb->AppendItem(_T("EEE"), wxColor(_T("YELLOW")), false);
	lb->AppendItem(_T("FFF"), wxColor(_T("SALMON")), false);
	lb->AppendItem(_T("GGG"), wxColor(_T("PLUM")), false);
	lb->AppendItem(_T("HHH"), wxColor(_T("KHAKI")), false);
	lb->AppendItem(_T("III"), wxColor(_T("WHEAT")), false);

    wxBoxSizer sizer(wxHORIZONTAL);
    sizer.Add(lb, 1, wxEXPAND|wxALL, 5);
    dlg->SetSizer(&sizer);
    dlg->Show();

    return true;
}





Post Reply