2015-03-11 11 views
5

Poniższy kod kompiluje się doskonale:Jakie są konsekwencje wymuszania QObject jako rodzica QWidget?

QObject* o = new QObject(0); 
QWidget* w = new QWidget(0); 
qobject_cast<QObject*>(w)->setParent(o); 

nie mogę ustawić QObject prawnie jako rodzic QWidget. Ale korzystanie z qobject_cast jest możliwe. Czy są negatywne konsekwencje?

+1

Po prostu ciekawy: jaki jest powód takiej hierarchii? – vahancho

+3

Co?!? QWidget dziedziczy publicznie z QObject –

+2

'QWidget :: setParent (QWidget *)' ukrywa 'QObject :: setParent (QObject *)'. – Oktalist

Odpowiedz

9

Qt nie jest przeznaczony do obsługi rodzica, który nie jest widgetem, do QWidget. Osobiście potraktowałbym to jako bezcelowe włamanie w tej chwili. To się skompiluje, ale nigdy nie zadziała. Uważam, że jest to błąd interfejsu API w Qt, ponieważ QWidget nie jest w pełni sensownym z powodu tego ograniczenia.

Qt 4.x ulegnie awarii podczas próby aktywacji widgetu. Będzie działać, dopóki nie skoncentrujesz aplikacji, a potem się zawiesi.

Qt 5.x zapewnia w QObject::setParent().

Twierdzenie można ominąć, choć:

// https://github.com/KubaO/stackoverflown/tree/master/questions/widget-parent-28992276 
#include <QApplication> 
#include <QLabel> 

class ParentHacker : private QWidget { 
public: 
    static void setParent(QWidget * child_, QObject * parent) { 
     // The following line invokes undefined behavior 
     auto child = static_cast<ParentHacker*>(child_); 
     Q_ASSERT(child->d_ptr->isWidget); 
     child->d_ptr->isWidget = 0; 
     child->QObject::setParent(parent); 
     child->d_ptr->isWidget = 1; 
    } 
}; 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    QLabel w{"Hello!"}; 
    w.setMinimumSize(200, 100); 
    w.show(); 
    ParentHacker::setParent(&w, &app); 
    return app.exec(); 
} 

Będzie on następnie rozbić gdzieś indziej.

Będziesz walczył w bitwach pod górkę, próbując załatać Qt, aby to zadziałało. Uważam, że nie jest to opłacalna walka, chyba że zostanie podjęta decyzja, aby dokonać prawdziwej QWidget prawdziwie-QObject i zmienić jego sygnaturę konstruktora. Można to zrobić najwcześniej w Qt 6, ponieważ jest to niezgodna z binarnymi zmianami AFAIK.

Co więcej, to, co próbujesz zrobić, jest w większości niepotrzebne. Z pewnością możesz mieć ukrytego rodzica QWidget do wielu samodzielnych widgetów najwyższego poziomu.

#include <QApplication> 
#include <QLabel> 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    QWidget parent; 
    QLabel l1{"Close me to quit!"}, l2{"Hello!"}; 
    for (auto label : {&l1, &l2}) { 
     label->setMinimumSize(200, 100); 
     label->setParent(&parent); 
     label->setWindowFlags(Qt::Window); 
     label->setText(QString("%1 Parent: %2."). 
        arg(label->text()).arg((quintptr)label->parent(), 0, 16)); 
     label->show(); 
    } 
    l2.setAttribute(Qt::WA_QuitOnClose, false); 
    return app.exec(); 
} 

szczytowy posiadania widget ukryty jest minimalne, nie marnujesz żadnych zasobów za pomocą QWidget zamiast QObject dla rodzica.

Powiązane problemy