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

后端 未结 2 490
说谎
说谎 2021-01-28 19:02

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 <

相关标签:
2条回答
  • 2021-01-28 19:32

    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"
    
    0 讨论(0)
  • 2021-01-28 19:42

    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.

    0 讨论(0)
提交回复
热议问题