【问题标题】:How to move the whole window when mouse is on the window's custom widget in Qt?当鼠标在Qt中窗口的自定义小部件上时如何移动整个窗口?
【发布时间】:2018-06-11 05:54:05
【问题描述】:

假设我有一个自定义小部件并将其添加到 qt 的主窗口中。

如您所见,红色区域是自定义小部件。我想要做的是当鼠标在红色区域按下并移动时,整个窗口也会移动。

我知道如何简单地实现mousePressEventmouseMoveEvent;但是在处理带有自定义小部件的窗口时,我不知道在自定义小部件上按下鼠标时如何移动整个窗口。

另外我想提一下,我只希望鼠标在红色区域按下并移动时窗口可移动,而当鼠标在主窗口区域的其余部分按下并移动时,什么都不会发生。

这就是我的CustomWidget 类的样子:

CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent)
{
    setFixedSize(50, 50);
    setStyleSheet("QWidget { background: red; }");
}

void CustomWidget::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.init(this);
    QPainter painter(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
}

void CustomWidget::mousePressEvent(QMouseEvent *event)
{
    xCoord = event->x();
    yCoord = event->y();
}

void CustomWidget::mouseMoveEvent(QMouseEvent *event)
{
    move(event->globalX() - xCoord, event->globalY() - yCoord);
}

如果您想知道我为什么要这样做,在我的应用程序中,我隐藏了标题栏并自己绘制了一个自定义标题栏。但是窗口是不可移动的,所以我想让整个窗口在鼠标按下并在标题栏上移动时可以移动。
希望我解释清楚。

【问题讨论】:

    标签: c++ qt qt5 qwidget qmouseevent


    【解决方案1】:

    要从任何小部件移动窗口,必须能够访问该窗口,为此我们使用返回顶层的方法window(),没有必要分开坐标x()和@ 987654323@,以下代码实现解决方案:

    customwidget.h

    #ifndef CUSTOMWIDGET_H
    #define CUSTOMWIDGET_H
    
    #include <QWidget>
    
    class CustomWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit CustomWidget(QWidget *parent = nullptr);
    protected:
        void paintEvent(QPaintEvent *);
        void mousePressEvent(QMouseEvent *event);
        void mouseMoveEvent(QMouseEvent *event);
    private:
        QPoint startPos;
    };
    
    #endif // CUSTOMWIDGET_H
    

    customwidget.cpp

    #include "customwidget.h"
    
    #include <QMouseEvent>
    #include <QPainter>
    #include <QStyleOption>
    
    CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent)
    {
        setFixedSize(50, 50);
        setStyleSheet("QWidget { background: red; }");
    }
    
    void CustomWidget::paintEvent(QPaintEvent *)
    {
        QStyleOption opt;
        opt.init(this);
        QPainter painter(this);
        style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
    }
    
    void CustomWidget::mousePressEvent(QMouseEvent *event)
    {
        startPos = event->pos();
        QWidget::mousePressEvent(event);
    }
    
    void CustomWidget::mouseMoveEvent(QMouseEvent *event)
    {
        QPoint delta = event->pos() - startPos;
        QWidget * w = window();
        if(w)
            w->move(w->pos() + delta);
        QWidget::mouseMoveEvent(event);
    }
    

    【讨论】:

    • 不需要重新实现paintEvent。小部件默认绘制背景。当你的paintEvent 被调用时,背景已经绘制好了,它是红色的 :) 你还应该声明事件处理程序override,因为你是用 C++11 编写的。
    • @KubaOber 好吧,只需复制示例并添加我需要的内容 :-)
    【解决方案2】:

    如果你在 Windows 上工作,可以使用它:

    #include "mywidget.h"
    #include <windows.h>
    #include <QWindow>
    
    MyWidget::MyWidget(QWidget *parent)
        : QWidget(parent)
    {
    }
    
    MyWidget::~MyWidget()
    {
    
    }
    
    void MyWidget::mousePressEvent(QMouseEvent* event)
    {
        if (event->buttons().testFlag(Qt::LeftButton))
        {
            HWND hWnd = ::GetAncestor((HWND)(window()->windowHandle()->winId()), GA_ROOT);
            POINT pt;
            ::GetCursorPos(&pt);
            ::ReleaseCapture();
            ::SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, POINTTOPOINTS(pt));
        }
    }
    

    【讨论】:

    • 我测试了你的答案,效果也很好。谢谢你的回答,所以我也会赞成你的。但我更喜欢使用 Qt 方法而不是 windows API。
    【解决方案3】:
    void QHexWindow::mousePressEvent(QMouseEvent *event)
    {
        QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
        if (child!=mTitleBar)        //mTitlebar is the QLabel on which we want to implement window drag
        {
            return;
        }
        isMousePressed = true;
        mStartPos = event->pos();
    }
    
    void QHexWindow::mouseMoveEvent(QMouseEvent *event)
    {
        if(isMousePressed)
        {
            QPoint deltaPos = event->pos() - mStartPos;
            this->move(this->pos()+deltaPos);
        }
    }
    
    void QHexWindow::mouseReleaseEvent(QMouseEvent *event)
    {
        QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
        if (child!=mTitleBar)
        {
            return;
        }
        isMousePressed = false;
    }
    

    我已经在我的一个 github 项目 https://github.com/VinuRajaKumar/AVR-HEX-Viewer 中实现了上述功能,其中 QLabel 用作窗口的 TitleBar。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 2018-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多