c++ - 通过单击内部小部件而不是标题栏来移动窗口

标签 c++ qt window mousemove titlebar

在 Windows 中,当我创建 QMainWindow 时,我可以通过单击标题栏并拖动它来在屏幕上移动它。

在我的应用程序中,我使用 setWindowFlags(Qt::CustomizeWindowHint) 隐藏了标题栏,我正在尝试使用小部件构建自定义标题栏并将其设置在菜单空间中使用 setMenuWidget(myWidget)

现在我想重现原来的行为:我想在 QMainWindow 中单击我的 MyWidget 小部件,并在按下鼠标的同时拖动鼠标移动窗口。

有办法吗?

最佳答案

这是一个关于如何实现假标题栏的示例,它具有标准按钮(最小化、最大化、关闭),并且可以拖动以移动整个窗口(这是基于@Kevin 的回答中的方法)。

screenshot

#include <QtWidgets>


class FakeTitleBar : public QWidget{
    Q_OBJECT
public:
    explicit FakeTitleBar(QWidget* parent= nullptr):QWidget(parent){
        label.setSizePolicy(QSizePolicy::Expanding,
                            QSizePolicy::Expanding);
        layout.addWidget(&label);
        layout.addWidget(&buttonMinimize);
        layout.addWidget(&buttonMaximize);
        layout.addWidget(&buttonClose);
        //connecting buttons' signals to slots
        connect(&buttonMinimize, &QPushButton::clicked,
                this, &FakeTitleBar::MinimizeWindow);
        connect(&buttonMaximize, &QPushButton::clicked,
                this, &FakeTitleBar::MaximizeWindow);
        connect(&buttonClose, &QPushButton::clicked,
                this, &FakeTitleBar::CloseWindow);
        //setting vertical fixed size policy
        //so that the title bar does not take up any additional space
        setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
        //a bit of styling
        setStyleSheet("QPushButton {margin:0px; padding:5px;}"
                      "QWidget {background-color:blue; color:white;}");
    }

public slots:
    //slots for corresponding buttons
    void MinimizeWindow(){
        window()->showMinimized();
    }
    void MaximizeWindow(){
        if(!window()->isMaximized())
            window()->showMaximized();
        else
            window()->showNormal();
    }
    void CloseWindow(){
        window()->close();
    }

protected:
    void mousePressEvent(QMouseEvent* event){
        //save the press position (this is relative to the current widget)
        pressPos= event->pos();
        isMoving= true;
    }
    void mouseMoveEvent(QMouseEvent* event){
        //isMoving flag makes sure that the drag and drop event originated
        //from within the titlebar, because otherwise the window shouldn't be moved
        if(isMoving){
            //calculate difference between the press position and the new Mouse position
            //(this is relative to the current widget)
            QPoint diff= event->pos() - pressPos;
            //move the window by diff
            window()->move(window()->pos()+diff);
        }
    }
    void mouseReleaseEvent(QMouseEvent* /*event*/){
        //drag and drop operation end
        isMoving= false;
    }
    //double-clicking on the title bar should maximize the window
    void mouseDoubleClickEvent(QMouseEvent* /*event*/){
        MaximizeWindow();
    }
    //in order for the style sheet to apply on this custom widget
    //see https://doc.qt.io/qt-5/stylesheet-reference.html#qwidget-widget
    void paintEvent(QPaintEvent *)
    {
        QStyleOption opt;
        opt.init(this);
        QPainter p(this);
        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    }

private:
    QHBoxLayout layout{this};
    QLabel label{"Fake Title Bar"};
    QPushButton buttonMinimize{"-"};
    QPushButton buttonMaximize{"M"};
    QPushButton buttonClose{"X"};
    QPoint pressPos;
    bool isMoving{false};
};

//sample usage

class Widget : public QWidget{
public:
    explicit Widget(QWidget* parent= nullptr):QWidget(parent){
        setWindowFlags(Qt::CustomizeWindowHint);
        layout.addWidget(&titleBar);
        layout.addWidget(&label);
        layout.setContentsMargins(0, 0, 0, 0);
        label.setAlignment(Qt::AlignCenter);
        //default size for the window
        resize(320,240);
    }
    ~Widget(){}

private:
    QVBoxLayout layout{this};
    FakeTitleBar titleBar;
    QLabel label{"this is a sample window"};
};

int main(int argc, char* argv[]) {
    QApplication app(argc, argv);

    Widget w;
    w.show();

    return app.exec();
}

#include "main.moc"

关于c++ - 通过单击内部小部件而不是标题栏来移动窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39818192/

相关文章:

c++ - QT 在另一个小部件中插入小部件

c++ - 从具有可选基数的字符串中解析数字

android - 在android中为对话框窗口添加边框

macos - CGWindowListCopyWindowInfo、kCGWindowLayer 和窗口级别

c++ - 通过检查其返回值作为 -32767 和 0x8000 来使用 GetAsyncKeyState() 有什么区别?

c++ - 如何将整数转换为字符串

c++ - 可以检索 Windows 待机计时器吗?

c++ - 空句柄错误

linux - 如何使用 opencv 和 qt 为 Yocto linux 镜像编译程序?

c++ - 将窗口设置为最顶层