在wxWidgets中创建一个无标题/无边框的可拖动wxFrame

use*_*570 1 c++ events wxwidgets draggable c++11

您好,我正在尝试创建一个 wxApp,它没有默认提供的标题栏(包括最小化、最大化和关闭)图标。我的代码如下: main.h

class MyApp : public wxApp
{
  public:
    virtual bool OnInit();
};

Run Code Online (Sandbox Code Playgroud)

主程序

bool MyApp::OnInit()
{

    MyFrame *prop = new MyFrame(wxT("MyFrame"));
    prop->Show(true);

    return true;
}
Run Code Online (Sandbox Code Playgroud)

myframe.h

class MyFrame : public wxFrame
{
public:
  MyFrame(const wxString& title);
  
  void OnClick(wxMouseEvent& event);

};
Run Code Online (Sandbox Code Playgroud)

myframe.cpp

MyFrame::MyFrame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(250, 130))
{
  MyPanel *panel = new MyPanel(this, wxID_ANY);
  panel->SetBackgroundColour(wxColour(255,255,255));
  MyButton *button = new MyButton(panel, wxID_ANY, wxT("Ok"));

  Connect( wxEVT_LEFT_UP, 
      wxMouseEventHandler(MyFrame::OnClick));

  panel->Centre();
}


void MyFrame::OnClick(wxMouseEvent& event) 
{
  std::cout << "event reached frame class" << std::endl;
  
}
Run Code Online (Sandbox Code Playgroud)

mypanel.h

class MyPanel : public wxPanel
{
public: 
  MyPanel(wxFrame *frame, int id);

  void OnClick(wxMouseEvent& event);
};
Run Code Online (Sandbox Code Playgroud)

mypanel.cpp

MyPanel::MyPanel(wxFrame *frame, int id)
    : wxPanel(frame, id)
{
  Connect( wxEVT_LEFT_UP, 
      wxMouseEventHandler(MyPanel::OnClick));
} 

void MyPanel::OnClick(wxMouseEvent& event) 
{
  std::cout << "event reached panel class" << std::endl;
  
}
Run Code Online (Sandbox Code Playgroud)

mybutton.h

class MyButton : public wxPanel
{
public:
  MyButton(wxPanel *panel, int id, const wxString &label);

  void OnClick(wxMouseEvent& event);

};
Run Code Online (Sandbox Code Playgroud)

mybutton.cpp

void MyButton::onClick(wxMouseEvent &event)
{

}
Run Code Online (Sandbox Code Playgroud)

我想要的是:

  1. 顶部不应有标题栏(包括 3 个最大化、最小化和关闭按钮)。
  2. 现在,由于框架顶部没有标题栏,因此无法拖动或关闭或最大化或最小化窗口。为此,我想在顶部创建一个自定义标题栏,其中应该有三个自定义的最大化、最小化和关闭按钮,而且我应该能够通过双击并按住并拖动新创建的框架的最顶部部分来拖动框架。

这在 wxWidgets 中可能吗?如果是,我怎样才能实现这一目标?

我并不是提出任何新的拖动方式。我们将拥有的新框架/窗口也应该仅由其自己的自定义标题栏拖动。这与在本机情况下通过双击并拖动框架来拖动旧框架完全相同。我只是想自定义原生标题栏。例如增加其高度、更改其颜色、更改三个按钮(最小化、最大化和关闭)的外观。

New*_*odi 7

这是我能想到的最简单的示例,如何创建一个带有伪标题栏的框架,可以单击该标题栏来拖动框架。此示例显示需要处理哪些鼠标事件来拖动窗口以及如何在这些事件处理程序中进行所需的计算。

请注意,移动框架需要在屏幕坐标中完成,但在事件处理程序中接收的坐标将在标题栏的客户端坐标中。此示例还展示了如何进行这些坐标转换。

#include "wx/wx.h"

class CustomTitleBar:public wxWindow
{
public:
    CustomTitleBar(wxWindow* p) : wxWindow(p,wxID_ANY)
    {
        m_dragging = false;

        SetBackgroundColour(*wxGREEN);
        Bind(wxEVT_LEFT_DOWN,&CustomTitleBar::OnMouseLeftDown,this);
        Bind(wxEVT_MOUSE_CAPTURE_LOST, &CustomTitleBar::OnMouseCaptureLost,
             this);
    }

    wxSize DoGetBestClientSize() const override
    {
        return wxSize(-1,20);
    }

private:
    void OnMouseLeftDown(wxMouseEvent& event)
    {
        if ( !m_dragging )
        {
            Bind(wxEVT_LEFT_UP,&CustomTitleBar::OnMouseLeftUp,this);
            Bind(wxEVT_MOTION,&CustomTitleBar::OnMouseMotion,this);
            m_dragging = true;

            wxPoint clientStart = event.GetPosition();
            m_dragStartMouse = ClientToScreen(clientStart);
            m_dragStartWindow = GetParent()->GetPosition();
            CaptureMouse();
        }
    }

    void OnMouseLeftUp(wxMouseEvent&)
    {
        FinishDrag();
    }

    void OnMouseMotion(wxMouseEvent& event)
    {
        wxPoint curClientPsn = event.GetPosition();
        wxPoint curScreenPsn = ClientToScreen(curClientPsn);
        wxPoint movementVector = curScreenPsn - m_dragStartMouse;

        GetParent()->SetPosition(m_dragStartWindow + movementVector);
    }

    void OnMouseCaptureLost(wxMouseCaptureLostEvent&)
    {
        FinishDrag();
    }

    void FinishDrag()
    {
        if ( m_dragging )
        {
            Unbind(wxEVT_LEFT_UP,&CustomTitleBar::OnMouseLeftUp,this);
            Unbind(wxEVT_MOTION,&CustomTitleBar::OnMouseMotion,this);
            m_dragging = false;
        }

        if ( HasCapture() )
        {
            ReleaseMouse();
        }
    }

    wxPoint m_dragStartMouse;
    wxPoint m_dragStartWindow;
    bool m_dragging;
};

class Customframe : public wxFrame
{
public:
    Customframe(wxWindow* p)
        :wxFrame(p, wxID_ANY, wxString(), wxDefaultPosition, wxSize(150,100),
                 wxBORDER_NONE)
    {
        CustomTitleBar* t = new CustomTitleBar(this);
        SetBackgroundColour(*wxBLUE);
        wxBoxSizer* szr = new wxBoxSizer(wxVERTICAL);
        szr->Add(t,wxSizerFlags(0).Expand());
        SetSizer(szr);
        Layout();
    }
};

class MyFrame: public wxFrame
{
public:
    MyFrame():wxFrame(NULL, wxID_ANY, "Custom frame Demo", wxDefaultPosition,
             wxSize(400, 300))
     {
         wxPanel* bg = new wxPanel(this, wxID_ANY);
         wxButton* btn = new wxButton(bg, wxID_ANY, "Custom frame");
         wxBoxSizer* szr = new wxBoxSizer(wxVERTICAL);
         szr->Add(btn,wxSizerFlags(0).Border(wxALL));
         bg->SetSizer(szr);

         Layout();

         btn->Bind(wxEVT_BUTTON, &MyFrame::OnButton, this);
         m_customFrame = NULL;
     }
private:
    void OnButton(wxCommandEvent&)
    {
        if ( m_customFrame )
        {
            m_customFrame->Close();
            m_customFrame = NULL;
        }
        else
        {
            m_customFrame = new Customframe(this);
            m_customFrame->CenterOnParent();
            m_customFrame->Show();
        }
    }

    wxFrame* m_customFrame;
};

class MyApp : public wxApp
{
    public:
        virtual bool OnInit()
        {
            MyFrame* frame = new MyFrame();
            frame->Show();
            return true;
        }
};

wxIMPLEMENT_APP(MyApp);

Run Code Online (Sandbox Code Playgroud)

在 Windows 上,它看起来像这样。

带有自定义标题栏的自定义框架

您应该能够将所需的任何按钮添加到自定义标题栏,就像将按钮添加到任何其他窗口一样。