【问题标题】:wxWidgets painting customization controlswxWidgets 绘画自定义控件
【发布时间】:2014-09-14 13:20:34
【问题描述】:

我想编写一个应用程序,它必须在任何平台上都具有相同的外观。我决定使用 wxWidgets

 (I never have a large amount of work with this library).

从 ScrollBar 开始我的自定义。这是一个糟糕的决定,

(inheritance from wxScrollBar = because all control badly flickering)

因为在 OS Windows 下默认 ScrollBar 的自定义能力很差,explanation here。接下来我的步骤是进行与this post 相同的工作,但使用 wxWidgets 而不是 MFC。

  1. 最好在一个窗口上绘制所有控件,或者用自己的窗口替换每个 4 部分:滚动背景、拇指滑块、2 个滚动箭头?需要建议。

我先选了:

#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. 为什么静态绘制(不改变位置、大小)拇指滑块总是正确绘制并且调整大小不会对该矩形产生任何影响?

然后闪烁的战争开始了。擦除背景根本没有帮助:

#define ENABLE_ERASING 1

Here 我发现解决方案需要添加正确的处理程序来调整大小:

#define ENABLE_ERASING 0
#define UPDATE_ON_RESIZE 1
  1. 这是正确的解决方案吗?
  2. 我不明白为什么我必须这样做 ev.Skip(); 在 resize 事件处理程序中?
  3. 为什么hereherehere 使用 wxPanel、wxWindow 而不是 wxControl,也许我必须这样做?

操作系统窗口 7 x64; MinGW 4.8.1; wxWidgets 3.1.0

【问题讨论】:

    标签: c++ wxwidgets


    【解决方案1】:

    对于编写必须在所有平台下具有相同外观的应用程序来说,wxWidgets 显然不是一个好的选择,因为这直接违背了 wxWidgets 的设计目标,即在每个平台下都与本机外观没有区别。

    使用 wxWidgets 做你想做的事的唯一方法是使用它的 wxUniversal 端口,它在任何地方都实现了相同的外观。但请注意,与通常的端口(wxMSW、wxGTK、wxOSX)相比,它有许多错误和缺失的功能,所以如果你决定使用它,你应该准备好处理它们。但这仍然比使用任何本地端口要好得多,因为您显然正在尝试这样做。

    【讨论】:

    • 但是,如果我通过从 wxControl 继承来实现所有控件。有这么糟糕吗?我将有机会为我的应用程序创建皮肤。
    • 您应该使用wxWindow 而不是wxControl(这是本机控件的基类)。但是尝试重新实现 wxUniversal 是没有意义的,而是从现有的内容开始并在必要时对其进行改进。
    • 你说'wxUniversal'有错误((。我创造了我自己的;-)。我如此年轻和愚蠢,但我试图获得知识或将我的头撞到科学的花岗岩上你能看看我的问题并指出与绘画相关的错误吗?以及调整大小处理程序中的“event.Skip()”。非常感谢。
    • 尝试做一个像wxUniv这样的原生端口是没有希望的,你会不断地遇到问题。你必须要么使用 wxUniv,要么完全使用 wxWidgets 以外的东西。
    • 我试试wxUniversal 端口。我有一个奇怪的印象,这个端口很长时间不支持。所有样品都存在严重的闪烁问题,有时甚至会停止绘画。我什至还没有开始创建自己的应用程序和外观自定义,已经有错误(((。谢谢建议,但我会留在我的脑海中并尝试创建他们自己的那个端口版本。也许你喜欢 more有经验的用户给我一些提示。
    猜你喜欢
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-07
    • 2013-01-16
    相关资源
    最近更新 更多