Page 1 of 1

Custom wxListBox, OnPaint doesn't call

Posted: Fri Jul 19, 2013 2:54 pm
by xterro
Hi, I need custom wxListBox(or may be wxCheckListBox), something like this:
Без имени.png
Без имени.png (8.29 KiB) Viewed 7089 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;
}

Re: Custom wxListBox, OnPaint doesn't call

Posted: Fri Jul 19, 2013 4:18 pm
by doublemax
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.

Re: Custom wxListBox, OnPaint doesn't call

Posted: Fri Jul 19, 2013 5:43 pm
by xterro
Thank you, I'll try to use it :)

Re: Custom wxListBox, OnPaint doesn't call

Posted: Sat Jul 20, 2013 4:45 am
by xterro
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;
}

Re: Custom wxListBox, OnPaint doesn't call

Posted: Sat Jul 20, 2013 5:13 am
by doublemax
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".

Re: Custom wxListBox, OnPaint doesn't call

Posted: Sat Jul 20, 2013 6:35 am
by xterro
So simple, thanks again, now it's ok :)

Re: Custom wxListBox, OnPaint doesn't call

Posted: Sat Jul 20, 2013 11:49 am
by xterro
It works :)
list.png
list.png (3.4 KiB) Viewed 7033 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;
}