Maximize window maintaining taskbar limits - c++

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.

Related

Tabified QDockWidget does not save its layout

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?

Draw inside a QGraphicsScene inside a QWidget

I am trying to have a window (in the form of a QWidget) consisting of both a menu on the right and a graphics area on the left.
Despite the numerous websites explaining the many ways to use QGraphicsScene and QGraphicsView, I just couldn't figure out how to do it.
Here's main.cpp modified to work on its own :
#include <QApplication>
#include <QRectF>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QPushButton>
#include <QVBoxLayout>
#include <QGraphicsRectItem>
#include <QPalette>
int main (int argc, char * argv []) {
QApplication app (argc, argv) ;
// Main window
QWidget frame ;
frame.setFixedSize(750, 550) ;
frame.show() ;
// Right side, works ok
QWidget menu (&frame) ;
menu.setFixedSize(200, 500) ;
menu.move(550, 10) ;
QPalette pal = menu.palette() ;
pal.setColor(QPalette::Background, Qt::red) ;
menu.setPalette(pal) ; // I expected this to color the whole area
// to show the extent of the zone devoted to the menu,
// but it only outlines the button
menu.show() ;
QPushButton button ("Menu", &menu) ;
button.show() ; // I didn't think this was necessary,
// but the button didn't appear without this line
// Left side, nothing displayed
QVBoxLayout layout ;
QGraphicsScene * scene = new QGraphicsScene () ;
QGraphicsView view (scene) ;
layout.addWidget(&view) ;
QWidget canvas (&frame) ;
canvas.setLayout(&layout) ;
// I found this trick to include a QGraphicsScene inside a QWidget,
// I haven't had the opportunity to see whether it really works.
scene->addItem(new QGraphicsRectItem(10, 10, 20, 20)) ;
// The above line has no visible effect
view.show() ;
return app.exec() ;
}
I would expect this to create a window, put a bunch of buttons on the right side (or in the case of the rediced code I provided, just a single button), and draw a rectangle on the left, but it leaves the whole left area blank.
Does the problem come from how I put the QGraphicsView inside the QWidget ? Or is it failing to draw because of something else ? Do I have to update the QGraphicsView to reflect the change ? Is it just out of visible range ?
Finally, is the failure to draw in any way related to the fact that the whole application crashes on line QWidget canvas (&frame) ; when closed ?
I just repaired you program a bit, so that it illustrates, what you can do with Qt and how you should likely use the framework.
I just moved the QPushButton to a QAction residing in a QMenuBar. The QMenuBar can be added to a QMainWindow, which is reasonable for a normal app.
The central widget of the QMainWindow contains the QGraphicsView. Now, you just forgot to connect the QGraphicsScene with the QGraphicsView. That was the reasons for not seeeing anything in your view.
QGraphicsView and QGraphicsScene are just a typical example for a MVC pattern. You can also add another QGraphicsView and connect it to the same QGraphicsScene.
You should also create all you objects with new, as Qt automatically disposes all its children of a QObject, if it is either deleted or leaves scope.
If you are realyl interesting into seriously learning Qt I suggest, that you are creating plenty small example programs like these. It really helped me a lot.
#include <QApplication>
#include <QMenuBar>
#include <QGraphicsView>
#include <QVBoxLayout>
#include <QGraphicsRectItem>
#include <QMainWindow>
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
auto mainWindow = new QMainWindow;
auto menuBar = new QMenuBar;
auto menu = new QMenu("Menu");
auto action = new QAction("Action");
menu->addAction(action);
menuBar->addMenu(menu);
mainWindow->setMenuBar(menuBar);
auto frame = new QFrame;
frame->setLayout(new QVBoxLayout);
mainWindow->setCentralWidget(frame);
auto scene = new QGraphicsScene();
auto view=new QGraphicsView(scene);
view->setScene(scene); // That connects the view with the scene
frame->layout()->addWidget(view);
QObject::connect(action, &QAction::triggered, [&]() {
scene->addItem(new QGraphicsRectItem(10, 10, 20, 20));
});
mainWindow->show();
return app.exec();
}

How to retrieve the icon FROM a QPushButton?

QT 5.8.0, OSX 10.12.6
I need to retrieve the image on a QButton in a window. Here's where I'm at:
I have a number of QPushButtons in a window. These all have been set to have images in QtDesigner by selecting the images from resources assigned to the project. Which works fine.
My (admittedly vague) understanding is that when the window initializes the ui...
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
...the images are applied to the button. When the window opens, they are there, and I didn't do anything else, so that's my guess.
What I need to do now is access the images in the buttons, by which I mean I need to make local copies of them for modification and use later. QAbstractButton has an icon() function, which says it returns the "icon property", so within MainWindow(), I attempted to get the icon from the entire button as follows...
{
QIcon xx;
xx = ui->entire->icon();
}
...which promptly crashes with:
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes:
KERN_INVALID_ADDRESS at 0x00000023000004b8 Exception Note:
EXC_CORPSE_NOTIFY
So I'm doing it wrong, or perhaps it can't be done. TIA for any insight on this one.
There is likely an error somewhere else in your code. I'm using Qt 5.13.0 and the following code works without problems. I suggest, that you might try it in your environment.
#include <QFrame>
#include <QHBoxLayout>
#include <QPushButton>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto frame = new QFrame;
frame->setLayout(new QHBoxLayout);
auto btn = new QPushButton("Test");
btn->setIcon(QIcon("./data/icon.png"));
frame->layout()->addWidget(btn);
QObject::connect(btn, &QPushButton::clicked, [btn]() {
auto icon = btn->icon();
auto pixmap=icon.pixmap(16,16,QIcon::Mode::Normal, QIcon::State::On);
pixmap.save("savedIcon.png");
});
frame->show();
return a.exec();
}

How can I program a custom popup Window in Qt?

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.

X11 window does not put into QWidget for embedding in a Qt application

There is a Qt application. GL-window created into this application by calling XCreateWindow function and I can't edit it.
I need put Xwindow in QWidget inside my Qt applications.
In the documentation:
void QWidget::create ( WId window = 0, bool initializeWindow = true,
bool destroyOldWindow = true ) [protected]
Creates a new widget window if the window is 0, otherwise sets the widget ' s window to window.Initializes the window sets the geometry etc.) if initializeWindow is true. If initializeWindow is false, no initialization is performed. This parameter only makes sense if window is a valid window.
...
For verifying the result of function QWidget::create there is the following code:
class ParentWindow : public QWidget
{
Q_OBJECT
public:
ParentWindow(WId id)
{
create(id);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton* button = new QPushButton("MEGA BUTTON");
button->show();
ParentWindow w(button->winId());
w.show();
return a.exec();
}
When application start a single blank window appears. Although expected window containing a button (or to be a button).
How can I put X11 window into my QWidget?
The problem was resolved:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Display* display = XOpenDisplay(NULL);
XSynchronize(display, True);
XSetErrorHandler(myErrorHandler);
Window x11root = XDefaultRootWindow(display);
int x = 500;
int y = 500;
unsigned int width = 150;
unsigned int height = 150;
unsigned int borderWidth = 0;
long colorBlue = 0xff0000ff;
Window x11w = XCreateSimpleWindow(display, x11root, x, y,
width, height, borderWidth, 1 /*magic number*/, colorBlue);
QWidget w;
w.resize(300, 300);
w.show();
XReparentWindow(display, x11w, w.winId(), 0, 0);
XMapWindow(display, x11w); // must be performed after XReparentWindow,
// otherwise the window is not visible.
return a.exec();
}
To solve the problem through a widget ParentWindow failed - xwindow is embedded in QWidget, but have problems with resizing the window and closing it (it doesn't close).
QX11EmbedContainer could be what you need.
Let Qt create your Window and then use the Qt X11 Drawable with your X11/GL code.
With OpenGL and Qt you must use the Qt OpenGL context, if Qt is rendering using OpenGL. Just be aware that Qt expects the OpenGL state to be put back to what it was when it last used it.
You can get access to the Drawable using QX11Info (also check Compiler does not see QX11Info as this covers a common problem when including X11 with Qt).
The way Qt provides access to both X11 and OpenGL seems to change between major and minor versions so you may need to do a little bit of digging.
I know that the above works with Qt5.1 upto 5.5. Qt5.6 has problems with this approach that I've not yet resolved.
You should not touch window IDs in your first Qt program. Window IDs are a low level concept and a Qt programmer normally needs them only to do something outside of the Qt framework. Managing widgets as children of other widgets is not that kind of task.
I recommend you start with one of the tutorials. Look in particular here to see how you make a widget a child of another widget.