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

Crash using QListWidget



  • Good afternoon,

    I am having problems with a widget. The widget and its code is as follows:

    ![alt text](image https://ibb.co/FzrvpQL)

    Below the "+" and "-" buttons there are 2 QListWidget where custom widgets are inserted, being these QListWidget as follows:

    ![alt text](image https://ibb.co/d7xnghc)

    The problem comes that when I try to add a new widget to the QListWidget, it crashes and closes everything. I have managed to find out that when they are going to insert the widget in one of the lists, the memory address of the lists has changed and that's where the crashes come from. But I can't understand the reason. And Image of problem:

    ![alt text](image https://ibb.co/rtgn9Wc)

    The code is the following:

    DataTypeListWidget.h

    #ifndef DATATYPELISTWIDGET_H
    #define DATATYPELISTWIDGET_H
    
    #include <QWidget>
    #include <QListWidget>
    #include <QListWidgetItem>
    
    #include "ItemDataTypeWidget.h"
    
    class DataTypeListWidget : public QWidget
    {
        Q_OBJECT
    public:
        DataTypeListWidget( QWidget* parent = nullptr );
    
        void AddNewWidget( QWidget* newWidget );
    
    public:
        QListWidget* _list;
        QHBoxLayout* layout;
    };
    
    #endif // DATATYPELISTWIDGET_H
    

    DataTypeListWidget.cpp

    #include "DataTypeListWidget.h"
    #include <QDebug>
    
    DataTypeListWidget::DataTypeListWidget(QWidget *parent)
        : QWidget( parent )
        , _list( new QListWidget( this ) )
    {
        layout = new QHBoxLayout( );
        layout->addWidget( _list );
    }
    
    void DataTypeListWidget::AddNewWidget(QWidget *newWidget )
    {
        QListWidgetItem* item = new QListWidgetItem( );
        _list->insertItem( _list->count(), item );
        item->setSizeHint( newWidget->sizeHint() );
        _list->setItemWidget( item, newWidget );
        layout->setSizeConstraint( QLayout::SetFixedSize );
        this->setMinimumSize( layout->sizeHint() );
    }
    

    SceneContainerConfigWindow.h

    #ifndef SCENECONTAINERCONFIGWINDOW_H
    #define SCENECONTAINERCONFIGWINDOW_H
    
    #include <QWidget>
    #include <QPushButton>
    #include <QLabel>
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    #include <QGridLayout>
    
    #include "DataTypeListWidget.h"
    #include "QDebug"
    
    class SceneContainerConfigWindow : public QWidget
    {
        Q_OBJECT
    public:
        explicit SceneContainerConfigWindow( QWidget* parent = nullptr );
        void BuildWidget();
        void BuildLogic();
    
    public slots:
        void AddInput();
        void AddOutput();
    
    protected:
        ItemDataTypeWidget* MakeNewItem( int pos, QStringList options );
    
    protected:
    
        QPushButton* apply;
        QPushButton* cancel;
    
        QPushButton* add_input;
        QPushButton* add_output;
        QPushButton* delete_input;
        QPushButton* delete_output;
    
        DataTypeListWidget* inputs_list;    int _input_count;
        DataTypeListWidget* outputs_list;   int _output_count;
    
        QLabel* input_label;
        QLabel* output_label;
    
        QHBoxLayout* actionsbuttons_layouts;
        QHBoxLayout* inputs_labes_layouts;
        QHBoxLayout* listwidgets_layouts;
        QHBoxLayout* add_delete_itemsList_layout;
        QGridLayout* p_layout;
    
        QVBoxLayout* main_layout;
    
        QStringList _options;
    
    };
    
    #endif // SCENECONTAINERCONFIGWINDOW_H
    

    SceneContainerConfigWindow.cpp

    #include "SceneContainerConfigWindow.h"
    
    SceneContainerConfigWindow::SceneContainerConfigWindow(QWidget *parent)
        : QWidget( parent )
        , _input_count( 0 ), _output_count( 0 )
    {
        BuildWidget();
        BuildLogic();
    }
    
    void SceneContainerConfigWindow::BuildWidget()
    {
        _options << "decimal" << "string";
    
        // First widgets level
        input_label     = new QLabel( " INPUTS ", this );
        output_label    = new QLabel( " OUTPUTS ", this );
    
        // Second widgets level
        add_input = new QPushButton( this );
        delete_input = new QPushButton( this );
    
        add_output = new QPushButton( this );
        delete_output = new QPushButton( this );
    
        p_layout = new QGridLayout();
        p_layout->addWidget( input_label, 0, 0, 1, 2 );
        p_layout->addWidget( output_label, 0, 2, 1, 2 );
    
        p_layout->addWidget( add_input, 1, 0, 1, 1 );
        p_layout->addWidget( delete_input, 1, 1, 1, 1 );
        p_layout->addWidget( add_output, 1, 2, 1, 1 );
        p_layout->addWidget( delete_output, 1, 3, 1, 1 );
    
    
        // Thirst widgets level
        DataTypeListWidget* inputs_list     = new DataTypeListWidget( this );
        DataTypeListWidget* outputs_list    = new DataTypeListWidget( this );
    
        inputs_list->setMinimumSize( 200, 300 );
        inputs_list->setMaximumSize( 5000, 5000 );
        inputs_list->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    
        outputs_list->setMinimumSize( 200, 300 );
        outputs_list->setMaximumSize( 5000, 5000 );
        outputs_list->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        listwidgets_layouts = new QHBoxLayout();
        listwidgets_layouts->addWidget( inputs_list );
        listwidgets_layouts->addWidget( outputs_list );
    
        // Four widgets level
        apply  = new QPushButton( "APPLY", this );
        cancel  = new QPushButton( "CANCEL", this );
    
        actionsbuttons_layouts = new QHBoxLayout();
        actionsbuttons_layouts->addSpacing( 150 );
        actionsbuttons_layouts->addWidget( cancel );
        actionsbuttons_layouts->addWidget( apply );
    
        // Adding all layout to widget
        main_layout = new QVBoxLayout();
        main_layout->addLayout( p_layout );
        main_layout->addLayout( listwidgets_layouts );
        main_layout->addLayout( actionsbuttons_layouts );
    
        this->setLayout( main_layout );
    
        this->setFixedSize( 520, 300 );
    
        qDebug() << "Input_List MEM DIR " << &inputs_list->_list;
        qDebug() << "Output_List MEM DIR " << &outputs_list->_list;
    
    }
    
    void SceneContainerConfigWindow::BuildLogic()
    {
    
        connect( add_input, &QPushButton::clicked,
                       this, &SceneContainerConfigWindow::AddOutput );
    
        connect( add_output, &QPushButton::clicked,
                 this, &SceneContainerConfigWindow::AddOutput );
    
        qDebug() << "Input_List MEM DIR " << &inputs_list->_list;
        qDebug() << "Output_List MEM DIR " << &outputs_list->_list;
    }
    
    void SceneContainerConfigWindow::AddInput()
    {
        _input_count++;
        ItemDataTypeWidget* item = new ItemDataTypeWidget(  );
        item->SetInfo( _input_count, _options );
        inputs_list->AddNewWidget( item );
    }
    
    void SceneContainerConfigWindow::AddOutput()
    {
        _output_count++;
        outputs_list->AddNewWidget( MakeNewItem( _output_count, _options ) );
    }
    
    ItemDataTypeWidget*
    SceneContainerConfigWindow::MakeNewItem(int pos, QStringList options)
    {
        ItemDataTypeWidget* item = new ItemDataTypeWidget();
        item->SetInfo( pos, options );
        return item;
    }
    

    ItemDataTypeWidget.h

    #ifndef ITEMDATATYPEWIDGET_H
    #define ITEMDATATYPEWIDGET_H
    
    #include <QWidget>
    #include <QLabel>
    #include <QListWidget>
    #include <QListWidgetItem>
    #include <QComboBox>
    #include <QHBoxLayout>
    
    class ItemDataTypeWidget : public QWidget
    {
        Q_OBJECT
    public:
        explicit ItemDataTypeWidget( QWidget * parent = nullptr );
        void SetInfo( int input_number, QStringList types_list );
    
    protected:
        void BuildWidget();
    
    protected:
        QLabel* label;
        QComboBox* type;
        QHBoxLayout* layout;
    
    };
    #endif // ITEMDATATYPEWIDGET_H
    

    ItemDataTypeWidget.cpp

    #include "ItemDataTypeWidget.h"
    
    
    ItemDataTypeWidget::ItemDataTypeWidget(QWidget* parent)
        : QWidget( parent )
    {
        BuildWidget();
    }
    
    void ItemDataTypeWidget::BuildWidget()
    {
        label = new QLabel( "Input", this );
        type = new QComboBox( this );
        layout = new QHBoxLayout();
    
        layout->addWidget( label );
        layout->addSpacing( 10 );
        layout->addWidget( type );
        layout->addStretch();
        layout->setSizeConstraint( QLayout::SetFixedSize );
        this->setLayout( layout );
    }
    
    void ItemDataTypeWidget::SetInfo(int input_number, QStringList types_list)
    {
        label->setText( "Input " + QString::number(input_number) );
        type->addItems( types_list );
        layout->setSizeConstraint( QLayout::SetFixedSize );
    }
    

  • Lifetime Qt Champion

    Please show/take a look at the backtrace to see where it really crashes.



  • @Christian-Ehrlicher, Here is an image of the debugger. I don't know if this is exactly what you meant. From what I see in the debugger, it fails to use the QListWidget class. It seems to me that the failure comes because that pointer with the class does not exist.

    The crash occurs in the AddNewWidget method of the DataTypeListWidget class.

    ![alt text](image https://ibb.co/Q6DSmrD)

    In the following image,
    ![alt text](image https://ibb.co/j8M9pGh)

    I print with debug messages the memory address of the QListWidget. The curious thing is that in the third call the memory address is different. I think that there is the failure, it tries to access an invalid memory address. But I don't understand the reason, because the constructor does instantiate the class.


  • Lifetime Qt Champion

    We can't see your images and you still don't tell us where exactly it crashes from your code.



  • Sorry, I didn't realize that the images are not visible. I have re-uploaded the images. I hope they are visible now.



  • @Jesus-C-Risq
    How do we/you know which instance of a DataTypeListWidget you are printing the address of _list from? If you're going to be printing addresses I'd include &this in your debug output.


  • Lifetime Qt Champion

    Your first image clearly show that the this pointer is a nullptr. So your pointer to DataTypeListWidget in AddNewWidget is a nullptr.
    Using a debugger should be a base skill btw - I suggest you to learn such stuff, otherwise debugging and fixing problems will become a pain.



  • @Christian-Ehrlicher said in Crash using QListWidget:

    Your first image clearly show that the this pointer is a nullptr

    Damn, you spot simple things quicker than I do :)
    Same point @Jesus-C-Risq though: you need to thinking about the instances of what you're printing out. And here the instance is, well, rubbish :)



  • I have already found the bug. In the end it was a silly thing, but as much as I checked the code I didn't see it.

    The problem was in the SceneContainerConfigWindow class. In the BuildWidget() method these two lines were wrong:

        DataTypeListWidget* inputs_list     = new DataTypeListWidget( this );
        DataTypeListWidget* outputs_list    = new DataTypeListWidget( this );
    

    Changing them for the following ones fixes it.

        inputs_list     = new DataTypeListWidget( this );
        outputs_list    = new DataTypeListWidget( this );
    

    The classes were instantiated but not assigned to any pointer, that's why the "inputs_list" address was empty.

    Thank you very much for the help and I take the advice to learn about debugger.


Log in to reply