Sorry for my English. I need to implement the order of the QWidget. I have a stack of objects QWidget. And I need to place the window in the order they appear in a stack.
For example:
Stack: window1 -> window2 -> window3
From this example window2 always closes window3, but it, in turn, closes window1.
Is there any such functionality in Qt? I am not limited to the QWidget. Maybe somehow you can specify the order \ windows priority?
The QStackedWidget class provides a stack of widgets where only one widget is visible at a time. I need to get all the widgets to be seen and they cover each other in order of priority.
Maybe there are some flags. Qt::WindowStaysOnTopHint it does not suit me, so the widget \ windows a lot and one should cover everything. And all in order of priority.
You can close the child window explicitly in the close event of a window, something like:
class WindowWithChildWindow : public QWidget
{
Q_OBJECT
public:
WindowWithChildWindow(QWidget *child)
: m_child(child)
{ }
....
protected:
void closeEvent(QCloseEvent *e) override
{
if (!m_child || m_child->close())
e->accept(); // close this window
else // child ignored the close request in its close event
e->ignore(); // do not close this window
}
....
};
Related
I have a mainwindow which in there is a Qtableview by clicking on insert record I go to other modal windows to add record when I add record and close the second windows I come back to main windows but the qtableview doesn't show the new record that is added. The record is in database.
I already make this somehow work with :
void MainWindow::showEvent( QShowEvent* event ) {
QWidget::showEvent( event );
updTbl();
}
But it only works when windows get minimized.
QMainWindow has also two event handler from QWidget
void QWidget::focusInEvent(QFocusEvent *event)
void QWidget::focusOutEvent(QFocusEvent *event)
If you use QtCreator, go to your mainwindow.h and search the line "class MainWindow : public QMainWindow". Right click on QMainWindow -> Refactoring -> Insert virtual function. That's an easy way to find which virtual functions exist and that can be overloaded, you can select focusInEvent and focusOutEvent from there.
Handling activate/deactivate events as follows will give you the desired behaviour
// overloading event(QEvent*) method of QMainWindow
bool MainWindow::event(QEvent* e)
{
switch (e->type())
{
case QEvent::WindowActivate:
// gained focus
//Update Table
break;
case QEvent::WindowDeactivate:
// lost focus
break;
};
return QMainWindow::event(e);
}
Ref: https://gist.github.com/01walid/2276009
I've seen this question : Qt/C++ - Closing two widgets when one is closed
However I do not have this MainWindow <-> Widget relationship.
class Ui_DialogResults
{
public:
QDialog *_Dialog;
void setupUi(QDialog *Dialog)
{
_Dialog = Dialog;
}
};
class Ui_DialogSearch
{
public:
QDialog *_Dialog;
void setupUi(QDialog *Dialog)
{
_Dialog = Dialog;
}
};
namespace Ui {
class Ui_Search : public Ui_DialogSearch {};
class Ui_Results : public Ui_DialogResults {};
}
class Search : public QDialog{
public:
Search(){
ui.setup(this);
}
void closeEvent(QCloseEvent *event)
{
//saves scan settings here
pResults->_Dialog->close();
}
Ui::Ui_Search ui;
Ui::Ui_Results *pResults;
}
class Results : public QDialog{
public:
Results(){
ui.setup(this);
}
void closeEvent(QCloseEvent *event)
{
//saves scan settings here
pSearch->_Dialog->close();
}
Ui::Ui_Search *pSearch;
Ui::Ui_Results ui;
}
When a Search dialog is open, a result dialog is also open and vice versa.
The Thread opening both dialogs also fills the pointer in the Search instance towards Result and vice versa.
Each class has overriden closeEvent()so that they close each others as such.
I would have expected cross recursive consequences and crash but it apparently works perfectly.
Qt doc states
The QCloseEvent class contains parameters that describe a close event.
Close events are sent to widgets that the user wants to close, usually by choosing "Close" from the window menu, or by clicking the X title bar button. They are also sent when you call QWidget::close() to close a widget programmatically.
Is this UB?
Since you already have a mutual reference between the search and results dialog, you can easily avoid any potential incidents by setting pointers to null and doing some basic checks.
The dialog that initiates the closing sets its own pointer in the other dialog to null, copies the pointer to the other to a temporary value, sets the other pointer to null and closes the other dialog through the temp pointer. If the pointer to the other dialog is already null, that would mean the other dialog has initiated the closing, so do nothing except call the base class implementation in order to close the dialog.
Is it undefined Behavior? No. Undocumented? Possibly. (Did not find any explicit statement that this is supposed to work). Unintended? Probably not. Qt is pretty mature, although not always documented to the last detail. I bet they only allow only one close event per widget.
EDIT and Some Self Critisicm
I tried both given solutions, which both solved my problem, and thus I thank you both! I marked the transparent solution as accepted because I thought it is was the easiest implementation when I only had one child widget, but I wish to share some insight for other beginners:
I first used QLabel, which apperently has enabled Qt::WA_TransparentForMouseEvents by default and thus obviously worked, but I also wanted the text to be selectable, by using QPlainTextEdit instead. Laughably, this is not possible in any way, because if you try to select the text (by clicking) you will close the window! I ended up keeping the transparancy, and neglecting the select-text-feature.
I'm guessing my following question has been answered somewhere before, but after an hour of searching I now post the question myself. I'm grateful if someone can point me to an already answered question that solves my problem.
Anyhow, I'm creating a popup window, using C++ and Qt. I've created the following PopupDialog class which works well and fine for all its purposes. However, I've removed its frame (including the bar containing the close button and window title) to make it look minimalistic, and now I want it to close if the user presses/releases the mouse button anywhere inside the popup window (dialog).
The below code works, however in such a way that I have to click and release the mouse exactly at the QDialog-window itself. It will not close when i click if the mouse hovers over the child widget(s) inside the QDialog, e.g. a QPlainTextEdit, which is displaying text.
Hence, I'm in need of a solution for QDialog to recognize QMouseEvents inside its child widgets. Please, don't hesitate to ask if something is unclear. I have not included my mainwindow.h/.cpp files, or popupdialog.ui file since I believe it would be a little too much to post here, but the .ui extremely simple: Just the QDialog window holding a QBoxLayout, containing a single widget, a QPlainTextEdit. I may posts these on request if it helps.
// popupdialog.h
#ifndef POPUPDIALOG_H
#define POPUPDIALOG_H
#include <QDialog>
#include <QString>
namespace Ui {class PopupDialog;}
class PopupDialog : public QDialog
{
Q_OBJECT
public:
explicit PopupDialog(QWidget *parent = 0, QString msgTxt="");
~PopupDialog();
private:
Ui::PopupDialog *ui;
QString messageText;
void mouseReleaseEvent(QMouseEvent*);
};
#endif //POPUPDIALOG_H
...
// popupdialog.cpp
#include "popupdialog.h"
#include "ui_popupdialog.h"
PopupDialog::PopupDialog(QWidget *parent, QString msgTxt) :
QDialog(parent),
ui(new Ui::PopupDialog),
messageText(msgTxt)
{
ui->setupUi(this);
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
setModal(true);
ui->message_text_display->setText(messageText);
// The message_text_display is an instance of the class,
// "PlainTextEdit". Using "QLabel" partly solves my
// problem, but does not allow text selection.
}
PopupDialog::~PopupDialog()
{
delete ui;
}
void PopupDialog::mouseReleaseEvent(QMouseEvent *e)
{
this->close();
}
As you already noticed mouse events are handled from child widgets and propagated to parents if not accepted. You can read more about it here
To close your popup window when the click is done inside a child widget you can do two things. You could try looking into installEventFilter and set it up on each child widget to call close().
Another option would require you to have a kind of centralWidget (like the MainWindow usually has) - just to group all your child widgets. This way you could call setAttribute() on it to set Qt::WA_TransparentForMouseEvents property to simply skip handling mouse events on the widget and all of its children.
groupWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
According to Qt docs:
When enabled, this attribute disables the delivery of mouse events to
the widget and its children. Mouse events are delivered to other
widgets as if the widget and its children were not present in the
widget hierarchy; mouse clicks and other events effectively "pass
through" them. This attribute is disabled by default.
Which basically means the event would be passed up the chain to the first widget which can handle the event. In your case it would be the PopupDialog and the already overriden mouseReleaseEvent slot.
in header file
class PopupDialog : public QDialog
{
Q_OBJECT
public:
explicit PopupDialog(QWidget *parent = 0, QString msgTxt="");
~PopupDialog();
//////////////////////////////////
protected:
bool eventFilter(QObject *obj, QEvent *event);
//////////////////////////////////////
private:
Ui::PopupDialog *ui;
QString messageText;
void mouseReleaseEvent(QMouseEvent*);
};
in cpp
PopupDialog::PopupDialog(QWidget *parent, QString msgTxt) :
QDialog(parent),
ui(new Ui::PopupDialog),
messageText(msgTxt)
{
ui->setupUi(this);
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
setModal(true);
ui->message_text_display->setText(messageText);
// The message_text_display is an instance of the class,
// "PlainTextEdit". Using "QLabel" partly solves my
// problem, but does not allow text selection.
///////////////////////////////////////
foreach (QObject *child, children())
{
child->installEventFilter(this);
}
///////////////////////////////////////
}
///////////////////////////////////////
bool PopupDialog::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonRelease)
{
this->close();
}
}
I have a layered kind of architecture, in which one Widget is inside another.
Top most object is QMainWindow, and there can be any numbers of internal widgets (one inside another).
example:- mainwindow is parent of widget1, widget1 is parent of widget2..so on..
Now I need to handle the close event of the latest child in the top most window.
I want to know the best way of achieving it in QT 5.7.
You may want to subclass the QMainWindow and override the childEvent function:
http://doc.qt.io/qt-5/qobject.html#childEvent
Would allow you to do something like:
class TarunsMainWindow : QMainWindow {
protected:
void childEvent(QChildEvent event) override {
if (event->type() == QEvent::ChildRemoved) {
// do something special
}
QMainWindow::childEvent(event);
}
}
I'm using the QMdiArea in Qt 4.4.
If a new project is created, I add a number of sub windows to a QMdiArea. I'd like to disallow the user to close a sub window during runtime. The sub windows should only be closed if the whole application is closed or if a new project is created.
How can I do this?
You need to define your own subWindow. create a subclass of QMdiSubWindow and override the closeEvent(QCloseEvent *closeEvent). you can control it by argument. for example:
void ChildWindow::closeEvent(QCloseEvent *closeEvent)
{
if(/*condition C*/)
closeEvent->accept();
else
closeEvent->ignore(); // you can do something else, like
// writing a string in status bar ...
}
then subclass the QMdiArea and override QMdiArea::closeAllSubWindows () like this:
class MainWindowArea : public QMdiArea
{
Q_OBJECT
public:
explicit MainWindowArea(QWidget *parent = 0);
signals:
void closeAllSubWindows();
public slots:
};
// Implementation:
MainWindowArea::closeAllSubWindows()
{
// set close condition (new project is creating, C = true)
foreach(QMdiSubWindow* sub,this->subWindowList())
{
(qobject_cast<ChildWindow*>(sub))->close();
}
}
you may also need to override close slot of your mdi area.
You'd do this the same as for a top-level window: process and ignore the QCloseEvent it sent. QMdiArea::closeActiveSubWindow/QMdiArea::closeAllSubWindows just call QWidget::close, which sends a closeEvent and confirms that it was accepted before proceeding.
You can process this event by subclassing QMdiSubWindow and reimplementing QWidget::closeEvent, or by using an event filter to intercept it..