Russian Qt Forum
Апрель 19, 2024, 00:26 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Закрытие/открытие формы.  (Прочитано 10093 раз)
newbie
Гость
« : Сентябрь 27, 2016, 05:27 »

Здравствуйте!
В qt тотальный новичок, поэтому возникают дурацкие вопросы, например: как правильно закрыть форму? Судя по гуглу, вопрос распространённый, но решения, которое сработало бы для меня, я не нашёл. Справку читал, но не всегда могу там найти ответы (как сейчас, например).

Суть: при закрытии формы закрывается вся программа, вместо того, чтобы закрыть окно. Как это исправить?

Подробнее: у меня есть форма класса "start_Form", она "QWidget". На ней есть кнопка, открывающая главное окно класса "Main_Window", оно "QMainWindow". В главном окне через меню вызывается ещё одна форма класса "edit_Form", которая "QWidget". Нужно, чтобы по нажатию кнопки на start_Form, открывалась главное окно, а начальная форма пряталась, и наоборот — при закрытии главного окна появлялась start_Form.  Это дело я реализовал так:

Код:
// start_form.cpp
    void start_Form::on_db_Button_clicked()
{
    this->hide();
    var_main_window = new Main_Window(this);
    //var_main_window->setAttribute(Qt::WA_DeleteOnClose);
    connect (var_main_window, Main_Window::main_window_close, this, start_Form::show);
    var_main_window->show();
}

// main_window.cpp
void Main_Window::closeEvent(QCloseEvent *event)   
{
    event->accept();
    emit main_window_close();
}

// main_window.h
protected:
    void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;

signals:

    void main_window_close();
    void edit_window_open();
Всё работает, как нужно. Вторую форму (edit_Form) я открываю так:
Код:
// main_window.cpp
void Main_Window::on_edit_table_triggered()
{
    var_edit_window = new edit_Form();
    //var_edit_window->setAttribute(Qt::WA_DeleteOnClose);
    connect (this, Main_Window::edit_window_open, var_edit_window, edit_Form::show);
    connect (var_edit_window, edit_Form::edit_window_close, this, Main_Window::show);
    emit edit_window_open();
}
Здесь начинаются проблемы. При закрытии формы закрывается вся программа целиком, но требуется чтобы закрылось только эта форма (edit_Form). Пробовал также переопределить closeEvent — не работает. Наткнулся, что в QWidget closeEvent не используется, пробовал reject(), close() — тоже самое. Вот и главный вопрос: как закрыть форму, чтобы программа не закрывалась.

P.S. Несколько вопросов, если не сложно ответьте и на них или дайте ссылки, где можно найти ответ.
1) В форме edit_Form, если я использую
Код:
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
...
void edit_Form::closeEvent(QCloseEvent *event)
{
    event->accept();
    emit edit_window_close();
}
компилятор говорит: "invalid use of incomplete type 'class QCloseEvent'". В коде выше это работает, что не так?
2) Обязательно ли писать "event->accept();"? Зачем он нужен в справке написано, но всё же зачем он, если и без него работает (проверил)?
3) Где лучше писать connect и объявлять переменные классов форм? Сначала делал это в конструкторе start_Form, но потом перенёс их на кнопки. Работает и там, и там.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #1 : Сентябрь 27, 2016, 11:10 »

Во вложении пример с переключением видимости форм. Оговорюсь, что не самый лучший, так как не до конца понял, что из себя представляет программа.
Записан
Bepec
Гость
« Ответ #2 : Сентябрь 27, 2016, 11:16 »

Поможет вам вот такая вот строка Веселый
Код:
qApp->setQuitOnLastWindowClosed(false);

PS qApp - это указатель на QApplication, следовательно хедер #include <QApplication> должен быть включен обязательно Улыбающийся
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #3 : Сентябрь 27, 2016, 11:47 »

Цитировать
при закрытии формы закрывается вся программа, вместо того, чтобы закрыть окно. Как это исправить?
Самое простое - не закрывать все формы, так как по умолчанию это интерпретируется как выход из программы.

Цитировать
компилятор говорит: "invalid use of incomplete type 'class QCloseEvent'"
Дело в том, что на момент использования экземпляра QCloseEvent сам класс является объявленным, но не определённым. Это позволяет таскать указатель на этот экземпляр, но не позволяет разыменовывать его для обращения к методам QCloseEvent. Решение:
Код
C++ (Qt)
#include <QCloseEvent>

Цитировать
3) Где лучше писать connect и объявлять переменные классов форм? Сначала делал это в конструкторе start_Form, но потом перенёс их на кнопки. Работает и там, и там.
Если на кнопки переносить, то будет по каждому щелчку вызываться лишний (кроме первого) connect. Рекомендую завести отдельный метод для коннектов и вызывать его в конструкторе класса формы. Где объявлять переменные класса формы - зависит от задачи. Если имеется "родительство" одной формы над другой, то, имхо, лучше дочернюю форму сделать членом класса родительской формы.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #4 : Сентябрь 27, 2016, 12:00 »

Цитировать
2) Обязательно ли писать "event->accept();"? Зачем он нужен в справке написано, но всё же зачем он, если и без него работает (проверил)?
Не пользовался этим, но судя по описаниям справки у нас в QEvent по умолчанию флаг accepted принят true, но не стоит на это полагаться, так как классы наследники могут назначить ему false в своих конструкторах. У QCloseEvent по умолчанию этот флаг в положении true. Если мы хотим отменить процесс закрытия окна, то переводим его в false, иначе просто ничего не делаем. Но также существует вероятность, что экземпляр QCloseEvent может прилететь в метод с выставленным флагом false, например из какого-то наследника, который решил отменить закрытие формы, а вы своим кодом
Код
C++ (Qt)
event->accept()
насильно заставляете его закрыться.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Сентябрь 27, 2016, 12:18 »

Большинство приложений используют примерно такой подход

Есть MainWindоw - главное окно, всегда только одно и "на всю жизнь". Закрытие MainWindоw означает закрытие приложения. Часто оно вообще всегда видимо. Если по каким-то причинам это не устраивает - скройте его методом hide, но не удаляйте. Все остальные окна - чайлды MainWindоw. Тогда легко узнать какие окна сейчас созданы/видимы даже не храня никаких указателей, напр
Код
C++ (Qt)
MyForm1 * form1 = var_main_window->findChild<MyForm1 *>();
if (!form1)  // создадим форму 1 если ее еще нет
   form1 = new MyForm1(var_main_window);
if (!form1->isVisible())
form1->show();
Также есть смысл сделать var_main_window синглтоном (глобальной переменной) чтобы не чикаться со слот/сигналами а звать его методы напрямую
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #6 : Сентябрь 27, 2016, 12:48 »

Не рекомендую
Код:
qApp->setQuitOnLastWindowClosed(false);

Потому, что на мой взгляд он не решит проблему, так как в любом случае переключение окон будет осуществляться тогда, когда хотя бы одно из них не закрыто, то есть в момент закрытия. Но при этом ещё придётся заботиться о выходе из приложения.

Также, считаю, что findChild не совсем удобный инструмент. ИМХО, гораздо проще хранить дочерние формы в виде членов класса. Это позволит избежать лишних проверок и конструирования элемента ручками.
Мне кажется, что не стоит делать глобальным главное окно ради удобств вызова слотов. Такое решение жёстко связывает классы и может стать проблемой для дальнейшего повторного использования дочернего класса.
Записан
Bepec
Гость
« Ответ #7 : Сентябрь 27, 2016, 14:11 »

Любое ваше решение кроме setQuitLastWindow несёт ограничения Веселый
Как то члены класса, как то сиглтон/главное окно. Они не хуже, но используются в разных ситуациях Веселый
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #8 : Сентябрь 27, 2016, 14:24 »

Bepec, а можете сделать примерчик с использованием setQuitLastWindow? Я не совсем понимаю, где вы его использовать собираетесь.
Записан
Bepec
Гость
« Ответ #9 : Сентябрь 27, 2016, 14:52 »

Вы прочитайте название темы, вопрос тсса и поймете где его будет использовать ТС, Igors, Вы и любой пожелавший Веселый

PS то, что вы с Igors развили тему, это хорошо. Плохо, что вы не ответили на главный вопрос ТСса, а стали придумывать "костыли".

PPS если даже так непонятно, то добавление этой строчки заставит работать программу ТСса предсказуемо для него. Точка. Проблема решена, основной вопрос закрыт.
Записан
newbie
Гость
« Ответ #10 : Сентябрь 27, 2016, 15:01 »

Во-первых, всем большое спасибо за ответы.
А во-вторых, третьих и т.д.:
С ответами на доп. вопросы вроде разобрался, по основному же
Цитировать
qApp->setQuitOnLastWindowClosed(false);
действительно работает, но не так, как хотелось бы. Окно формы закрывается, но не уничтожается, т.е. новом открытии формы edit_Form создаётся вторая форма edit_Form и красуется рядом с первой. Плюс, при закрытии всех окон, процесс остаётся висеть в системе. Сделал всем окнам
Код:
var_start_form.setAttribute(Qt::WA_DeleteOnClose);
...
var_edit_window->setAttribute(Qt::WA_DeleteOnClose);
...
var_main_window->setAttribute(Qt::WA_DeleteOnClose);
Тогда при закрытии последней формы программа крашится. Опять возник вопрос Улыбающийся
Что я делаю не так, и как это исправить?

Цитировать
Цитировать
при закрытии формы закрывается вся программа, вместо того, чтобы закрыть окно. Как это исправить?
Самое простое - не закрывать все формы, так как по умолчанию это интерпретируется как выход из программы.
Не закрываю все, только одно. На момент закрытия "формы 2" у меня "форма 1" hide, а главное окно видно и торчит рядом со второй формой.

P.S. В процессе снова возникла пара доп. вопросов:
1)
Код:
qApp->setQuitOnLastWindowClosed(false);
Работает везде, где бы я его не написал (с тем же результатом) и в main.cpp, и в конструкторах и на кнопках. Куда это писать по-хорошему?
2) На момент написания думал, что в форме создавать главное окно так себе индусня, но не хотел переписывать. Сейчас решил это переделать, и столкнулся со следующей проблемой (которая, правда, была и до этого):
Код:
// var_start_window создаётся в главном окне QMainWindow.
var_start_window = new start_Form(); // 1-ый вариант. Работает.
var_start_window = new start_Form(this); // 2-ой. Не работает.
Когда я главным окном (QMainWindow) создаю форму (QWidget), то в первом варианте всё замечательно, окно появляется. Во втором случае же новое окно не появляется, его интерфейс отображается поверх интерфейса главного окна. В случае, если я создаю QMainWindow в QWidget, то оно работает. Почему так? Если я правильно понял, то такая конструкция указывает на "наследника"/зависимого/как-его-правильно-назвать, говорит, что var_start_window будет зависеть от this и при уничтожении this, уничтожится и var_start_window. И если правильно понял, то нужно это для исключения возможности утечки памяти. Правильно ли я понял, нужно ли так вообще делать? И если нужно, то как правильно?

3) Можно ли часть ответа под спойлером прятать? А то у меня полотна какие-то получаются Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Сентябрь 27, 2016, 15:21 »

var_start_window = new start_Form(this); // 2-ой. Не работает.

Когда я главным окном (QMainWindow) создаю форму (QWidget), то в первом варианте всё замечательно, окно появляется. Во втором случае же новое окно не появляется, его интерфейс отображается поверх интерфейса главного окна.
Укажите что создаете окно, а не просто виджет
Код
C++ (Qt)
var_start_window = new start_Form(this, Qt::Window);
 

Плохо, что вы не ответили на главный вопрос ТСса, а стали придумывать "костыли".
У Вас забыли спросить

PPS если даже так непонятно, то добавление этой строчки заставит работать программу ТСса предсказуемо для него. Точка. Проблема решена, основной вопрос закрыт.
Здесь нужно не строчки менять а метод/подход
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #12 : Сентябрь 27, 2016, 15:42 »

newbie, советую ещё посмотреть класс QDialog.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.122 секунд. Запросов: 22.