Russian Qt Forum

Qt => Вопросы новичков => Тема начата: PavelVX от Сентября 24, 2012, 10:23



Название: когда вызывается деструктор класса?
Отправлено: PavelVX от Сентября 24, 2012, 10:23
Ситуация следующая: есть
class MainWindow : public QMainWindow.
На него укладываются QDockWidget на которых мои виджеты(wid1, wid2, ...). В wid1, при определенном действии, создается wid1_1,
        widAdv = new wid1_1();
        widAdv->show();
//   this->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); (это прописано в конструкторе wid1_1)
Таким образом получаем рядом с основной программой, окно спутник, которое всегда сверху, где все действия взаимодействуют через сигналы и слоты.
Но вот приходит время закрытия программы. Закрываем основное окно, спутник не закрывается. Вроде бы логично, поскольку спутник не имеет родителя. Но возникает вопрос: а как тогда закрывать спутник при закрытии программы? Попробовал вставить это в деструктор
~wid1{ wid1_1->close(); qDebug() << "destr"; }
В итоге получаю странный результат: Если закрывать wid1, то деструктор вызывается сразу и все проходит как надо. Если же закрывать QMainWindow, то деструктор не вызывается, пока ВРУЧНУЮ не закроется wid1_1? Почему? Кто виноват, и что делать? :)


Название: Re: когда вызывается деструктор класса?
Отправлено: Пантер от Сентября 24, 2012, 10:30
Qt:: WA_DeleteOnClose


Название: Re: когда вызывается деструктор класса?
Отправлено: Kurles от Сентября 24, 2012, 10:39
Закрытие QMainWindows != его уничтожению, eventLoop продолжает крутиться, обслуживая твоё окно-спутник. Может быть такой вот вызов главного окна поможет:
Код
C++ (Qt)
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   MainWindow *w = new MainWindow();
   w->setAttribute(Qt::WA_DeleteOnClose);
   w->show();
 
   return a.exec();
}
или вручную закрывать все созданые окна в void QWidget::closeEvent ( QCloseEvent * event ) [virtual protected]


Название: Re: когда вызывается деструктор класса?
Отправлено: Kurles от Сентября 24, 2012, 10:41
Qt:: WA_DeleteOnClose
Интересно, что произойдет с окном (объектом) с этим атрибутом, если оно создано не в куче, а на стеке?


Название: Re: когда вызывается деструктор класса?
Отправлено: PavelVX от Сентября 24, 2012, 10:44
Ребята, без паники!
В конструкторе
wid1::wid1(...) {
...
setAttribute(Qt::WA_DeleteOnClose);
...}
Уже стоит, но не помогает.
Такой же атрибут стоит и на doc на который накладывается wid1.
В общем-то я и хотел, при закрытии виджета закрыть спутник.
Кстати, последовательность закрытия влияет на события.
1. Если закрывать wid1, то все нормально, выполнится деструктор, спутник закроется, дальше все как надо.
2. Если закрывать главное окно, то висим и ждем, пока не закроем спутник, тогда и деструктор вызовется. Кстати, тут непонятка есть: если я закрываю спутник, то он же должен удалиться? Значит указатель на него показывает хз куда. И вызывая wid1_1->close(); я обращаюсь непонятно куда. Но программа не рушится.


Название: Re: когда вызывается деструктор класса?
Отправлено: Kurles от Сентября 24, 2012, 10:55
Минимально компилируемый пример.


Название: Re: когда вызывается деструктор класса?
Отправлено: Igors от Сентября 24, 2012, 11:17
Сделать указатель на спутник членом главного окна и в деструкторе удалять. Т.к. спутник может быть удален и самостоятельно здесь хорошо использовать QPointer


Название: Re: когда вызывается деструктор класса?
Отправлено: GreatSnake от Сентября 24, 2012, 11:22
повесь сигнал на wid1
Код
C++ (Qt)
connect( mainwindow, SIGNAL( destroyed() ), wid1, SLOT( close() ) );


Название: Re: когда вызывается деструктор класса?
Отправлено: PavelVX от Сентября 24, 2012, 11:50
повесь сигнал на wid1
Код
C++ (Qt)
connect( mainwindow, SIGNAL( destroyed ), wid1, SLOT( close() ) );

Повесил, не помогает. Сделал так:
Код:
MainWindow::~MainWindow()
{
    qDebug() << "main";
}
Надпись появляется, когда я закрываю спутник. Все приложение ждет закрытия спутника :)


Название: Re: когда вызывается деструктор класса?
Отправлено: GreatSnake от Сентября 24, 2012, 11:53
ну, а на MainWindow
Код
C++ (Qt)
setAttribute(Qt::WA_DeleteOnClose);
был выставлен?


Название: Re: когда вызывается деструктор класса?
Отправлено: PavelVX от Сентября 24, 2012, 12:01
Нет.
Сейчас выставил.
Код:
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->setGeometry(100, 100, 800, 600);
    setAttribute(Qt::WA_DeleteOnClose);
    statusBar()->showMessage(tr("Ready"));

}

MainWindow::~MainWindow()
{
}

При закрытии программы происходит краш.


Название: Re: когда вызывается деструктор класса?
Отправлено: GreatSnake от Сентября 24, 2012, 12:06
Нет.
Сейчас выставил.
Ну, а почему не читаешь советы Kurles ???

Цитировать
При закрытии программы происходит краш.
Опять же Kurles сразу тебе сказал о возможных проблемах.
Почему не читаем советы ???


Название: Re: когда вызывается деструктор класса?
Отправлено: Kurles от Сентября 24, 2012, 12:07
Нет.
Сейчас выставил.
Код:
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->setGeometry(100, 100, 800, 600);
    setAttribute(Qt::WA_DeleteOnClose);
    statusBar()->showMessage(tr("Ready"));

}

MainWindow::~MainWindow()
{
}

При закрытии программы происходит краш.
Qt:: WA_DeleteOnClose
Интересно, что произойдет с окном (объектом) с этим атрибутом, если оно создано не в куче, а на стеке?
Вот наверное ответ на мой вопрос ) В main(..) создвавй MainWindows не на стеке, а на куче, т.е. через оператор new.


Название: Re: когда вызывается деструктор класса?
Отправлено: PavelVX от Сентября 24, 2012, 12:19
СПАСИБО всем!!!
Отдельное спасибо:
1. Kurles за void QWidget::closeEvent ( QCloseEvent * event ) [virtual protected]! (тут я просмотрел, мой косяк)
2. Igors за QPointer (про это я не знал, использовал похожую самописную фигнюшку)
3. GreatSnake за попытку повторно обратить мое внимание на п1.
В итоге все заработало. Сейчас нужные части на QPointer переведу и будет красивый и читабельный код.
Еще раз спасибо!
Код:
void MainWindow::closeEvent ( QCloseEvent * event )
{
    qDebug() << "close event";
    if (wid1)
    {
        qobject_cast< QDockWidget* >(wid1->parent())->close();
    }
}


Название: Re: когда вызывается деструктор класса?
Отправлено: Пантер от Сентября 24, 2012, 12:22
За qobject_cast< QDockWidget* >(wid1->parent())->close() нужно руки выдирать.


Название: Re: когда вызывается деструктор класса?
Отправлено: PavelVX от Сентября 24, 2012, 12:25
Почему? Мне же нужно удалить виджет, на который я накладываю свой класс? Как правильнее?


Название: Re: когда вызывается деструктор класса?
Отправлено: GreatSnake от Сентября 24, 2012, 12:26
2. GreatSnake за QPointer (про это я не знал, использовал похожую самописную фигнюшку) и за попытку повторно обратить мое внимание
Про QPointer говорил Igors.
И ещё раз повторюсь, самый безопасный и практичный способ здесь (http://www.prog.org.ru/index.php?topic=23113.msg163190#msg163190).


Название: Re: когда вызывается деструктор класса?
Отправлено: Странник от Сентября 24, 2012, 14:59
Почему? Мне же нужно удалить виджет, на который я накладываю свой класс? Как правильнее?
ну хотя бы потому, что:
- если у wid1 нет родителя - крэш.
- если родитель wid1 не QDockWidget - крэш.
- есть QWidget * QWidget::parentWidget () const
- кастить нет никакого смысла, можно вызвать bool QWidget::close () [slot]. и сделать это, кстати говоря, через сигнал-слот, как вам предложил GreatSnake.


Название: Re: когда вызывается деструктор класса?
Отправлено: PavelVX от Сентября 25, 2012, 06:46
голосу более опытных товарищей внял, код переписал. Спасибо.