Закрыть немодальное окно из главного
Поскольку писать на Qt начал недавно, то столкнулся со следующей проблемой: как правильно закрыть немодальное окно из главного окна.
Ниже пример: на главной форме есть кнопка «Создать окно». При нажатии на нее открывается дочернее немодальное окно. Всегда должен быть только 1 экземпляр этого окна. Если пользователь впервые нажал кнопку «Создать окно», то нужно создать его. Если он нажал второй раз, то сделать активным уже открытое окно. Если нажал крестик «Закрыть», то закрыть его.
Проблема в том, как контролировать, когда это окно открыто, а когда закрыто, чтобы не плодить кучу экземпляров этого окна, а держать только 1 экземпляр.
Последние дни перелопатил кучу примеров найденных в гугле и работает только 1 и то он очень громоздкий и похоже через заднее место.
Принцип работы:
— в классе главного окна (MainDialog) имеем указатель (pAnotherDialog) на наше дочернее окно (класс AnotherDialog)
— если пользователь нажал кнопку «Создать окно», то проверяем не создано ли оно уже (нашел единственный работающий способ проверить это: pAnotherDialog==NULL), и если оно уже создано (pAnotherDialog!=NULL) то делаем его активным), если не создано (pAnotherDialog==NULL), то создаем его.
Нашел единственный работающий способ: переопределить closeEvent(QCloseEvent *event) в AnotherDialog и отправлять в главное окно сигнал о том, пользователь пытается закрыть окно. В главном окне ловим этот сигнал в слоте и «насильно закрываем его» через accept() и обнуляем pAnotherDialog (чтобы потом знать, открыто окно или нет).
В общем способ громоздкий и чувствую, что решение должно быть намного проще.
Главный вопрос: как узнать в главном окне, открыто ли дочернее окно или нет? Единственное решение, которое я нашел, — это все время обнулять pAnotherDialog после закрытия окна (pAnotherDialog=NULL).
Повторю, что перелопатил кучу способов найденных в гугле и работает только этот.
Извиняюсь, что кидаю сюда кучу кода, комментить по строкам не буду, вроде все понятно.
Итак, структура проекта:
Headers:
anotherdialog.h // заголовочный файл дочернего окна
maindialog.h // заголовочный файл главного окна
Sources:
anotherdialog.cpp // код дочернего окна
main.cpp // код входа
maindialog.cpp // код главного окна
Forms:
anotherdialog.ui // форма дочернего окна
maindialog.ui // форма главного окна
Не буду постить main.cpp, т.к. там все по умолчанию. В maindialog.ui только 1 кнопка «Открыть окно». В maindialog.ui ничего нет.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#ifndef MAINDIALOG_H #define MAINDIALOG_H #include #include "AnotherDialog.h" QT_BEGIN_NAMESPACE namespace Ui { class MainDialog; } QT_END_NAMESPACE class MainDialog : public QDialog { Q_OBJECT public: MainDialog(QWidget *parent = nullptr); ~MainDialog(); AnotherDialog* pAnotherDialog; void showAnotherDialog(bool boolShow); private slots: void slotShowAnotherDialog(); void slotHideAnotherDialog(); private: Ui::MainDialog *ui; }; #endif // MAINDIALOG_H
maindialog.cpp :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#include "maindialog.h" #include "ui_maindialog.h" #include #include MainDialog::MainDialog(QWidget *parent) : QDialog(parent) , ui(new Ui::MainDialog) { ui->setupUi(this); pAnotherDialog = NULL; connect(ui->pushButton, &QPushButton::clicked, this, &this->slotShowAnotherDialog); } MainDialog::~MainDialog() { delete ui; } void MainDialog::showAnotherDialog(bool boolShow) { if (boolShow) { if (pAnotherDialog==NULL) { pAnotherDialog = new AnotherDialog(this); pAnotherDialog->show(); } else pAnotherDialog->activateWindow(); connect(this->pAnotherDialog, AnotherDialog::signalHideAnotherDialog, this, this->slotHideAnotherDialog); } else { if (pAnotherDialog != NULL) { pAnotherDialog->accept(); pAnotherDialog = NULL; } } } void MainDialog::slotShowAnotherDialog() { showAnotherDialog(true); } void MainDialog::slotHideAnotherDialog() { showAnotherDialog(false); }
anotherdialog.h :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
#ifndef ANOTHERDIALOG_H #define ANOTHERDIALOG_H #include namespace Ui { class AnotherDialog; } class AnotherDialog : public QDialog { Q_OBJECT public: explicit AnotherDialog(QWidget *parent = nullptr); ~AnotherDialog(); protected: void closeEvent(QCloseEvent *event) override; signals: void signalHideAnotherDialog(); private: Ui::AnotherDialog *ui; }; #endif // ANOTHERDIALOG_H
anotherdialog.cpp :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include "anotherdialog.h" #include "ui_anotherdialog.h" #include AnotherDialog::AnotherDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AnotherDialog) { ui->setupUi(this); } AnotherDialog::~AnotherDialog() { delete ui; } void AnotherDialog::closeEvent(QCloseEvent *event) { emit signalHideAnotherDialog(); event->ignore(); }
Главный вопрос: как контролировать открыто или закрыто дочернее окно, чтобы не плодить кучу экземпляров, а держать только 1 экземпляр?
Насколько это грамотный способ? Почему все так сложно и громоздко? Как сделать проще?
Какие есть еще способы?
Как закрыть окно qt
Можно ли в qt как-то инициировать немедленное закрытие окна?
Наткнулся на такую вещь: вызов слота close() как метода класса не приводит к немедленному закытию окна (с вызовом closeEvent и далее деструктора окна). Окно закрывается, но где-то после (вероятно, закрытие ставится в какую-то внутреннюю qt-шную очередь). В результате, после вызова wnd->close() окно остается неуничтоженным, деструктор невызванным, а мне нужно дальше уничтожать различные объекты, которые можно уничтожать только после закрытия целой группы окон и вызова их деструкторов.
Re: close(), как сделать немедленное закрытие окна
От: | _niko_ |
Дата: | 28.01.14 14:10 |
Оценка: |
Здравствуйте, Аноним, Вы писали:
А>Можно ли в qt как-то инициировать немедленное закрытие окна?
А>Наткнулся на такую вещь: вызов слота close() как метода класса не приводит к немедленному закытию окна (с вызовом closeEvent и далее деструктора окна). Окно закрывается, но где-то после (вероятно, закрытие ставится в какую-то внутреннюю qt-шную очередь). В результате, после вызова wnd->close() окно остается неуничтоженным, деструктор невызванным, а мне нужно дальше уничтожать различные объекты, которые можно уничтожать только после закрытия целой группы окон и вызова их деструкторов.
Метод QWidget::close по умолчанию не предполагает разрушение объекта, ибо после закрытия можно захотеть ещё пообщаться с ним.
Для разрушения при закрытии используй:
QWidget::setAttribute(Qt::WA_DeleteOnClose, true);
Отмечу, установка подобного флага также доступна и в конструкторе, но данное решение считается устаревшим:
QWidget::QWidget(parent, Qt::WDestructiveClose); // Obsolete
Re[2]: close(), как сделать немедленное закрытие окна
От: | _niko_ | |
Дата: | 28.01.14 17:08 | |
Оценка: | 1 (1) |
С учетом вышесказанного (я про атрибут Qt::WA_DeleteOnClose) стоит уточнить что при выходе из метода QWidget::close объект удален не будет, он всего лишь будет отмечен как закрытый!
В очереди сообщений потока будет лежать сообщение адресованное данному виджету при дальнейшей обработки которого виджет как раз таки и удалиться.
Если необходимо дождаться его удаления тут же — это можно решить через локальную прокрутку очереди сообщений (QEventLoop), но так лучше не делать, а придумать другое решение изначально-сложившейся проблемы.
Как правильно закрыть окно?
У меня есть два окна, первое окно это окно политика конфидициальности. Второе окно открывается при соглашение на первое окно. Мне нужно что бы первое окно закрывалось сразу после открытия второго. Я пробовал через QApplication::quake и через имяпервогокласса::close().
Но возникает вторая проблема, второе окно не успевает открыться.
Я и в начало кода передвигал close и в конец и в середину, Ничего не помогло.
Каким образом БЕЗОПАСНО ЗАКРЫТЬ окно и успев открыть второе окошко.
- Вопрос задан более трёх лет назад
- 218 просмотров
Комментировать
Решения вопроса 2
Яков Е @Zifix Куратор тега Qt
Почитайте любую книгу по Qt. Сэкономите кучу времени и найдёте ответы ещё на тысячу подобных вопросов.
Ответ написан более трёх лет назад
Комментировать
Нравится 3 Комментировать
Vitaly @vt4a2h Куратор тега C++
Senior software engineer (C++/Qt/boost)
#include #include int main(int argc, char *argv[]) < QApplication a(argc, argv); QMainWindow mainWindow; auto res = QMessageBox::question(&mainWindow, QMainWindow::tr("Just in case"), QMainWindow::tr("Are you sure?")); if (res == QMessageBox::Yes) < mainWindow.show(); return a.exec(); >else < return -1; >>
Смысл в том, что у вас первое окно — это модальный диалог (наследник QDialog, допустим). У него есть метод exec обычно, который возвращает результат (например согласился пользователь или нет). На основании результата и решайте, что делать дальше: показать окно или выйти из программы.
Ответ написан более трёх лет назад
Комментировать
Нравится 2 Комментировать
Ответы на вопрос 0
Ваш ответ на вопрос
Войдите, чтобы написать ответ
- C++
- +1 ещё
В чем ошибка кода?
- 1 подписчик
- 7 часов назад
- 96 просмотров
Как правильно закрыть окно Qt?
Есть многооконное приложение. Виджеты иногда меняют родителей и переходят из одного окна в другое. Возникает необходимость закрывать окна с остатками виджетов. Например, было два окна, в каждом по два QLabel . Из одного окна в другое перешел QLabel . Окно с оставшимся в нем одним QLabel больше не нужно и его можно полностью удалить со всеми виджетами в нем. Как теперь правильно удалить это окно, чтобы не было утечек памяти и других неприятных вещей? Или память освобождается автоматически?
Отслеживать
28.5k 12 12 золотых знаков 58 58 серебряных знаков 118 118 бронзовых знаков
задан 30 авг 2016 в 15:02
835 9 9 серебряных знаков 23 23 бронзовых знака
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Для каждого окна установите атрибут:
setAttribute(Qt::WA_DeleteOnClose);
Этот атрибут делает следующее:
Makes Qt delete this widget when the widget has accepted the close event (see QWidget::closeEvent()).
Другими словами, когда окно получает QCloseEvent , оно самоуничтожается
Отслеживать
ответ дан 30 авг 2016 в 15:46
yrHeTateJlb yrHeTateJlb
8,022 15 15 серебряных знаков 35 35 бронзовых знаков
Для окна — вы имеете в виду для самого главного виджета в окне, у которого родитель — nullptr ?
30 авг 2016 в 17:06
@LNK, да, за остальные виджеты отвечают их родители
30 авг 2016 в 17:10
И память освободится, всё удалится, если я вызову close(); ? Просто сейчас попробовал закрыть окно, а потом обратится к его потомкам(вызвать метод show() и resize() ), которые должны были быть удалены(чтобы проверить удалились ли потомки). На экран ничего не выводится, но процесс остается запущен, хотя ни одного видимого окна нет. Отсюда возникли сомнения.
31 авг 2016 в 12:08
@LNK, когда уничтожается родитель, то он уничтожает всех потомков. Виджет верхнего уровня(окно) родителя не имеет, но благодаря атрибуту Qt::WA_DeleteOnClose оно самоуничтожится при закрытии. Если сомневаетесь, можете взять этот класс, написать в конце конструктора какого-нибудь окна new Watcher(this); и убедится, что все работает
31 авг 2016 в 12:38
@LNK, если перефразировать ваш вопрос, то получится «Что будет, если обратится к удаленному объекту?». Ответ — Undefined Behavior. Программа может нормально продолжить работать, может вылететь с ошибкой, может заполнить всю имеющуюся память нулями, может отформатировать жесткий диск. Короче, при обращении к удаленным объектам произойти может все что угодно, и это будет в рамках стандарта.
31 авг 2016 в 16:38
Виджет-родитель при уничтожении автоматически удалит своих потомков.
When QObjects are created on the heap (i.e., created with new), a tree can be constructed from them in any order, and later, the objects in the tree can be destroyed in any order. When any QObject in the tree is deleted, if the object has a parent, the destructor automatically removes the object from its parent. If the object has children, the destructor automatically deletes each child. No QObject is deleted twice, regardless of the order of destruction.
Другими словами если у вас что-то отображается в окне, то достаточно удалить виджет окна, об остальном позаботится система объектных иерархий Qt.