I want to write an application, which must have the same appearance on any platform. I decide use wxWidgets
(I never have a large amount of work with this library).
Start my customization from ScrollBar. This was a bad decision,
(inheritance from wxScrollBar = because all control badly flickering)
because under OS Windows default ScrollBar has very poor ability for customization, explanation here. Next my step was to make same work as in this post, but use wxWidgets instead MFC.
- Better paint all control on one window or replace each 4 part by own window: scroll background, thumb slider, 2 scroll arrows? need advice.
I chose first:
#include "wx/wx.h"
#include "wx/sizer.h"
#define ENABLE_ERASING 0
#define DISABLE_BORDER 1
#define UPDATE_ON_RESIZE 0
#if DISABLE_BORDER
long gBorder = wxBORDER_NONE;
#else
long gBorder = 0;
#endif
class ScrollBar : public wxControl
{
public:
ScrollBar(wxWindow *parent, wxWindowID id);
protected:
void on_paint(wxPaintEvent& ev);
#if ENABLE_ERASING
void on_erace(wxEraseEvent& ev);
#endif
void draw(wxDC& dc);
wxSize DoGetBestSize() const override;
#if UPDATE_ON_RESIZE
void on_size(wxSizeEvent& ev);
#endif
wxDECLARE_EVENT_TABLE();
private:
};
wxBEGIN_EVENT_TABLE(ScrollBar, wxControl)
EVT_PAINT(ScrollBar::on_paint)
#if ENABLE_ERASING
EVT_ERASE_BACKGROUND(ScrollBar::on_erace)
#endif
#if UPDATE_ON_RESIZE
EVT_SIZE(ScrollBar::on_size)
#endif
wxEND_EVENT_TABLE()
ScrollBar::ScrollBar(wxWindow* parent, wxWindowID id)
: wxControl(parent, id, wxDefaultPosition, wxDefaultSize, gBorder)
{}
void ScrollBar::on_paint(wxPaintEvent& ev)
{
wxPaintDC dc(this);
draw(dc);
wxSize size = GetClientSize();
wxString text = wxString::Format("%i; %i paint", size.GetWidth(),
size.GetHeight());
dc.DrawText(text, wxPoint(74, 8));
}
#if ENABLE_ERASING
void ScrollBar::on_erace(wxEraseEvent& ev)
{
wxClientDC* clientDC = nullptr;
if (!ev.GetDC())
clientDC = new wxClientDC(this);
wxDC* dc = clientDC ? clientDC : ev.GetDC() ;
draw(*dc);
wxSize size = GetClientSize();
wxString text = wxString::Format("%i; %i erase", size.GetWidth(),
size.GetHeight());
dc->DrawText(text, wxPoint(74, 8));
if (clientDC)
delete clientDC;
}
#endif
void ScrollBar::draw(wxDC& dc)
{
wxSize size = dc.GetSize();
// draw scroll arrows
dc.SetBrush(*wxBLUE_BRUSH);
dc.SetPen( wxPen( wxColor(0,175,175), 2 ) );
dc.DrawRectangle(0, 0, 20, size.GetHeight());
dc.DrawRectangle(size.GetWidth() - 21, 0, 20, size.GetHeight());
// draw background
dc.SetBrush(*wxGREY_BRUSH);
dc.SetPen( wxPen( wxColor(175,175, 0), 2 ) );
dc.DrawRectangle(21, 0, size.GetWidth() - 43, size.GetHeight());
// draw thumb slider
dc.SetBrush(*wxCYAN_BRUSH);
dc.SetPen( wxPen( wxColor(175, 0, 175), 2 ) );
dc.DrawRectangle(70, 7, 150, 20);
dc.SetPen(wxNullPen);
dc.SetBrush(wxNullBrush);
}
wxSize ScrollBar::DoGetBestSize() const
{
return wxSize(-1, 35);
}
#if UPDATE_ON_RESIZE
void ScrollBar::on_size(wxSizeEvent& ev)
{
Refresh();
ev.Skip();
}
#endif
// ********************************************** //
class MyApp: public wxApp
{
wxFrame* frame_;
ScrollBar* sc_bar_;
public:
bool OnInit()
{
if ( !wxApp::OnInit() )
return false;
frame_ = new wxFrame(nullptr, wxID_ANY, "ScBar test App");
sc_bar_ = new ScrollBar(frame_, wxID_ANY);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(new wxButton(frame_, -1, "Tiny Button"), 0, 0, 0);
sizer->Add(sc_bar_, 0, wxEXPAND, 0);
frame_->SetSizer(sizer);
frame_->Show();
return true;
}
};
IMPLEMENT_APP(MyApp)
- Why does statically painted (not change position, size) thumb slider always draw correct and resizing not make any effect on that rect?
And then the flicker wars began. Erasing background not help at all:
#define ENABLE_ERASING 1
Here i find solution need add correct handler for resizing:
#define ENABLE_ERASING 0
#define UPDATE_ON_RESIZE 1
- Is it the correct solution?
- I not understand why i must to do ev.Skip(); in resize event handler?
- And why here, here, here use wxPanel, wxWindow not wxControl maybe i must do the same?
OS Window 7 x64; MinGW 4.8.1; wxWidgets 3.1.0