Move a window by clicking an internal widget instead of title bar

心已入冬 提交于 2019-12-20 07:26:27

问题


In Windows when I create a QMainWindow I can move it around the screen by clicking the title bar and dragging it.

In my application I've hidden the title bar by using setWindowFlags(Qt::CustomizeWindowHint) and I'm trying to build a custom title bar using a widget and setting it in the menu space with setMenuWidget(myWidget).

Now I want to reproduce the original behaviour: I want to click on my MyWidget widget inside the QMainWindow and, while mouse is pressed, dragging the mouse moves the window.

Is there a way to do it?


回答1:


This is an example on how to implement a fake title bar, that has standard buttons (minimize, maximize, close), and can be dragged to move the whole window (this is based on the approach in @Kevin's answer).

#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"



回答2:


You just need to implement the necessary mouse event handling by overwriting MyWidget's mousePressEvent(), mouseMoveEvent() and mouseReleaseEvent() handlers.

  1. Detect the mouse down, get current mouse position
  2. While moving, get current mouse position, calculate difference, save new position, move window by diff

You can get the window (top level widget) from inside MyWidget through the window() method.



来源:https://stackoverflow.com/questions/39818192/move-a-window-by-clicking-an-internal-widget-instead-of-title-bar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!