Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?



  • Hi All,

    I have made a custom widget. It is a QSplitter with a number of widgets in it. When I then place that custom widget into another QSplitter, I have to specify the parent, while I don't have to do that when I add a QTextBrowser. Why is this? How come a QTextBrowser automatically knows the parent, while my custom widget does not?

    Below are the relevant parts of the code:

    myHlayout = new QSplitter();
    rs232Rx = new RS232(myHlayout);
    rs232Tx = new RS232(myHlayout);
    myHlayout->setOrientation(Qt::Horizontal);
    myHlayout->addWidget(rs232Rx);
    myHlayout->addWidget(rs232Tx);
    

    class definition of RS232:

    class RS232 : public QWidget
    {
        Q_OBJECT
    public:
        RS232(QWidget *parent=0);
    public slots:
       <snip>
    signals:
       <snip>
       
    private:
       <snip>
    };
    

    Cheers,
    Cedric


  • Moderators

    @cdwijs said in Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?:

    rs232Rx = new RS232(myHlayout);
    rs232Tx = new RS232(myHlayout);

    Why do you specify the parent here? Calling just addWidget() is enough.



  • @sierdzio said in Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?:

    @cdwijs said in Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?:

    rs232Rx = new RS232(myHlayout);
    rs232Tx = new RS232(myHlayout);

    Why do you specify the parent here? Calling just addWidget() is enough.

    Thanks Sierdzio, I have just tried it, but this line causes the widget to float in it's own window:
    rs232Rx = new RS232();

    This line causes the widget to correctly place itself in the QSplitter.
    rs232Rx = new RS232(myHlayout);

    Maybe this is only true on my PC:
    Windows 7 enterprise SP1
    QT 5.10.1
    mingw53_32

    Cheers,
    Cedric


  • Moderators

    @cdwijs said in Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?:

    Thanks Sierdzio, I have just tried it, but this line causes the widget to float in it's own window:

    That's because your splitter needs a parent.

    myHlayout = new QSplitter();



  • @sierdzio said in Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?:

    @cdwijs said in Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?:

    Thanks Sierdzio, I have just tried it, but this line causes the widget to float in it's own window:

    That's because your splitter needs a parent.

    myHlayout = new QSplitter();

    I'm not convinced :-) This yields 3 floating windows:

        myVlayout = new QSplitter(parent);
        myVlayout->setOrientation(Qt::Vertical);
        myRxLabel = new QLabel("Rx");
        myTxLabel = new QLabel("Tx");
        myClearBtn = new QPushButton("Clear");
        myLog = new QPlainTextEdit();
        myHlayout = new QSplitter(myVlayout);
        myHlayout->setOrientation(Qt::Horizontal);
        myHlayout->addWidget(myRxLabel);
        rs232Rx = new RS232();
        myHlayout->addWidget(rs232Rx);
        myHlayout->addWidget(myTxLabel);
        rs232Tx = new RS232();
        myHlayout->addWidget(rs232Tx);
        myHlayout->addWidget(myClearBtn);
        myVlayout->addWidget(myLog);
        myVlayout->addWidget(myHlayout);
        myVlayout->show();
    

    This yields the desired effect:

     myRxLabel = new QLabel("Rx");
        myTxLabel = new QLabel("Tx");
        myClearBtn = new QPushButton("Clear");
        myLog = new QPlainTextEdit();
        myHlayout = new QSplitter();
        myHlayout->setOrientation(Qt::Horizontal);
        myHlayout->addWidget(myRxLabel);
        rs232Rx = new RS232(myHlayout);
        myHlayout->addWidget(rs232Rx);
        myHlayout->addWidget(myTxLabel);
        rs232Tx = new RS232(myHlayout);
        myHlayout->addWidget(rs232Tx);
        myVlayout = new QSplitter();
        myVlayout->setOrientation(Qt::Vertical);
        myHlayout->addWidget(myClearBtn);
        myVlayout->addWidget(myLog);
        myVlayout->addWidget(myHlayout);
        myVlayout->show();
    

    I noticed this yields the 2 RS232 widgets to be displayed before the Rx and Tx labels, and finally the clear button:

    myRxLabel = new QLabel("Rx");
        myTxLabel = new QLabel("Tx");
        myClearBtn = new QPushButton("Clear");
        myLog = new QPlainTextEdit();
        myHlayout = new QSplitter();
        myHlayout->setOrientation(Qt::Horizontal);
        rs232Rx = new RS232(myHlayout);
        rs232Tx = new RS232(myHlayout);
        myHlayout->addWidget(myRxLabel);
        myHlayout->addWidget(rs232Rx);
        myHlayout->addWidget(myTxLabel);
        myHlayout->addWidget(rs232Tx);
        myVlayout = new QSplitter();
        myVlayout->setOrientation(Qt::Vertical);
        myHlayout->addWidget(myClearBtn);
        myVlayout->addWidget(myLog);
        myVlayout->addWidget(myHlayout);
        myVlayout->show();
    

    Cheers,
    Cedric


  • Lifetime Qt Champion

    Hi,

    Can you show the RS232 constructor content ?



  • @SGaist
    Sure:

    RS232::RS232(QWidget *parent)
    {
        qDebug()<<Q_FUNC_INFO;
    #ifdef FAKE_MESSAGES
        myTimer = new QTimer();
        connect(myTimer,&QTimer::timeout,this,&RS232::slotTimer);
        myTimer->setInterval(500);
        myTimer->start();
    #endif
        mySettingsDia = new SettingsDialog;
        myRxQueue = new QQueue<unsigned char>;
        myRxQueue->clear();
    
        mySerialPort = new QSerialPort ;
        myTxTimer = new QTimer();
        myTxTimer->setSingleShot(true);
        myRxTimer = new QTimer();
        myRxTimer->setSingleShot(true);
    
        myLabel = new QLabel("COM-");
    
        mySettingsBtn = new QPushButton;
        mySettingsBtn->setIcon(QIcon(":/images/wrench.png"));
        mySettingsBtn->setToolTip("Settings");
    
        myConnectBtn = new QPushButton;
        myConnectBtn->setIcon(QIcon(":/images/disconnected.png"));
        myConnectBtn->setToolTip("Connect");
    
        const int LED_SIZE = 10;
        myRxLED = new LedIndicator();
        myRxLED->setLedSize(LED_SIZE);
        myRxLED->setOnColor(Qt::green);
        myRxLED->setToolTip("Rx");
    
        myTxLED = new LedIndicator();
        myTxLED->setLedSize(LED_SIZE);
        myTxLED->setOnColor(Qt::green);
        myTxLED->setToolTip("Tx");
    
        myHlayout = new QSplitter();
        myHlayout->setOrientation(Qt::Horizontal);
        myHlayout->addWidget(myLabel);
        myHlayout->addWidget(myTxLED);
        myHlayout->addWidget(myRxLED);
        myHlayout->addWidget(mySettingsBtn);
        myHlayout->addWidget(myConnectBtn);
    
        connect(mySettingsBtn,&QPushButton::clicked,this,&RS232::slotSettings);
        connect(myConnectBtn,&QPushButton::clicked,this,&RS232::slotConnect);
        connect(mySerialPort,&QSerialPort::readyRead,this,&RS232::slotRx);
        connect(myRxTimer,&QTimer::timeout,this,slotRxTimer);
        connect(myTxTimer,&QTimer::timeout,this,slotTxTimer);
        myHlayout->setParent(parent);
        myHlayout->show();
    }
    

    And the class:

    class RS232 : public QWidget
    {
        Q_OBJECT
    public:
        RS232(QWidget *parent=0);
    public slots:
        slotSettings(bool clicked);
        slotConnect(bool clicked);
        slotDisconnect(bool clicked);
        slotMessage(QString string);
        slotRx();
        slotRxTimer();
        slotTxTimer();
    #ifdef FAKE_MESSAGES
        slotTimer();
    #endif
    signals:
        void sigOpenChanged(bool open);
        void sigReceived(QString msg);
    private:
    #ifdef FAKE_MESSAGES
        QTimer *myTimer;
    #endif
        QTimer *myTxTimer;
        QTimer *myRxTimer;
        LedIndicator *myRxLED;
        LedIndicator *myTxLED;
        SettingsDialog *mySettingsDia;
        QSplitter *myHlayout;
        QLabel *myLabel;
        QPushButton *mySettingsBtn;
        QPushButton *myConnectBtn;
        SettingsDialog::Settings *mySerSettings;
        QSerialPort *mySerialPort;
        QQueue<unsigned char> *myRxQueue;
    };
    

  • Moderators

    @cdwijs said in Parenting: why is a custom widget placed in a QSplitter not automatically a child of that splitter?:

    RS232::RS232(QWidget *parent)

    You are not initializing the parent class! Should be:

    RS232::RS232(QWidget *parent) : QWidget(parent)
    

    That should fix your problems. @SGaist well done :-)


  • Lifetime Qt Champion

    Also, you are using QSplitter like a layout manager which it is not. It's currently "floating" in RS232. Either put the splitter in a QVBox/HBoxLayout in RS232 (and other widgets you are using) or, depending on what you want to do, use layouts in place of QSplitter.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.