【问题标题】:Move a window by clicking an internal widget instead of title bar通过单击内部小部件而不是标题栏来移动窗口
【发布时间】:2017-02-10 14:33:07
【问题描述】:

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

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

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

有办法吗?

【问题讨论】:

    标签: c++ qt window mousemove titlebar


    【解决方案1】:

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

    #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】:

      您只需要通过覆盖MyWidgetmousePressEvent()mouseMoveEvent()mouseReleaseEvent() 处理程序来实现必要的鼠标事件处理。

      1. 检测鼠标向下,获取当前鼠标位置
      2. 移动时,获取当前鼠标位置,计算差异,保存新位置,按差异移动窗口

      您可以通过window() 方法从MyWidget 内部获取窗口(顶级小部件)。

      【讨论】:

        猜你喜欢
        • 2014-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-17
        • 1970-01-01
        • 2020-08-08
        相关资源
        最近更新 更多