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

calling QListWidgetItem setText() or setCheckState() on crashes Qt application



  • I have an application which needs to populate a QListWidget with entries. The list widget should have 2 data entries:

    1. Name
    2. Checkbox

    Using this as some reference and adapting it to something similar to this to enable user altering the QListWidgetItem::setCheckedState(), I get the following:

    MainWindow constructor

    MainWindow::MainWindow(QWidget* parent) :
         QMainWindow(parent),
         ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        //...
    
        // Called AFTER ui is setup
        // Call stack for the method below is: initGui > connectSettings > connectDriveListChanges > updateDrivesList
        updateDrivesListWidget();
        //...
    }
    

    later in constructor, this is called:

    void MainWindow::updateDrivesListWidget() {
        //...
    	// Get name of item
    	QString name = QString("Local Disk (%1)").arg(s);
    	bool enabled = attachedDriveList.value(s);
    
    	// create item for QListWidget named listDriveInfo on form
    	// QListWidgetItem* item = new QListWidgetItem(name, ui->listDriveInfo); <---crashes when setting text
    	QListWidgetItem* item = new QListWidgetItem(ui->listDriveInfo);
    
    	//set checkable and state
    	item->setText(name);                                                      < -----tried as alternative to crash above
    	item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
    	Qt::ItemFlags localFlags = item->flags();
    	localFlags = localFlags | Qt::ItemIsUserCheckable;
    	item->setFlags(localFlags);
    
    	// add item to list
    	ui->listDriveInfo->addItem(item);
        //...
    }
    

    I have run also ran Run qmake, also cleaned and rebuilt the project (incase of some invalid reference to the listWidget) but it keeps crashing at this same spot.


    Stepping through item->setText(name); callstack, I see the application crashes at this point:

    qlistwidget.cpp (ref)

    void QListModel::itemChanged(QListWidgetItem *item, const QVector<int> &roles)
    {
        const QModelIndex idx = index(item);
        emit dataChanged(idx, idx, roles);          <-------crash when emitting signal
    }
    

    Call stack here at the emit dataChange() line

    1  QListModel::itemChanged             qlistwidget.cpp 455  0x172b4ee8 
    2  QListWidgetItem::setData            qlistwidget.cpp 745  0x172b5c28 
    3  QListWidgetItem::setText            qlistwidget.h   179  0x4b2a7e   
    4  MainWindow::updateDrivesListWidget  MainWindow.cpp  1074 0x44d953   
    5  MainWindow::updateDrivesList        MainWindow.cpp  1390 0x45015b   
    6  MainWindow::connectDriveListChanges MainWindow.cpp  933  0x44c83d   
    7  MainWindow::connectSettings         MainWindow.cpp  466  0x448161   
    8  MainWindow::initGui                 MainWindow.cpp  57   0x444b4c   
    9  MainWindow::MainWindow              MainWindow.cpp  17   0x44449f   
    10 qMain                               main.cpp        230  0x466faf   
    11 WinMain *16                         qtmain_win.cpp  97   0x48df70   
    12 main                                                     0x4e0bfd   
    

    Debugger Content at the emit dataChange() line

    idx	@0x56af450	QModelIndex
    	c	0	int
    	i	783195744	quintptr
    	m	@0x2e9a2b18	QListModel
    	r	0	int
    item	@0x2eae9e60	QListWidgetItem
    	[vptr]	_vptr.QListWidgetItem	 
    	d	@0x2eb36c80	QListWidgetItemPrivate
    	dummy	<0 items>	QVector<void*>
    	itemFlags	(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled) (0x0035)	Qt::ItemFlags
    	rtti	0	int
    	view	"listDriveInfo"	QListWidget
    roles	<2 items>	QVector<int> &
    		0	int
    		2	int
    this	@0x2e9a2b18	QListModel
    	[QAbstractListModel]	@0x2e9a2b18	QAbstractListModel
    	[d]	@0x2e9a32f0	QAbstractItemModelPrivate
    	[parent]	"listDriveInfo"	QListWidget
    	[children]	<0 items>	
    	[properties]	<at least 0 items>	
    	[methods]	<0 items>	
    	[extra]		
    	cachedIndexes	<0 items>	QModelIndexList
    	items	<1 items>	QList<QListWidgetItem*>
    	staticMetaObject	@0x17425334	QMetaObject
    

    Any idea why it may crash at this point?


    Update (not a solution), an extension only

    from the signal emitted emit dataChanged(idx, idx, roles); in the function (mentioned above) QListModel::itemChanged(), it reaches this line (shown below) via this signal-slot connection, but I have absolutely no idea how to trace it further, nor what ever this q refers to.

    void QListWidgetPrivate::_q_emitItemChanged(const QModelIndex &index)
    {
        Q_Q(QListWidget);
        emit q->itemChanged(listModel()->at(index.row()));
    }
    

    q is shown here to connect the signals & slots.

    Stack Trace here

    1  QListWidgetPrivate::_q_emitItemChanged qlistwidget.cpp            1198 0x171948ac 
    2  QListWidget::qt_static_metacall        moc_qlistwidget.cpp        196  0x17198264 
    3  QMetaObject::activate                  qobject.cpp                3809 0x6bb282a7 
    4  QMetaObject::activate                  qobject.cpp                3660 0x6bb2851b 
    5  QAbstractItemModel::dataChanged        moc_qabstractitemmodel.cpp 557  0x6bac9e3f 
    6  QListModel::itemChanged                qlistwidget.cpp            455  0x17194eff 
    7  QListWidgetItem::setData               qlistwidget.cpp            745  0x17195c28 
    8  QListWidgetItem::setText               qlistwidget.h              179  0x4b2a7e   
    9  MainWindow::updateDrivesListWidget     MainWindow.cpp             1074 0x44d953   
    10 MainWindow::updateDrivesList           MainWindow.cpp             1390 0x45015b   
    11 MainWindow::connectDriveListChanges    MainWindow.cpp             933  0x44c83d   
    12 MainWindow::connectSettings            MainWindow.cpp             466  0x448161   
    13 MainWindow::initGui                    MainWindow.cpp             57   0x444b4c   
    14 MainWindow::MainWindow                 MainWindow.cpp             17   0x44449f   
    15 qMain                                  main.cpp                   230  0x466faf   
    16 WinMain *16                            qtmain_win.cpp             97   0x48df70   
    17 main                                                                   0x4e0bfd   
    

    Debugger Output here:

    Locals		
    	index	@0x56af450	QModelIndex &
    		c	0	int
    		i	783486936	quintptr
    		m	@0x2e9e3280	QListModel
    			[QAbstractListModel]	@0x2e9e3280	QAbstractListModel
    			[d]	@0x2e9e3a58	QAbstractItemModelPrivate
    			[parent]	"listDriveInfo"	QListWidget
    			[children]	<0 items>	
    			[properties]	<at least 0 items>	
    			[methods]	<0 items>	
    			[extra]		
    			cachedIndexes	<0 items>	QModelIndexList
    			items	<1 items>	QList<QListWidgetItem*>
    			staticMetaObject	@0x17305334	QMetaObject
    		r	0	int
    Inspector		
    Expressions		
    Return Value		
    Tooltip		
    	q	<not accessible>
    


  • I suspect the problem is to something connecting to that signal.

    Try not passing ui->listDriveInfo to the item constructor (this prevents the signal being sent when you change the data)



  • @VRonin

    Doing a few (rather simple) tests, I found the following (which confirms your suspicion)

    Works: (but no check box) - this is expected to work

    // create item
              QListWidgetItem* item = new QListWidgetItem(name, ui->listDriveInfo);
    
    //          item->setText(name);
    //          item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
    //          item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
              // add item to list
              ui->listDriveInfo->addItem(item);
    

    this crashes on setFlags() call

              // create item
              QListWidgetItem* item = new QListWidgetItem(name, ui->listDriveInfo);
    
    //          item->setText(name);
              //set checkable and state
              Qt::ItemFlags localFlags = item->flags();
              item->setFlags(localFlags | Qt::ItemIsUserCheckable);
              item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
    
              // add item to list
              ui->listDriveInfo->addItem(item);
    

    but these 2 both work (without setting owning QListWidget)

          // create item
          QListWidgetItem* item = new QListWidgetItem(name);
    
    //          item->setText(name);
          //set checkable and state
          Qt::ItemFlags localFlags = item->flags();
          item->setFlags(localFlags | Qt::ItemIsUserCheckable);
          item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
    
          // add item to list
          ui->listDriveInfo->addItem(item);
    

    and

          // create item
          QListWidgetItem* item = new QListWidgetItem();
    
    //         item->setText(name);
          //set checkable and state
          Qt::ItemFlags localFlags = item->flags();
          item->setFlags(localFlags | Qt::ItemIsUserCheckable);
          item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
    
          // add item to list
          ui->listDriveInfo->addItem(item);
    

    Testing:

    I create a new application, did exactly the same (add a string and a checkbox) and that work 100%. Create a form, throw on a
    QListWidget and run it with this code.

         QListWidgetItem* item = new QListWidgetItem("New", ui->listWidget);
         item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
         item->setCheckState(Qt::Unchecked);
         QListWidgetItem* item1 = new QListWidgetItem("New 1", ui->listWidget);
         item1->setFlags(item->flags() | Qt::ItemIsUserCheckable);
         item1->setCheckState(Qt::Unchecked);
         QListWidgetItem* item2 = new QListWidgetItem("New 2", ui->listWidget);
         item2->setFlags(item->flags() | Qt::ItemIsUserCheckable);
         item2->setCheckState(Qt::Unchecked);
    
         ui->listWidget->addItem(item);
         ui->listWidget->addItem(item1);
         ui->listWidget->addItem(item2);
    
         connect(ui->listWidget, &QListWidget::itemClicked, this, [this](QListWidgetItem * i) {
              // Get drive info from driveList
              int pos = ui->listWidget->row(i);
    
              // check state & set state
              bool active = i->checkState() == Qt::Checked;
              qDebug() << (active ? "enabled" : "disabled");
         });
    

    So my question is, bug (on whose side) or some setting on my side? Thoughts on what to look for?