Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Родитель виджета, не удаляющий дитёнка
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Общие вопросы
Алексей1153
В общем то, иногда напрягает эта самодеятельность - что родительский виджет мочит чайлдов, когда сам разрушается. Это можно как-то запретить делать ? Но само родительство должно оставаться в силе
Litkevich Yuriy
Цитата(Алексей1153 @ 12.11.2010, 17:15) *
Это можно как-то запретить делать ?
нет. а где может понадобится оставлять сирот?
Алексей1153
Litkevich Yuriy, много где может. Например: имеется список виджетов. Создаю временного родителя, связываю, показываю их там (или в другом порядке - сначала создан родитель, потом заполнен список)

А потом мне родитель не нужен, а дети должны остаться. Я мочу родителя, а он мочит детей - некузяво.

разве что попробовать при разрушении родителя отсоединить всех детей
Litkevich Yuriy
Цитата(Алексей1153 @ 12.11.2010, 18:56) *
А потом мне родитель не нужен, а дети должны остаться.
установи всем детям "0" в качестве родителя
panter_dsd
Можно пробовать по сигналу void QObject::destroyed ( QObject * obj = 0 ) [signal] родителя забирать у него детей.
Litkevich Yuriy
Цитата(Алексей1153 @ 12.11.2010, 18:56) *
имеется список виджетов. Создаю временного родителя, связываю, показываю их там
...
А потом мне родитель не нужен, а дети должны остаться.
вообще здесь нужен "управлятор" этим процессом, который и будет следить за объектами и их связями

Имеет смысл полистать и освежить в памяти шаблоны проектирования.
Алексей1153
Цитата(Litkevich Yuriy @ 12.11.2010, 18:03) *
установи всем детям "0" в качестве родителя

нее, они тогда не смогут быть его кнопками/окошками :)

Цитата(panter_dsd @ 12.11.2010, 18:29) *
Можно пробовать по сигналу void QObject::destroyed ( QObject * obj = 0 ) [signal] родителя забирать у него детей.

вот это более на правду похоже, попробую завтра

kwisp
Цитата(Алексей1153 @ 12.11.2010, 18:38) *
они тогда не смогут быть его кнопками/окошками :)

кого его?
ты в следующей строчке его удалишь.
что то типа:
void killWidgetWithoutChildren(QWidget* wgt)
{
foreach(wgt->children(), QObject* obj) if(obj->isWidget()) obj->reparent(NULL);
delete wgt;
}
Алексей1153
Цитата(kwisp @ 12.11.2010, 20:47) *
кого его?

это я не так предложение прочитал. Юрий предлагает обнулить родителя у детей перед удалением родителя (я так и решил сделать). А я сначала почему-то решил, что он предлагает изначально не задавать родителя :D

---------------
А вот , вроде, и таблетка:
Цитата
void QWidget::destroy ( bool destroyWindow = true, bool destroySubWindows = true ) [protected]
Frees up window system resources. Destroys the widget window if destroyWindow is true.

destroy() calls itself recursively for all the child widgets, passing destroySubWindows for the destroyWindow parameter. To have more control over destruction of subwidgets, destroy subwidgets selectively first.

This function is usually called from the QWidget destructor.



то есть, в деструкторе просто вызвать

destroy ( true, false );

и всё :) Щас проверю
kwisp
Цитата(Алексей1153 @ 12.11.2010, 19:06) *
А вот , вроре, и таблетка:

ну да это больше на ООП похоже. хотя в нутрях предполагаю тоже происходит что и в приведенной мной функции
Litkevich Yuriy
Цитата(Алексей1153 @ 12.11.2010, 23:06) *
void QWidget::destroy ( bool destroyWindow = true, bool destroySubWindows = true ) [protected]
не смущает?
Алексей1153
Цитата(Litkevich Yuriy @ 12.11.2010, 21:55) *
не смущает?

ни грамма. Защищённые функции можно вызывать из потомков

Но!

в деструкторе вызывать УЖЕ поздно, а сигналы
destroyed()),this,SL
destroyed(QObject*))

почему-то не происходят. Вот такая петрушка
kwisp
Цитата(Litkevich Yuriy @ 12.11.2010, 19:55) *
не смущает?

как раз и не должно.
Унаследовался от QWidget и вперёд. Со спецификатором доступа public при наследовании все public и protected методы QWidget должны стать public и protected что ли методами наследника.

Цитата(Алексей1153 @ 12.11.2010, 20:11) *
в деструкторе вызывать УЖЕ поздно
Цитата(Алексей1153 @ 12.11.2010, 19:06) *
This function is usually called from the QWidget destructor.

странно.

Цитата(Алексей1153 @ 12.11.2010, 20:11) *
почему-то не происходят.

это вообще странно. может все таки ты где то ошибся. код давай.
и по-моему даже если их поймаешь то будет поздно - т.к. деструкторы вызываются в обратном порядке вызова конструкторов. получается если сигнал вызывается перед деструктором QObject то вся виджетная часть уже удалена.
Алексей1153
Цитата(kwisp @ 12.11.2010, 22:15) *
странно.

но факт. Проверил

kwisp
Цитата(Алексей1153 @ 12.11.2010, 20:20) *
но факт. Проверил

я тебе не верю. код давай.
Алексей1153
#pragma once

#include <QWidget>

class CWin : public QWidget
{
    Q_OBJECT
public:
    explicit CWin(QWidget *parent=0);
    
public slots:
    void preventChildrenKilling();
    void preventChildrenKilling(QObject *);
    
};



#include "CWin.h"

CWin::CWin(QWidget *parent) :QWidget(parent)
{
    connect(this,SIGNAL(destroyed()),this,SLOT(preventChildrenKilling()));
    connect(this,SIGNAL(destroyed(QObject*)),this,SLOT(preventChildrenKilling(QObject*)));
}

void CWin::preventChildrenKilling()
{
    destroy(true,false);
}
void CWin::preventChildrenKilling(QObject*)
{
    destroy(true,false);
}


    CWin* w=new CWin;
    
    std::vector<QWidget*> list;
    
    list.push_back(new QWidget(w));
    list.push_back(new QWidget(w));
    list.push_back(new QWidget(w));

    delete w;

    list[0]->show(); //тут нарушение сегментации (дитё уже убито)
    list[1]->show();
    list[2]->show();


что не так ?
kwisp
добавил в слот
void CWin::preventChildrenKilling(QObject*)

std::cout << __PRETTY_FUNCTION__ << "\n";

при работе получил вывод
Цитата
./test
void CWin::preventChildrenKilling(QObject*)
Ошибка сегментирования


так что на сигнал destoyed() зря грешишь он вызывается и даже слот срабатывает

можно попробовать через deleteLater()
посмотреть в багрекере троллей баг на destroy твоей версии Qt

---------
Цитата(Алексей1153 @ 12.11.2010, 20:11) *
в деструкторе вызывать УЖЕ поздно,

хотя ты знаешь все поддается логике.
деструкторы вызываются в обратном порядке. ты к примеру используешь destroy в своем деструкторе .сначала вызывается в твоем destroy(true,false) а затемм - destroy(true,true) в деструкторе QWidget вполне возможно что второй раз детки погибают от рук попаши.
panter_dsd
void QObject::destroyed ( QObject * obj = 0 ) [signal]
This signal is emitted immediately before the object obj is destroyed, and can not be blocked.
All the objects's children are destroyed immediately after this signal is emitted.
Алексей1153
kwisp, только сейчас обратил внимание, что в консоли вывод
Цитата
Object::connect: Attempt to bind non-signal CWin::destroyed()
Object::connect: Attempt to bind non-signal CWin::destroyed(QObject*)


определение в <qobject.h>
Цитата
Q_SIGNALS:
void destroyed(QObject * = 0);

- хм


Цитата(kwisp @ 12.11.2010, 22:37) *
посмотреть в багрекере троллей баг на destroy твоей версии Qt

это как делается ? и где



попробовал вызывать deleteLater() вместо delete. Потом, попозже, по мышиному событию вызвал show для детей - тоже вылет.

Похоже, остаётся только так
Цитата(kwisp @ 12.11.2010, 20:47) *
что то типа:
void killWidgetWithoutChildren(QWidget* wgt)
{
foreach(wgt->children(), QObject* obj) if(obj->isWidget()) obj->reparent(NULL);
delete wgt;
}
kwisp
Цитата(Алексей1153 @ 12.11.2010, 21:06) *
Похоже, остаётся только так

так точно
только правда что то типа. я скоренько накатал рабочий вариант. завернешь в функцию сам.
int main(int a, char** B)
{
  QApplication app(a,B);
  CWin* w = new CWin;
  QWidget* wgt = new QWidget(w);
  foreach(QObject* obj, w->children()) {
    if(obj->isWidgetType()) {
      std::cout << __func__ << '\n';
      qobject_cast<QWidget*>(obj)->setParent(NULL);
    }
  }
  delete w;
  wgt->show();
  return app.exec();
}

без qobject_cast не работает. что очень интересно.
а всё дело в setParent - их две в QObject и QWidget :)
как делать со всеми кнопками и лейблами. не знаю на сколько корректно будет приводить их к QWidget* думаю прокатит т.к. они все его прямые public наследники
Алексей1153
спасибо, конечно, но вот это
Цитата(kwisp @ 12.11.2010, 23:24) *
без qobject_cast не работает.

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

я же имею массив указателей на детей. Когда я хочу удалить окно, которое, как мне известно, может повлечь за собой удаление потомков, я должен пробежаться по массиву элементов и задать им родителя == 0.
Алексей1153
финт ушами :) Ничего переопределять и не пришлось
    CWin* w=new CWin;
        
    list.push_back(new QWidget(w));
    list.push_back(new QWidget(w));
    list.push_back(new QWidget(w));
    
    list[0]->setParent(0);
    list[1]->setParent(0);
    list[2]->setParent(0);
    
    delete w;
    w=0;

    list[0]->show();
    list[1]->show();
    list[2]->show();

это работает
Litkevich Yuriy
Цитата(Алексей1153 @ 13.11.2010, 2:43) *
list[0]->setParent(0);
list[1]->setParent(0);
list[2]->setParent(0);

delete w;
собственно, я про это и говорил
Алексей1153
Litkevich Yuriy, ну так то да. Только там я почему-то решил идти сложным путём - вытаскивать список детей из родителя, а надо то было в своём списке всё и сделать было :D
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.