2015-03-11 10 views
5

Il seguente codice compila perfettamente:Quali sono le conseguenze del forzare QObject come genitore di QWidget?

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

non può legalmente impostare QObject come genitore di QWidget. Ma usando qobject_cast è possibile. Ci sono conseguenze negative?

+1

Solo curioso: qual è la ragione di tale gerarchia? – vahancho

+3

Cosa?!? QWidget eredita pubblicamente da QObject –

+2

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

risposta

9

Qt non è progettato per supportare un genitore senza widget su un QWidget. Personalmente, lo tratterei come un hack inutile al momento. Si compilerà, ma non funzionerà mai. Lo considero un bug API in Qt, dal momento che un QWidget non è completamente un QObject nel senso Principio di sostituzione di Liskov a causa di questa limitazione.

Qt 4.x si blocca quando si tenta di attivare il widget. Quindi funzionerà finché non focalizzi la tua applicazione e poi si bloccherà.

Qt 5.x asserisce in QObject::setParent().

L'affermazione può essere aggirato, anche se:

// 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(); 
} 

andrà in crash da qualche altra parte, allora.

Sareste combattendo una battaglia in salita cercando di applicare Qt per farlo funzionare. Non è una lotta utile, credo - a meno che non venga presa una decisione per rendere un QWidget un vero QObject e cambiare la sua firma del costruttore. Questo può essere fatto al più presto in Qt 6 dato che è un cambiamento binario incompatibile con AFAIK.

Inoltre, quello che stai cercando di fare è per lo più inutile. È sicuramente possibile avere un genitore nascosto QWidget in più widget di livello superiore autonomi.

#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(); 
} 

Il sovraccarico di avere il widget di nascosto è minima, non stai sprecando le risorse utilizzando una QWidget invece di un QObject per il genitore.

Problemi correlati