(按下+下拉)按钮wxWidgets

时间:2016-05-06 16:06:15

标签: wxwidgets

我需要一个带按钮和下拉按钮的控件。

e.g。

this button is available in ribbon control

wxRibbonButtonBar中提供了类似的控件,我无法在简单的wxPanel中使用它。

4 个答案:

答案 0 :(得分:3)

我实现了SplitButton,它看起来像:

enter image description here

<强> SplitButton.h

#ifndef __SPLIT_BUTTON_H__
#define __SPLIT_BUTTON_H__

#include <wx/wx.h>
#include <wx/menu.h>

class SplitButton : public wxPanel
{
public:
    SplitButton(wxWindow *parent,
        wxWindowID id,
        const wxString& label,
        const wxPoint& pos = wxDefaultPosition,
        const wxSize& size = wxDefaultSize);

    ~SplitButton();

    wxMenu* GetSplitButtonMenu();

protected:
    void OnKillFocus(wxFocusEvent& event);
    void OnMouseLeave(wxMouseEvent& event);
    void OnMouseEnter(wxMouseEvent& event);
    void OnLeftButtonUp(wxMouseEvent& event);
    void OnLeftButtonDown(wxMouseEvent& event);
    void OnPaint(wxPaintEvent& WXUNUSED(event));

    bool Enable(bool enable = true) override;

private:
    int m_stateButton = 0;
    int m_stateMenu = 0;
    bool m_bIsEnable = true;
    wxColor m_colorNormal;
    wxColor m_colorDisabled;
    const int m_arrowButtonWidth = 20;
    bool m_bLButtonDown = false;
    wxString m_label;
    wxMenu* m_pMenu = nullptr;
};

#endif /*__SPLIT_BUTTON_H__*/

<强> SplitButton.cpp

#include "SplitButton.h"
#include <wx/renderer.h>

SplitButton::SplitButton(wxWindow *parent,
    wxWindowID id,
    const wxString& label,
    const wxPoint& pos,
    const wxSize& size)
    : wxPanel(parent, id, pos, size, wxBORDER_NONE | wxTAB_TRAVERSAL, "DropDownButton"),
    m_label(label)
{
    m_colorNormal = GetForegroundColour();
    m_colorDisabled = GetForegroundColour().MakeDisabled();

    if (size == wxDefaultSize)
    {
        wxSize defaultSize = wxButton::GetDefaultSize();

        wxSize textSize = GetTextExtent(m_label);
        textSize.SetWidth(textSize.GetWidth() + m_arrowButtonWidth + 20);
        SetMinSize(wxSize(textSize.GetWidth(), defaultSize.GetHeight()));
    }

    Bind(wxEVT_PAINT, &SplitButton::OnPaint, this);
    Bind(wxEVT_LEFT_UP, &SplitButton::OnLeftButtonUp, this);
    Bind(wxEVT_LEFT_DOWN, &SplitButton::OnLeftButtonDown, this);
    Bind(wxEVT_KILL_FOCUS, &SplitButton::OnKillFocus, this);
    Bind(wxEVT_LEAVE_WINDOW, &SplitButton::OnMouseLeave, this);
    Bind(wxEVT_ENTER_WINDOW, &SplitButton::OnMouseEnter, this);

    m_pMenu = new wxMenu();
}

SplitButton::~SplitButton()
{
    delete m_pMenu;
    m_pMenu = nullptr;
}

wxMenu* SplitButton::GetSplitButtonMenu()
{
    return m_pMenu;
}

void SplitButton::OnKillFocus(wxFocusEvent& event)
{
    m_stateButton = wxCONTROL_CURRENT;
    m_stateMenu = wxCONTROL_CURRENT;
    Refresh();

    event.Skip();
}

void SplitButton::OnMouseLeave(wxMouseEvent& event)
{
    m_stateButton = 0;
    m_stateMenu = 0;
    Refresh();

    event.Skip();
}

void SplitButton::OnMouseEnter(wxMouseEvent& event)
{
    m_stateButton = wxCONTROL_CURRENT;
    m_stateMenu = wxCONTROL_CURRENT;
    Refresh();

    event.Skip();
}

void SplitButton::OnLeftButtonUp(wxMouseEvent& event)
{
    m_stateButton = 0;
    m_stateMenu = 0;

    Refresh();

    int x = -1;
    int y = -1;
    event.GetPosition(&x, &y);

    if (x < (GetSize().GetWidth() - m_arrowButtonWidth))
    {
        wxEvtHandler* pEventHandler = GetEventHandler();
        wxASSERT(pEventHandler);

        pEventHandler->CallAfter([=]()
        {
            wxCommandEvent evt(wxEVT_BUTTON, this->GetId());
            evt.SetEventObject(this);
            GetEventHandler()->ProcessEvent(evt);
        });
    }

    m_bLButtonDown = false;

    event.Skip();
}

void SplitButton::OnLeftButtonDown(wxMouseEvent& event)
{
    m_bLButtonDown = true;

    int x = -1;
    int y = -1;
    event.GetPosition(&x, &y);

    if (x >= (GetSize().GetWidth() - m_arrowButtonWidth))
    {
        m_stateButton = 0;
        m_stateMenu = wxCONTROL_PRESSED;
        Refresh();

        wxSize size = GetSize();
        wxPoint position;
        position.x = 0;
        position.y = size.GetHeight();
        PopupMenu(m_pMenu, position);

        m_stateMenu = 0;
        Refresh();
    }
    else
    {
        m_stateButton = wxCONTROL_PRESSED;
        m_stateMenu = wxCONTROL_PRESSED;
        Refresh();
    }

    event.Skip();
}

void SplitButton::OnPaint(wxPaintEvent& WXUNUSED(event))
{
    wxPaintDC dc(this);
    wxSize size = GetSize();
    const int width = size.GetWidth() - m_arrowButtonWidth;

    // Draw first part of button
    wxRect r1;
    r1.x = 0;
    r1.y = 0;
    r1.width = width + 2;
    r1.height = size.GetHeight();

    wxRendererNative::Get().DrawPushButton(this, dc, r1, m_stateButton);

    SetForegroundColour(m_bIsEnable ? m_colorNormal : m_colorDisabled);

    r1.y += (size.GetHeight() - GetCharHeight()) / 2;
    dc.DrawLabel(m_label, r1, wxALIGN_CENTER_HORIZONTAL);

    // Draw second part of button
    wxRect r2;
    r2.x = width - 2;
    r2.y = 0;
    r2.width = m_arrowButtonWidth;
    r2.height = size.GetHeight();

    wxRendererNative::Get().DrawPushButton(this, dc, r2, m_stateMenu);
    wxRendererNative::Get().DrawDropArrow(this, dc, r2, m_stateMenu);
}

bool SplitButton::Enable(bool enable)
{
    m_bIsEnable = enable;
    wxPanel::Enable(m_bIsEnable);

    if (m_bIsEnable)
    {
        m_stateButton = 0;
        m_stateMenu = 0;
    }
    else
    {
        m_stateButton = wxCONTROL_DISABLED;
        m_stateMenu = wxCONTROL_DISABLED;
    }

    wxPaintEvent event;
    ProcessEvent(event);
    Refresh();

    return enable;
}

答案 1 :(得分:1)

这种按钮没有wxwidgets。但是如果您使用的是win32且wxwidgets为3.1+,则可以尝试使用nativewindow

请参阅wxwidget包附带的示例文件

%wxpath%\的wxWidgets-3.1.0 \样品\部件\ native.cpp

class NativeWindow : public wxNativeWindow
{
public:
    explicit NativeWindow(wxWindow* parent)
        : wxNativeWindow()
    {
        // When creating the native window, we must specify the valid parent
        // and while we don't have to specify any position if it's going to be
        // laid out by sizers, we do need the size.
        const wxSize size = FromDIP(wxSize(140, 30));

        HWND hwnd = ::CreateWindow
                      (
                        TEXT("BUTTON"),
                        TEXT("Press me to do it"),
                        WS_CHILD | WS_VISIBLE | BS_SPLITBUTTON,
                        0, 0, size.x, size.y,
                        (HWND)parent->GetHWND(), 0, NULL, NULL
                      );
        if ( !hwnd )
        {
            wxLogError("Creating split button failed.");
            return;
        }

        (void)Create(parent, wxID_ANY, hwnd);
    }

enter image description here

更新:解决方法是使用两个按钮来模拟组合按钮,不要忘记设置wxBU_EXACTFIT并调整板 enter image description here

答案 2 :(得分:1)

我建议使用wxNativeWindow和3.1+,但是还有另一个可能适合您的解决方案,可用于3.0:使用wxToolBar并使用{{添加工具1}}风格。

答案 3 :(得分:1)

看看wxOwnderDrawComboBox。