Problem
I'm creating the main window with multiple dock widgets. My current goal is to save the whole layout on exit. Everything works fine until I try to tabify some of my dock widgets using the tabifyDockWidget() method. And now the tabified widgets don't save their positions for some reason.
Example
Here is the minimal reproducible example.
You can check the described behavior by (un)commenting the tabifyDockWidget() line and resizing the dock widgets.
Of course, don't forget to remove the saved settings file to reset the layout to its initial state.
#include "mainwindow.h"
#include <QDockWidget>
#include <QLabel>
#include <QSettings>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
resize(800, 320);
auto centralWidget = new QLabel("Central Widget", this);
centralWidget->setAlignment(Qt::AlignCenter);
centralWidget->setStyleSheet("border: 2px solid black");
setCentralWidget(centralWidget);
auto dockLeft1 = new QDockWidget(this);
auto dockLeft2 = new QDockWidget(this);
auto dockRight = new QDockWidget(this);
dockLeft1->setObjectName("dockLeft1");
dockLeft2->setObjectName("dockLeft2");
dockRight->setObjectName("dockRight");
dockLeft1->setWindowTitle(tr("Left Dock 1"));
dockLeft2->setWindowTitle(tr("Left Dock 2"));
dockRight->setWindowTitle(tr("Right Dock"));
addDockWidget(Qt::LeftDockWidgetArea, dockLeft1);
addDockWidget(Qt::LeftDockWidgetArea, dockLeft2);
addDockWidget(Qt::RightDockWidgetArea, dockRight);
tabifyDockWidget(dockLeft1, dockLeft2);
QSettings settings("foo", "bar");
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("state").toByteArray());
}
void MainWindow::closeEvent(QCloseEvent *event)
{
QSettings settings("foo", "bar");
settings.setValue("geometry", saveGeometry());
settings.setValue("state", saveState());
QMainWindow::closeEvent(event);
}
Behavior without tabifyDockWidget()
Resize left and right dock widget.
Close and reopen the application.
The layout settings are properly restored. 👍
Behavior with tabifyDockWidget()
Resize left and right dock widget.
Close and reopen the application.
The restored layout settings are wrong for the left (tabified) dock. 👎
What's the reason?
Is there any proper workaround?
Related
I am trying to draw various shapes like rectangle, ellipse, text etc uisng QGraphicsView and QGraphicsScene. For that I am trying to create an interface where there will be a vertical layout and besides that there will be few buttons. On clicking those buttons, I can show various QGraphicsItem's on screen. I want to create this interface programatically but not using ui.
I tried and ended up this way.
I wanted buttons on the right side and verticalLayout on the left side and both should filled up the whole screen.
Here is my current implementation :
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGraphicsScene* scene = new QGraphicsScene(this);
QGraphicsView* view = new QGraphicsView(this);
view->setScene(scene);
QWidget* mainWidget = new QWidget(this);
QHBoxLayout *mainLayout = new QHBoxLayout();
QVBoxLayout *buttonLayout = new QVBoxLayout();
QVBoxLayout *vlayout2 = new QVBoxLayout();
vlayout2->addWidget(view);
QPushButton *btn1 = new QPushButton("Rectangle");
btn1->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
QPushButton *btn2 = new QPushButton("Ellipse");
btn2->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
QPushButton *btn3 = new QPushButton("Text");
btn3->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
buttonLayout->addWidget(btn1);
buttonLayout->addWidget(btn2);
buttonLayout->addWidget(btn3);
buttonLayout->addStretch();
mainLayout->addLayout(buttonLayout);
mainLayout->addLayout(vlayout2);
mainWidget->setLayout(mainLayout);
}
Can anyone guide me ?
Actually, it should work with the hints given in my comments.
I made an MCVE to convince myself:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QWidget qMain;
qMain.setWindowTitle("Test Box Layout");
qMain.resize(640, 320);
QHBoxLayout qHBox;
QVBoxLayout qVBoxBtns;
QPushButton qBtnRect("Rectangle");
qVBoxBtns.addWidget(&qBtnRect);
QPushButton qBtnCirc("Circle");
qVBoxBtns.addWidget(&qBtnCirc);
QPushButton qBtnText("Text");
qVBoxBtns.addWidget(&qBtnText);
qVBoxBtns.addStretch();
qHBox.addLayout(&qVBoxBtns);
QVBoxLayout qVBoxView;
QGraphicsView qView;
qVBoxView.addWidget(&qView, 1);
qHBox.addLayout(&qVBoxView, 1);
qMain.setLayout(&qHBox);
qMain.show();
// runtime loop
return app.exec();
}
Output:
Thus, there must be something else in OP's code…
Unfortunately, OP didn't expose an MCVE.
Thus, it's not clear how OP's Widget is instanced. Is it the widget which becomes the main window? Is there another widget where the Widget's instance becomes child of?
It's just guessing but the latter would explain what OP described.
To confirm my guess, I modified the above code a bit:
// setup GUI
QWidget qMain0; // main window widget
QWidget qMain(&qMain0); // child widget of main window widget
⋮
qMain.setLayout(&qHBox);
qMain0.show();
// runtime loop
return app.exec();
Please, note that qMain is now a child of qMain0 but there is no layout which adjusts the size of qMain when qMain0 is resized.
Hence, the size of view stays the initial size while the window is resized.
While using the QtStackedWidget for switching windows in a big project, it doesn't seem to take in consideration the " setWindowTitle " part added in every window, and even for the size it takes only the first size precise in the QtStackedWidget declaration. This is weird.Any clarification I'm here to read.
So My question is:
-does the QtStackedWidget allow us to change the window's title each time we switch the window?
-and what about the size is it fixed or dynamic?
From the Qt docs setWindowTitle
This property only makes sense for top-level widgets, such as windows and dialogs. If no caption has been set, the title is based of the windowFilePath. If neither of these is set, then the title is an empty string.
You can connect the QStackedWidget signals to the QMainWindow
Here is a working example:
#include <QPushButton>
#include <QHBoxLayout>
#include <QLabel>
#include <QStackedWidget>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QWidget * poCentral = new QWidget(this);
QVBoxLayout * poVLayout = new QVBoxLayout;
QHBoxLayout * poHBtnLayout = new QHBoxLayout;
QStackedWidget * poMyStackedWidget = new QStackedWidget(this);
QPushButton * poNextPage = new QPushButton("Next page", this);
this->setWindowTitle("Page: 0");
// switch stacked pages
connect(poNextPage, &QPushButton::clicked,
[=]()
{
int iPageIndex = poMyStackedWidget->currentIndex() + 1;
if (iPageIndex >= poMyStackedWidget->count())
{
poMyStackedWidget->setCurrentIndex(0);
}
else
{
poMyStackedWidget->setCurrentIndex(iPageIndex);
}
// set window title
poMyStackedWidget->setWindowTitle(QString("Page: %1").arg(poMyStackedWidget->currentIndex()));
});
// Connect the signlas so the main window will display the title.
connect(poMyStackedWidget, &QStackedWidget::windowTitleChanged,
this, &MainWindow::setWindowTitle);
// UI layout
poHBtnLayout->addWidget(poNextPage);
poVLayout->addLayout(poHBtnLayout);
poVLayout->addWidget(poMyStackedWidget);
poCentral->setLayout(poVLayout);
// Add dumy pages
poMyStackedWidget->insertWidget(0,new QLabel("First page", this));
poMyStackedWidget->insertWidget(1,new QLabel("Second page", this));
poMyStackedWidget->insertWidget(2,new QLabel("third page", this));
this->setCentralWidget(poCentral);
}
My Qt application consists of several screens added on a QStackedLayout(). Now after some useraction I would like a little popup window that confirms the action and disappears after a few seconds. What I would like is a gray rectangle with black border and some text in it. No buttons, no titlebar.
I tried to do it with QMessage Box (see code below) but in general it doesnt seem to be possible to adjust border styles for QMessageBox(). Also the size can't be adjusted.
QMessageBox* tempbox = new QMessageBox;
tempbox->setWindowFlags(Qt::FramelessWindowHint); //removes titlebar
tempbox->setStandardButtons(0); //removes button
tempbox->setText("Some text");
tempbox->setFixedSize(800,300); //has no effect
tempbox->show();
QTimer::singleShot(2000, tempbox, SLOT(close())); //closes box after 2 seconds
So, how can I program a custom popup Window in Qt?
First of all, I'd like to recommend the Windows Flags Example of the Qt docs. It provides a nice sample to play around with this topic. In this sample, a QWidget is derived to show the effect of the distinct flags. This brought me to the idea that probably any QWidget can be used for this if the appropriate Qt::WindowFlags are set. I choosed QLabel because
it can display text
it inherits from QFrame and, thus, can have a frame.
Source code testQPopup.cc:
// standard C++ header:
#include <iostream>
#include <string>
// Qt header:
#include <QApplication>
#include <QLabel>
#include <QMainWindow>
#include <QTimer>
using namespace std;
int main(int argc, char **argv)
{
cout << QT_VERSION_STR << endl;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
qWin.setFixedSize(640, 400);
qWin.show();
// setup popup
QLabel qPopup(QString::fromLatin1("Some text"),
&qWin,
Qt::SplashScreen | Qt::WindowStaysOnTopHint);
QPalette qPalette = qPopup.palette();
qPalette.setBrush(QPalette::Background, QColor(0xff, 0xe0, 0xc0));
qPopup.setPalette(qPalette);
qPopup.setFrameStyle(QLabel::Raised | QLabel::Panel);
qPopup.setAlignment(Qt::AlignCenter);
qPopup.setFixedSize(320, 200);
qPopup.show();
// setup timer
QTimer::singleShot(1000,
[&qPopup]() {
qPopup.setText(QString::fromLatin1("Closing in 3 s"));
});
QTimer::singleShot(2000,
[&qPopup]() {
qPopup.setText(QString::fromLatin1("Closing in 2 s"));
});
QTimer::singleShot(3000,
[&qPopup]() {
qPopup.setText(QString::fromLatin1("Closing in 1 s"));
});
QTimer::singleShot(4000, &qPopup, &QLabel::hide);
// run application
return qApp.exec();
}
I compiled with VS2013 and Qt 5.6 on Windows 10 (64 bit). The image below shows a snaphot:
To make the popup better visible (and because I liked it), I changed the background color of the QLabel for popup. And, I couldn't resist to add a little countdown.
I want to create a Qt application without the windows title bar (I want to create a customized one).
I've created three buttons for minimizing, maximizing and closing the window. Everything works except for considering that when I maximize the window, application doesn't take into account the taskbar, and the maximized window takes the entire screen, going under the taskbar. A normal maximize command from windows instead maximizes the application window avoiding to go under the taskbar.
If I don't use the Qt::CustomizeWindowHint the window title bar appears, and maximizing behaviour is correct; but if I use this flag, the title bar disappears and the application goes under the window: here you can find two screenshots explaning the behaviour:
With Windows title:
Without Windows title:
As you can see in latter case che "Close" button goes inside the taskbar because the application takes the entire screen.
How can I avoid this behaviour without using windows title bar? I want to recreate the same behaviour as with the window title bar.
SampleWindow.h
#ifndef SAMPLEWINDOW_H_
#define SAMPLEWINDOW_H_
#include <QMainWindow>
#include <QPushButton>
#include <QHBoxLayout>
class SampleWindow : public QMainWindow {
Q_OBJECT
public:
SampleWindow();
virtual ~SampleWindow() = default;
};
#endif // !SAMPLEWINDOW_H_
SampleWindow.cpp
#include "SampleWindow.h"
#include <QCoreApplication>
SampleWindow::SampleWindow() :
QMainWindow() {
// With uncommenting this line the title bar disappears
// but application goes under the taskbar when maximized
//
//setWindowFlags(Qt::CustomizeWindowHint);
auto centralWidget = new QWidget(this);
auto layout = new QHBoxLayout(this);
auto minimizeButton = new QPushButton("Minimize", this);
auto maximizeButton = new QPushButton("Maximize", this);
auto closeButton = new QPushButton("Close", this);
layout->addWidget(minimizeButton);
layout->addWidget(maximizeButton);
layout->addWidget(closeButton);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
connect(closeButton, &QPushButton::clicked, [=]() {QCoreApplication::quit();});
connect(minimizeButton, &QPushButton::clicked, this, [=]() {setWindowState(Qt::WindowMinimized);});
connect(maximizeButton, &QPushButton::clicked, this, [=]() {setWindowState(Qt::WindowMaximized);});
}
Main.cpp
#include <QApplication>
#include "SampleWindow.h"
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
SampleWindow mainWindow;
mainWindow.show();
return app.exec();
}
This behavior depends on system. I tested your code on Windows 7 and Linux Mint KDE and behavior was different. In Windows 7 taskbar has hidden and window has filled area of taskbar. In KDE I have noticed that window maximizes correctly (avoids widget panels and not hides them).
However when I try to run code in Windows 10 with compatibility mode, I was able to repeat behavior of Win7 only in compatibility with Windows Vista and older versions.
For Windows 10 I found another solution: you can maximize your window in fullscreen if that suits you:
mainWindow.showFullScreen();
or
setWindowState(Qt::WindowFullScreen);
UPD:
In addition to your solution I found another one:
setGeometry(QApplication::desktop()->availableGeometry().x(),
QApplication::desktop()->availableGeometry().y(),
QApplication::desktop()->availableGeometry().width(),
QApplication::desktop()->availableGeometry().height());
I think that I've found a solution by using this slot when maximize button is clicked:
void SampleWindow::maximize() {
//setWindowState(Qt::WindowFullScreen);
QDesktopWidget *desktop = QApplication::desktop();
QRect desktopGeometry = desktop->availableGeometry();
int desktopHeight = desktopGeometry.height();
int desktopWidth = desktopGeometry.width();
int padx = (frameGeometry().width() - geometry().width()) / 2;
setFixedSize(desktopWidth, desktopHeight);
move(-padx,0);
}
I need to test it more but at the moment the area seems correct.
I am making a application by Qt, that has a central widget, right dock widget and left dock widget. Their sizes are fixed.
They are displayed, but there a blank space between the central widget and the right widget when the left dock widget is floating.
https://twitter.com/#!/hizz_GI/status/155768124321435648/photo/1
Will you please tell me the way to remove the blank space?
I appreciate you taking the time to respond to my question.
code:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
textEdit = new QTextEdit;
textEdit->setFixedSize(100, 150);
setCentralWidget(textEdit);
creatDocks();
layout()->setSizeConstraint(QLayout::SetFixedSize);
}
void MainWindow::creatDocks()
{
leftTextEdit = new QTextEdit;
rightTextEdit = new QTextEdit;
leftDock = new QDockWidget(tr("Left Dock Widget"));
rightDock = new QDockWidget(tr("Right Dock Widget"));
leftDock->setFixedSize(100, 150);
leftDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
leftDock->setWidget(leftTextEdit);
rightDock->setFixedSize(150, 150);
rightDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
rightDock->setWidget(rightTextEdit);
addDockWidget(Qt::LeftDockWidgetArea, leftDock);
addDockWidget(Qt::RightDockWidgetArea, rightDock);
}
I found a solving.
It is a way that calls menuWidget()->adjustSize() and adjustSize() when paintEvent of MainWindow without textEdit->setFixedSize() and layout()->setSizeConstraint().
But it is expensive. What time is the proper call?
And is this appropriate?
Thanks.
Probably, since you set all the 3 widget to have a fixed size, when your left widget is floating, the central widget correctly go to the left, but since it and the right widget have a fixed size, they where not resized to fill the space in the middle.
Have you the same problem also when the central or right widget are floating instead of the left widget ?