当鼠标位于Qt窗口的自定义小部件上时,如何移动整个窗口?

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

enter image description here

如您所见,红色区域是自定义小部件。我想做的是当鼠标按在红色区域并移动时,整个窗口也会移动。
我知道如何简单地实现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);
}

如果你想知道我为什么想要这样做,在我的应用程序中,我隐藏了标题栏,并自己绘制了一个自定义标题栏。但窗口无法移动,所以我希望当鼠标在标题栏上按下并移动时,整个窗口可以移动。
希望我表达清楚了。
3个回答

6

要移动窗口,需要能够访问窗口,并使用方法window()返回顶层窗口,不需要分别使用坐标x()y(),以下代码实现了解决方案:

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);
}

2
不需要重新实现paintEvent。小部件默认绘制它们的背景。在调用paintEvent时,背景已经被绘制了,而且是红色的 :) 你还应该声明事件处理程序为override,因为你正在使用C++11编写。 - Kuba hasn't forgotten Monica
@KubaOber 好的,只需复制示例并添加我所需的即可 :-) - eyllanesc

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。 - Theodore Tang

1
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被用作窗口的标题栏。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接