How to set focus to non-modal QDialog when application becomes active? - c++

I have a MainWindow with a non-modal QDialog and a QPushButton just for the purpose of showing the dialog. When the application is minimised and maximised again, I want the dialog, if visible, to regain keyboard focus.
Here is the code:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
QDialog *dialog;
public:
explicit MainWindow(QWidget *parent = nullptr);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPushButton>
#include <QDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
dialog(new QDialog(this))
{
QPushButton *button = new QPushButton("show dialog", this);
connect(button, &QPushButton::clicked, dialog, &QDialog::show);
setCentralWidget(button);
}
Sounds very simple but I have tried various approaches without any luck:
Approach 1:
Listen to QApplication::applicationStateChanged() signal and set focus to dialog when application state becomes active.
Approach 2:
Listen to dialog's show and window activate events and setting focus when triggered.
Approach 3:
Listen to main window's show and window activate events and setting focus when triggered.
Here is the code with the above approaches implemented:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
QDialog *dialog;
public:
explicit MainWindow(QWidget *parent = nullptr);
virtual bool event(QEvent *event) override;
virtual bool eventFilter(QObject *watched, QEvent *event) override;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPushButton>
#include <QDialog>
#include <QEvent>
#include <QApplication>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
dialog(new QDialog(this))
{
QPushButton *button = new QPushButton("show dialog", this);
connect(button, &QPushButton::clicked, dialog, &QDialog::show);
setCentralWidget(button);
dialog->installEventFilter(this);
//set focus on dialog when app becomes active
connect(qApp, &QApplication::applicationStateChanged, this, [this](Qt::ApplicationState state){
if (dialog->isVisible() && state == Qt::ApplicationActive) {
dialog->setFocus();
}
});
}
bool MainWindow::event(QEvent *event)
{
//set focus on dialog when main window is shown or activated
if (event->type() == QEvent::Show || event->type() == QEvent::WindowActivate) {
if (dialog->isVisible()) {
dialog->setFocus();
}
}
return QMainWindow::event(event);
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
//set focus on dialog when dialog is shown or activated
if (watched == dialog) {
if (event->type() == QEvent::Show || event->type() == QEvent::WindowActivate) {
dialog->setFocus();
}
}
return QMainWindow::eventFilter(watched, event);
}

An approach that works is listening to the QApplication::applicationStateChanged() signal and calling QWindow::requestActivate() when app becomes active:
connect(qApp, &QApplication::applicationStateChanged, this, [this](Qt::ApplicationState state){
if (dialog->isVisible() && state == Qt::ApplicationActive) {
if (dialog->windowHandle()) dialog->windowHandle()->requestActivate();
}
});
Not sure why QWindow::requestActivate() works but QWidget::setFocus() doesn't when both functions are supposed to give keyboard focus, according to the docs. If anyone knows please comment below.

Related

How to identify the pressed button in Qt C++?

I have 4 buttons on my main window. Each button opens its own window with its own data. How to identify the pressed button to open right window? For example: I press sales button and it opens a window that shows information about ticket sales.
Mainwindow ui
Here is my code from mainwindow h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <sales.h>
#include <theatres.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void button_pressed();
private:
Ui::MainWindow *ui;
sales *s;
theatres *t;
};
#endif // MAINWINDOW_H
And here is my code from mainwindow cpp:
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "build/sqlite/sqlite3.h"
#include <QtSql/QSqlDatabase>
#include <QTableView>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect((*ui).pushButton,SIGNAL(released()), this, SLOT(button_pressed()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::button_pressed()
{
s = new sales(this);
s -> show();
}
As Andy Newman already answered
the shortest solution is a lambda function
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QHBoxLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QHBoxLayout *h_layout = new QHBoxLayout;
centralWidget()->setLayout(h_layout);
for(int c =1; c <= 10; c++)
{
QPushButton *button = new QPushButton(this); // create button
button->setText(QString::number(c)); // set button id
h_layout->addWidget(button); // add a button to the form
// lambda magic
/* connecting a button signal to a lambda function that captures a pointer to a
button and invokes an arbitrary type function. */
connect(button, &QPushButton::clicked, [this, button]() {
pressedButton(button->text());
});
}
}
void MainWindow::pressedButton(const QString &id_button)
{
qDebug("Pressed button: %ls", id_button.utf16());
}
MainWindow::~MainWindow()
{
delete ui;
}
#include "widget.h"
#include "./ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->btn_0,&QPushButton::clicked,this,&Widget::SlotButtonClicked);
connect(ui->btn_1,&QPushButton::clicked,this,&Widget::SlotButtonClicked);
connect(ui->btn_2,&QPushButton::clicked,this,&Widget::SlotButtonClicked);
connect(ui->btn_3,&QPushButton::clicked,this,&Widget::SlotButtonClicked);
}
Widget::~Widget()
{
delete ui;
}
void Widget::SlotButtonClicked()
{
auto sender = this->sender();
if ( sender == ui->btn_0 ) {
// Click btn_0 to open widget0
} else if ( sender == ui->btn_1 ) {
// Click btn_1 to open widget1
} else if ( sender == ui->btn_2 ) {
// Click btn_2 to open widget2
} else if ( sender == ui->btn_3 ) {
// Click btn_3 to open widget3
}
}
If you can use Qt Designer, the best way to do this is to click with button right on the QPushButton (On .ui file in Qt Designer) and click to "Go to Slot", this will create a private slot to this button! In the header file will create the definition, like this:
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
And in the source file (.cpp) will create the "function" clicked pushButton:
void MainWindow::on_pushButton_clicked()
{
}
void MainWindow::on_pushButton_2_clicked()
{
}
void MainWindow::on_pushButton_3_clicked()
{
}
void MainWindow::on_pushButton_4_clicked()
{
}
Inside of the "function" in .cpp, you put the task that you want this button to do, in this case, to open a new window!
When you click "go to slot" in another button, will create another private slot with the respective number (If is the second QPushButton that you create, the private slot will be called by pushButton_2).
The usual way to do this would be to connect the 4 different buttons to 4 different slots. It looks like you are using QtDesigner so that shouldn't be an issue.
If you were generating an array of buttons at run time you'd run into problems and would need a different solution. You could try something like this to pass an array index to the function, for example:
connect(button[x], &QPushButton::clicked, this, [this, x]() { button_pressed(x); });
Or you could do it the Qt way, which would be to call ::setProperty to store data in the button, and then retrieve it from the event, but it's so esoteric that I can't actually remember how to do that...

Trouble with Event Filter for key presses

I am trying to learn how to make software with GUIs using QtCreator. I've done some programming before, but never anything this involved. So far, I have made a window with 5 items: 2 labels, 1 button, 1 lineEdit, and 1 listWidget.
My goal is to be able to enter text in the lineEdit and make it appear in the listWidget. If you click on the button with the mouse, this works fine.
I would also like to be able to use the enter/return key on a keyboard to activate the button. This is the part I need help with.
I created a new class for handling key events called KeyboardFilter.
I have installed the event filter on the main window object. The eventFilter function should receive any event, check if it's a key event, then check if it's the enter button. If it is, then I want to activate the button.
I can't tell if any of the stuff I've written for the eventFilter is actually working.
// == keyboardfilter.h =======================================================
#ifndef KEYBOARDFILTER_H
#define KEYBOARDFILTER_H
#include <QApplication>
#include <QLineEdit>
#include <QKeyEvent>
class KeyboardFilter : public QObject
{
public:
KeyboardFilter( QObject *parent = nullptr ) : QObject( parent ) {}
//protected:
public:
bool eventFilter( QObject *target, QEvent *event );
};
#endif // KEYBOARDFILTER_H
// == mainwindow.h ===========================================================
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
// handles clicking the enter button with the mouse
//private slots:
public slots:
void EnterPressed();
// supposed to handle key presses. doesn't actually work
//protected:
public:
void KeyPressEvent(QKeyEvent *event);
void KeyReleaseEvent(QKeyEvent *event);
bool EventFilter(QEvent *event);
};
#endif // MAINWINDOW_H
// == keyboardfilter.cpp =====================================================
#include "keyboardfilter.h"
bool KeyboardFilter::eventFilter(QObject *target, QEvent *event)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
return true;
}
}
if(event->type() == QEvent::KeyRelease){
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
return true;
}
}
return false;
}
// == mainwindow.cpp =========================================================
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include <QKeyEvent>
#include <iostream>
QString stack[10];
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
stack[1] = "stack";
ui->Display->addItem(stack[1]);
connect(ui->Enter, SIGNAL(released()), this, SLOT(EnterPressed()));
}
MainWindow::~MainWindow()
{
delete ui;
}
//qDebug() << "Debug Message";
//QDebug("text");
void MainWindow::EnterPressed(){
//ui->Input->setText(QString("text"));
ui->Display->clear();
QString input = ui->Input->text();
ui->Input->clear();
ui->Display->addItem(input);
}
// -- keyboardfilter.cpp
#include "keyboardfilter.h"
bool KeyboardFilter::eventFilter(QObject *target, QEvent *event)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
return true;
}
}
if(event->type() == QEvent::KeyRelease){
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
return true;
}
}
return false;
}
// == main.cpp ===============================================================
#include "mainwindow.h"
#include "keyboardfilter.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
// KeyboardFilter filter;
// a.installEventFilter(&filter);
KeyboardFilter* key = new KeyboardFilter();
w.installEventFilter(key);
if(key){
w.EnterPressed();
}
return a.exec();
}
When I run this code, the window pops up and I can enter text into the lineEdit. If I click the button with the mouse, the text gets moved to the listWidget, as desired. If I enter text and then hit "Enter", nothing happens.
I have tried hitting tab to give focus to the lineEdit, listWidget, and button before hitting enter, but hasn't helped though.
Maybe Qt docs for installEventFilter isn't absolutely clear, you need to install event filter to the object which events you want to filter. In your case it is QLineEdit(Input?) and not the MainWindow. Also you don't need actually extra class for event filter. you could override eventFilte of your MainWindow and install it on QLineEdit. Just be sure to return false if you don't want to stop processing event.
Here is how that could look:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLineEdit>
#include <QKeyEvent>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
private:
Ui::MainWindow *ui;
public slots:
void EnterPressed();
bool eventFilter(QObject *target, QEvent *event) override;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QKeyEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//... your code here
this->ui->Input->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::EnterPressed(){
//.... your code here
}
bool MainWindow::eventFilter(QObject *target, QEvent *event)
{
if(target != this->ui->Input)return false;
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
qDebug() << "eventFilter Enter pressed";
this->EnterPressed(); // call your slot
return true;
}
}
if(event->type() == QEvent::KeyRelease){
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter){
qDebug() << "eventFilter Enter pressed released";
return true;
}
}
return false;
}
A simple way to catch Enter/Return keys globally is using QShortcut and, then, connect the trigger event to button click.
QWidget *widget = new QWidget(this); //The main window central widget
QLineEdit *edit = new QLineEdit(this); //Your edit
QPushButton *button = new QPushButton("Accept", this); //Your button
QLabel *label = new QLabel(this); //Your label
QHBoxLayout *layout = new QHBoxLayout(widget); //Arrange items horizontally
layout->addWidget(edit);
layout->addWidget(button);
layout->addWidget(label);
connect(button, &QPushButton::clicked, this, [=](bool checked){ //The button clicked event
Q_UNUSED(checked)
label->setText(edit->text());
edit->clear();
});
QShortcut *shortcut_return = new QShortcut(Qt::Key_Return, this); //The return shortcut event
connect(shortcut_return, &QShortcut::activated, button, &QPushButton::click);
QShortcut *shortcut_enter = new QShortcut(Qt::Key_Enter, this); //The enter shortcut event
connect(shortcut_enter, &QShortcut::activated, button, &QPushButton::click);
button->setDefault(true); //Set the button as default
setCentralWidget(widget);

Slot for QListView::doubleClicked not getting called

I have a QListView named listView. It is the only widget in the MainWindow. I want to track the double clicks on the listView. So, I did this:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
listView = new QListView(this);
this->setCentralWidget(listView);
connect(listView, &QListView::doubleClicked, this, &MainWindow::onDoubleClicked);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow :: onDoubleClicked(const QModelIndex &index)
{
QMessageBox :: information(this, "Info", "List view was double clicked at\nColumn: " + QString :: number(index.column()) + " and Row: " + QString::number(index.row()));
}
But when I double click the listView a get no message box
If the docs are reviewed:
void QAbstractItemView::doubleClicked(const QModelIndex &index)
This signal is emitted when a mouse button is double-clicked. The item
the mouse was double-clicked on is specified by index. The signal is
only emitted when the index is valid.
In your case, your QListView does not have a model, so when you click there is no valid QModelIndex, so the signal will not be emitted.
If you want to follow the double-click event there are 2 possible solutions:
Create a QListView and overwrite the mouseDoubleClickEvent event.
Or use an event filter.
In my solution I will use the second method:
*.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QListView;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
bool eventFilter(QObject *watched, QEvent *event);
private:
Ui::MainWindow *ui;
QListView *listView;
};
#endif // MAINWINDOW_H
*.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QEvent>
#include <QListView>
#include <QMouseEvent>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
listView = new QListView;
this->setCentralWidget(listView);
listView->viewport()->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if(watched == listView->viewport() && event->type() == QEvent::MouseButtonDblClick){
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
qDebug()<<"MouseButtonDblClick"<<mouseEvent->pos();
}
return QMainWindow::eventFilter(watched, event);
}

How to Pass QMainWindow mouse clicked position to QGraphicsView

I have a display window like this:
Above display widgets are QGraphicsView widgets (they are in a QGridLayout) and what I want to achieve is that:
when user click in MainWindow, I want to seize that clicked position and decide which QGraphicsView widget contains that position and set the border of that selected QGraphicsView widget to green color. And only one QGraphicView widget can be selected at a time.
Can anyone give me some ideas?
Thanks
You can use installEventFilter for your QGraphicsViews and detect mouse press events on them. So, you can define current view and make border for it as you want. Small example:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsView>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public:
bool eventFilter(QObject* watched, QEvent* event) override;
private:
Ui::MainWindow *ui;
QGraphicsView* view1_;
QGraphicsView* view2_;
QGraphicsView* selectedView_;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGridLayout>
#include <QMessageBox>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
view1_(nullptr),
view2_(nullptr),
selectedView_(nullptr)
{
ui->setupUi(this);
QGridLayout* grid = new QGridLayout(this->centralWidget());
view1_ = new QGraphicsView(this);
view2_ = new QGraphicsView(this);
grid->addWidget(view1_, 0, 0);
grid->addWidget(view2_, 0, 1);
view1_->viewport()->installEventFilter(this);
view2_->viewport()->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject* watched, QEvent* event)
{
qDebug() << event->type();
if (event->type() == QEvent::MouseButtonPress)
{
if (watched == view1_->viewport()){
selectedView_ = view1_;
QMessageBox::information(this, "!", "First");
return false;
}
else if (watched == view2_->viewport()){
selectedView_ = view2_;
QMessageBox::information(this, "!", "Second");
return false;
}
}
return QMainWindow::eventFilter(watched, event);
}
If you only want to change the border color on mouse hover, you wouldn't need such complicated programming. Qt supports style sheets, just like CSS.
In this case, it's enough to attach the following stylesheet to your MainWindow.
QGraphicsView:hover {
border-style: solid;
border-width: 2px;
border-color: green;
}
There's two ways to get this done:
Using the Designer: First select the MainWindow and then in its properties panel click on the styleSheet and copy and paste the style sheet.
Using code: Use setStyleSheet(...) method of QMainWindow and pass the style sheet as a string.

Making a borderless window with for Qt

I'm new to Qt C++. I downloaded the latest windows version, did some tutorials and its great.
I saw some styling options that the Qt framework has and its great, but now I need to build my application that its main windows (form) it designed/skinned with image without the rectangle borders (borderless?).
How can I do it with Qt?
If your looking for some advanced styling in the shape of a widget, maybe this example will help you:
Shaped Clock Example
Or maybe you're simply looking for this kind of flag: Qt::CustomizeWindowHint or simply Qt::FramelessWindowHint.
I created a small example, of how to create VS2013 like frameless window in Qt5:
You can get the complete sources here: https://github.com/Jorgen-VikingGod/Qt-Frameless-Window-DarkStyle
Otherwise here a code overview of how to embed the "main" mainwindow into the "frameless" window. Also you can see how to add titlebar, buttons and do maximize, resize and move of the frameless window.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets>
/*
place your QMainWindow code here
*/
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
/*
this class is to add frameless window supoort and do all the stuff with titlebar and buttons
*/
class BorderlessMainWindow: public QMainWindow
{
Q_OBJECT
public:
explicit BorderlessMainWindow(QWidget *parent = 0);
~BorderlessMainWindow() {}
protected:
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseDoubleClickEvent(QMouseEvent *event);
private slots:
void slot_minimized();
void slot_restored();
void slot_maximized();
void slot_closed();
private:
MainWindow *mMainWindow;
QWidget *mTitlebarWidget;
QLabel *mWindowTitle;
QPushButton *mMinimizeButton;
QPushButton *mRestoreButton;
QPushButton *mMaximizeButton;
QPushButton *mCloseButton;
QPoint mLastMousePosition;
bool mMoving;
bool mMaximized;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
/*
frameless window class: it adds the MainWindow class inside the centralWidget
*/
BorderlessMainWindow::BorderlessMainWindow(QWidget *parent) : QMainWindow(parent, Qt::CustomizeWindowHint ) {
setObjectName("borderlessMainWindow");
setWindowFlags(Qt::FramelessWindowHint| Qt::WindowSystemMenuHint);
// to fix taskbar minimize feature
setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint);
mMainWindow = new MainWindow(this);
setWindowTitle(mMainWindow->windowTitle());
QVBoxLayout *verticalLayout = new QVBoxLayout();
verticalLayout->setSpacing(0);
verticalLayout->setMargin(1);
QHBoxLayout *horizontalLayout = new QHBoxLayout();
horizontalLayout->setSpacing(0);
horizontalLayout->setMargin(0);
mTitlebarWidget = new QWidget(this);
mTitlebarWidget->setObjectName("titlebarWidget");
mTitlebarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
mTitlebarWidget->setLayout(horizontalLayout);
mMinimizeButton = new QPushButton(mTitlebarWidget);
mMinimizeButton->setObjectName("minimizeButton");
connect(mMinimizeButton, SIGNAL(clicked()), this, SLOT(slot_minimized()));
mRestoreButton = new QPushButton(mTitlebarWidget);
mRestoreButton->setObjectName("restoreButton");
mRestoreButton->setVisible(false);
connect(mRestoreButton, SIGNAL(clicked()), this, SLOT(slot_restored()));
mMaximizeButton = new QPushButton(mTitlebarWidget);
mMaximizeButton->setObjectName("maximizeButton");
connect(mMaximizeButton, SIGNAL(clicked()), this, SLOT(slot_maximized()));
mCloseButton = new QPushButton(mTitlebarWidget);
mCloseButton->setObjectName("closeButton");
connect(mCloseButton, SIGNAL(clicked()), this, SLOT(slot_closed()));
mWindowTitle = new QLabel(mTitlebarWidget);
mWindowTitle->setObjectName("windowTitle");
mWindowTitle->setText(windowTitle());
horizontalLayout->addWidget(mWindowTitle);
horizontalLayout->addStretch(1);
horizontalLayout->addWidget(mMinimizeButton);
horizontalLayout->addWidget(mRestoreButton);
horizontalLayout->addWidget(mMaximizeButton);
horizontalLayout->addWidget(mCloseButton);
verticalLayout->addWidget(mTitlebarWidget);
verticalLayout->addWidget(mMainWindow);
QWidget *centralWidget = new QWidget(this);
centralWidget->setObjectName("centralWidget");
centralWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
centralWidget->setLayout(verticalLayout);
setCentralWidget(centralWidget);
}
void BorderlessMainWindow::mousePressEvent(QMouseEvent* event) {
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
if(event->button() == Qt::LeftButton) {
mMoving = true;
mLastMousePosition = event->pos();
}
}
void BorderlessMainWindow::mouseMoveEvent(QMouseEvent* event) {
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
if( event->buttons().testFlag(Qt::LeftButton) && mMoving) {
this->move(this->pos() + (event->pos() - mLastMousePosition));
}
}
void BorderlessMainWindow::mouseReleaseEvent(QMouseEvent* event) {
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
if(event->button() == Qt::LeftButton) {
mMoving = false;
}
}
void BorderlessMainWindow::mouseDoubleClickEvent(QMouseEvent *event) {
Q_UNUSED(event);
if (!mTitlebarWidget->underMouse() && !mWindowTitle->underMouse())
return;
mMaximized = !mMaximized;
if (mMaximized) {
slot_maximized();
} else {
slot_restored();
}
}
void BorderlessMainWindow::slot_minimized() {
setWindowState(Qt::WindowMinimized);
}
void BorderlessMainWindow::slot_restored() {
mRestoreButton->setVisible(false);
mMaximizeButton->setVisible(true);
setWindowState(Qt::WindowNoState);
setStyleSheet("#borderlessMainWindow{border:1px solid palette(highlight);}");
}
void BorderlessMainWindow::slot_maximized() {
mRestoreButton->setVisible(true);
mMaximizeButton->setVisible(false);
setWindowState(Qt::WindowMaximized);
setStyleSheet("#borderlessMainWindow{border:1px solid palette(base);}");
}
void BorderlessMainWindow::slot_closed() {
close();
}
/*
MainWindow class: put all your code here
*/
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent, Qt::FramelessWindowHint), ui(new Ui::MainWindow) {
ui->setupUi(this);
statusBar()->setSizeGripEnabled(true);
}
MainWindow::~MainWindow() {
delete ui;
}
There is a sample application in your Qt directory: examples/widgets/windowsflags.
I ran into this myself and figured it out after some time. Check out https://github.com/ianbannerman/TrueFramelessWindow for sample code for both Windows & macOS.
Qt::FramelessWindowHint sacrifices resizing and min/max/close, so is probably not what mot people are looking for.