1

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.

  1. 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)
  1. 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
  1. Is it the correct solution?
  2. I not understand why i must to do ev.Skip(); in resize event handler?
  3. 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

Chantola
  • 540
  • 1
  • 5
  • 18
DeadWarlock
  • 720
  • 6
  • 23

1 Answers1

0

wxWidgets is emphatically not a good choice for writing an application that must have the same appearance under all platforms because this goes straight against wxWidgets design goals which are to be indistinguishable from the native look and feel under each platform.

The only way to use wxWidgets to do what you want to is to use its wxUniversal port which does implement the same appearance everywhere. Be warned though, that it has a number of bugs and missing features compared to the usual ports (wxMSW, wxGTK, wxOSX), so you should be ready to deal with them if you decide to use it. But it would still be a much better idea than using any native port as you're apparently trying to do.

VZ.
  • 21,740
  • 3
  • 39
  • 42
  • However if I implement all controls by inheritance from wxControl. Is it so bad? I will get the opportunity to create skins for my application. – DeadWarlock Sep 15 '14 at 12:45
  • You should use `wxWindow` and not `wxControl` (which is the base class for the native controls). But there is no point in trying to reimplement wxUniversal, start with what is there and improve it if necessary instead. – VZ. Sep 15 '14 at 12:48
  • You say 'wxUniversal' has bugs ((. I batter create my own ;-). I'm so young and stupid, but I try to gain knowledge or smash me head against the granite of Science Can you look on my question and point out errors related to painting. And 'event.Skip()' in resizing handler. Thank you very much. – DeadWarlock Sep 15 '14 at 13:00
  • It's hopeless to try to make a native port like wxUniv, you will constantly run into problems with the way things are done in it. You must either use wxUniv or use something else than wxWidgets entirely. – VZ. Sep 15 '14 at 13:11
  • I try `wxUniversal` port. I got the strange impression that this port is not supported for a long time. All samples has huge flicker problems, sometime they even stop painting. I even have not started creating own application and appearance customization, already has bugs (((. Thx for advice, but I'll stay in my mind and try to create their own version of that port. Maybe you like a **more experienced** user give me some tips on how to do it. – DeadWarlock Sep 18 '14 at 22:40
  • Yes, wxUniv port was unmaintained for quite some time, but a lot of work was done on it this summer, see https://github.com/Daetalus/wxWidgets – VZ. Sep 19 '14 at 14:52