Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

nullptr layout from widget inside QTabWidget?



  • I'm trying to get a child of a widget within a layout from QTabWidget

    It's inserted like this:

    QWidget* containerWidget = new QWidget();
    containerWidget->setLayout(new QVBoxLayout());
    containerWidget->layout()->addWidget(new ViewWidget());
    tabWidget->insertTab(index, containerWidget, "Example");
    tabWidget->setCurrentIndex(index);
    

    Then I try to reacquire it with:

    QWidget* containerWidget = tabWidget->widget(index);
    ViewWidget* viewWidget = qobject_cast<ViewWidget*>(containerWidget->layout()->itemAt(0)->widget());
    

    But layout returns nullptr? What am I doing wrong?



  • @SGaist As I said earlier it is created within the markup (.ui file). It is a QWidget promoted into my ViewWidget. In my MainWindow the "ui_MainWindow.h" is included and Ui::MainWindowWidget ui; is declared as a member and setup. ui.viewWidget1 is ultimately where it exists. However, over the course of the program the tabs and contained ViewWidget's will be added and removed. Thus I cannot access it this way for all tabs. For example, the ui.viewWidget1 could be deleted when the tab is deleted.

    Looking at the file generated by Qt it did:

            tabWidget1 = new QTabWidget(centralwidget);
            tabWidget1->setObjectName(QString::fromUtf8("tabWidget1"));
            tabWidget1->setTabsClosable(false);
            tabWidget1->setMovable(true);
            tab1 = new QWidget();
            tab1->setObjectName(QString::fromUtf8("tab1"));
            verticalLayout = new QVBoxLayout(tab1);
            verticalLayout->setSpacing(0);
            verticalLayout->setContentsMargins(11, 11, 11, 11);
            verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
            verticalLayout->setContentsMargins(0, 0, 0, 0);
            viewWidget1 = new View3DWidget(tab1);
            viewWidget1->setObjectName(QString::fromUtf8("viewWidget1"));
    
            verticalLayout->addWidget(viewWidget1);
    

    The layout was not set to the widget with setLayout but the widget was given through the constructor to the layout. So this brings me to the question. What's the difference between doing:

    QWidget* parent = new QWidget();
    QVBoxLayout* layout= new QVBoxLayout(parent);
    

    and

    QWidget* parent = new QWidget();
    QVBoxLayout* layout = new QVBoxlayout();
    parent->setLayout(layout);
    

    In fact, if I manually edit Qt's generated code to be the latter, my code then works and I can use:

    ViewWidget* viewWidget = qobject_cast<ViewWidget*>(tabWidget->widget(index)->layout()->itemAt(0)->widget());
    

    to obtain whatever view is present.

    So I then just solved this by removing the initial tabs from QTabWidget in the markup and adding them myself as shown above. This solved the problem and seems like a more appropriate solution as it prevents some nullptrs hanging around in the generated Ui::MainWindowWidget for tabs that were deleted.


  • Lifetime Qt Champion

    Hi,

    This looks pretty convoluted. Why not have your ViewWidget be responsible for returning its internal widget ?



  • Yeah that's the first thing I tried but it didn't work. I'm using .ui file for the initialization of the tabwidget and Qt Creator doesn't let you set a layout on the tab widget directly. So you have to do:

    QTabWidget
      BaseWidget
        Layout
          Widget I want to fill the tab widget
    

    What you're suggesting sounds like

    QTabWidget
      Layout
        MyWidget
    

    0_1550105183087_2019-02-13 18_45_04-MainWindow.ui [Temp] - Qt Creator.jpg
    Maybe I just don't know how to do it in Qt Creator?


  • Qt Champions 2019

    @Andaharoo I think what @SGaist means is that your ViewWidget has a method which returns the internal widget, so the the caller does not have to know any internal details of ViewWidget.



  • @jsulm @SGaist I think I read that wrong or it was edited. What does he mean by "Internal Widget" the only thing inside ViewWidget is a QVTK widget from VTK to display 3d views and the such through Qt.

    Or do you mean get the parent through the ViewWidget? I don't have the ViewWidget and I'm trying to get it. All I have is the tab widget and need to acquire the ViewWidget which is inside the TabWidget. But the normal way I would access children from a layout is not working.


  • Lifetime Qt Champion

    Where does that ViewWidget come from then ?



  • @SGaist As I said earlier it is created within the markup (.ui file). It is a QWidget promoted into my ViewWidget. In my MainWindow the "ui_MainWindow.h" is included and Ui::MainWindowWidget ui; is declared as a member and setup. ui.viewWidget1 is ultimately where it exists. However, over the course of the program the tabs and contained ViewWidget's will be added and removed. Thus I cannot access it this way for all tabs. For example, the ui.viewWidget1 could be deleted when the tab is deleted.

    Looking at the file generated by Qt it did:

            tabWidget1 = new QTabWidget(centralwidget);
            tabWidget1->setObjectName(QString::fromUtf8("tabWidget1"));
            tabWidget1->setTabsClosable(false);
            tabWidget1->setMovable(true);
            tab1 = new QWidget();
            tab1->setObjectName(QString::fromUtf8("tab1"));
            verticalLayout = new QVBoxLayout(tab1);
            verticalLayout->setSpacing(0);
            verticalLayout->setContentsMargins(11, 11, 11, 11);
            verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
            verticalLayout->setContentsMargins(0, 0, 0, 0);
            viewWidget1 = new View3DWidget(tab1);
            viewWidget1->setObjectName(QString::fromUtf8("viewWidget1"));
    
            verticalLayout->addWidget(viewWidget1);
    

    The layout was not set to the widget with setLayout but the widget was given through the constructor to the layout. So this brings me to the question. What's the difference between doing:

    QWidget* parent = new QWidget();
    QVBoxLayout* layout= new QVBoxLayout(parent);
    

    and

    QWidget* parent = new QWidget();
    QVBoxLayout* layout = new QVBoxlayout();
    parent->setLayout(layout);
    

    In fact, if I manually edit Qt's generated code to be the latter, my code then works and I can use:

    ViewWidget* viewWidget = qobject_cast<ViewWidget*>(tabWidget->widget(index)->layout()->itemAt(0)->widget());
    

    to obtain whatever view is present.

    So I then just solved this by removing the initial tabs from QTabWidget in the markup and adding them myself as shown above. This solved the problem and seems like a more appropriate solution as it prevents some nullptrs hanging around in the generated Ui::MainWindowWidget for tabs that were deleted.


Log in to reply