В Windows, когда я создаю QMainWindow, я могу перемещать его по экрану, щелкая строку заголовка и перетаскивая его.
В моем приложении я скрыл строку заголовка, используя setWindowFlags(Qt::CustomizeWindowHint)
и я пытаюсь построить собственную строку заголовка с помощью виджета и установить его в пространстве меню с помощью setMenuWidget(myWidget)
,
Теперь я хочу воспроизвести оригинальное поведение: я хочу нажать на мой MyWidget
виджет внутри QMainWindow и, пока мышь нажата, перетаскивание мыши перемещает окно.
Есть ли способ сделать это?
Вам просто нужно реализовать необходимую обработку событий мыши путем перезаписи MyWidget
«s mousePressEvent()
, mouseMoveEvent()
а также mouseReleaseEvent()
обработчики.
Вы можете получить окно (виджет верхнего уровня) изнутри MyWidget
сквозь window()
метод.
Это пример того, как реализовать поддельную строку заголовка со стандартными кнопками (свернуть, развернуть, закрыть), и ее можно перетаскивать для перемещения всего окна (это основано на подходе в ответе @ 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"