For some reason the Qt compiler doesn't compile if you try to pass a QObject derived class as the rparent to a QWidget derived class.
What is the correct way to provide a parent to QWidget derived classes in a QObject derived class? I'm thinking of the following solutions:
- Use a smart pointer with the QWidget classes, instead of giving the object a parent.
- Derive from QWidget instead of QObject (Sounds wrong to me, since the class isn't a widget).
- Pass a QWidget instance to the QObject derviced class which already has a parent, as I've tried to demonstrate in the example below:
#include <QApplication>
#include <QtWidgets>
class ErrorMsgDialog;
class Controller;
class MainWindow;
// This is the QWidget class used in the QObject derived class (DataReadController)
class ErrorMsgDialog : public QDialog
{
Q_OBJECT
public:
explicit ErrorMsgDialog(QWidget *parent = nullptr)
: QDialog(parent)
{
errorLbl = new QLabel("An unknown read error occured!");
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(errorLbl);
setLayout(layout);
setWindowTitle("Error!");
setGeometry(250, 250, 250, 100);
}
~ErrorMsgDialog() { qDebug() << "~ErrorMsgDialog() destructed"; }
private:
QLabel* errorLbl;
};
// QObject derived class - I want to instatiate Qwidget derived classes here, with this class as parent
class DataReadController
: public QObject
{
Q_OBJECT
public:
DataReadController(QWidget* pw, QObject *parent = nullptr)
: QObject(parent)
{
m_errorMsgDialog = new ErrorMsgDialog(pw);
//m_errorMsgDialog = QSharedPointer<ErrorMsgDialog>(m_errorMsgDialog);
//m_dataReader = new DataReader(this); m_dataReader->moveToThread(m_dataReaderThread); connect(....etc
//simulate that DataReader emits an error msg
QTimer::singleShot(2000, [&]() {
onErrorTriggered();
});
}
public slots:
void onNewDataArrived() {}
// called if reader emits an error message
void onErrorTriggered() { m_errorMsgDialog->show(); }
private:
ErrorMsgDialog* m_errorMsgDialog;
//QSharedPointer<ErrorMsgDialog> m_errorMsgDialog;
//DataReader* m_dataReader;// DataReader is not shown here, it would be moved to a different thread and provide some data
};
// MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr)
: QMainWindow(parent)
{
parentWidget = new QWidget(this);
m_dataReadController = new DataReadController(parentWidget, this);
setGeometry(200, 200, 640, 480);
//Close after 5 seconds.
QTimer::singleShot(5000, [&]() {
close();
});
}
private:
QWidget* parentWidget; // QWidget to pass to OBject derive class for parenting QWidgets
DataReadController* m_dataReadController;
};
// Main
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#include "main.moc"
This test crashes if I use QSharedPointer with ErrorMsgDialog. Any suggestions on the way to do this? Maybe none of my suggested solutions is the best practise?

QWidgetexpects aQWidget*as parent. ThoughQWidgetis itself derived fromQObject, this doesn't change the first requirement. There is nothing wrong to have a pointer to aQWidgetin a class derived fromQObject. However, concerning ownership, aQWidgetshould be owned by anotherQWidget(and that's what the parentship actual means). Concerning yourErrorMsgDialog,MainWindow wwould be a sufficient parent. That doesn't mean thatDataReadControllercouldn't add/remove these instances (or just show/hide). - Scheff's CatDataReadControllerthat emits an error with the message as an argument, and connect this signal to a slot inMainWindowthat shows the message in a dialog. Think about how someQtclasses work, for exampleQSerialPort. You have a signal likeerrorOccurredwhich you can connect to when you want to show an error message. It doesn't show any dialogs on its own. You should follow a similar design. - thuga