[Interest] Replacing QListWidget that uses cell widgets with QListView & model

Murphy, Sean Sean.Murphy at centauricorp.com
Fri Sep 3 19:09:55 CEST 2021

We've got an application we're working on where we'd like to replace a QListWidget that uses 
cell widgets, with a view/model/delegate and we're running into a snag. Here's what we have:

We have a "layerData" class with three member variables:
- bool visible
- QString name
- double opacity

We have a custom "layerControl" widget class that has three controls (QToolButton, QLineEdit, QSlider 
respectively) for displaying/setting those parameters. This widget has separate signals (bool, QString, 
double) which are emitted when their respective control is modified. 

Originally, we had a QListWidget where we'd call setCellWidget(new layerControl()) to populate 
the list with one our "layerControl" widgets per row. This worked well, but now we've realized that 
we want to display this same information in a couple different views (some of which are QTableViews, 
some are QListViews), so we're converting everything over to view/model/delegate so that we can 
just use a single shared model and changes that are made on any view are immediately reflected in the 
other views.

To convert over to the view/model/delegate way of doing things I've got this so far: 
- I've created a model (inherited from QAbstractItemModel) that takes a QVector<layerData> for 
  its underlying data, and in data() returns the bool parameter for column 0, the QString parameter 
  for column 1, and the double for column 2. 
- I set the same instance of this model on both a QTableView and a QListView
- I've created a delegate class, "layerWidgetDelegate",  that uses our "layerControl" widget as its editor
- on the QListView, I call setItemDelegateForColumn(0, new layerWidgetDelegate()), and then I loop 
  though all the rows of the view, calling openPersistentEditor(model->index(row, 0)) so the 
  "layerControl" widgets are always shown in the QListView
- in the delegate, I've connected the editor's 3 distinct signals (bool, QString, double) up to calling the 
  model's setData() function with the appropriate column (0, 1, 2 respectively)

This setup works fine when the user makes a change in the QListView. Using the "layerControl"  item 
delegate/editor to make a change on any of the three parameters, the change immediately ripples 
through the model and the table view is updated to match. But we're having trouble going the other 
way, but only for columns 1 & 2. If the user makes a change in the table view to something in column 0, 
that change propagates through the model, the delegate's setEditorData() is called with an index 
of (row, 0), and then the editor widget's QToolButton's state is updated to match the new value. But if 
the user makes a change in the table view to something in column 1, the model's underlying data is correctly
updated, it still emits the correct dataChanged() signal for the index (row, 1), but the item delegate's 
setEditorData() function is never called and therefor the QLineEdit is never updated. The same thing 
happens if the user makes a change in the table view to something in column 2 - the model's setData() is 
correctly called, the dataChanged() signal is correctly emitted, but the delegate's setEditorData() function 
is never called, and therefore the QSlider never gets updated.

Anyone have any tips for this? The basic problem with what I'm doing is that I'm trying to use a three 
column model in a single column widget (the QListView), but I STILL want all three columns of data to 
come through because I need to populate the delegate. It appears something in the QListView 
class prevents setEditorData() from being called when the index isn't in column 0.

The only hack I've found that works so far is in my model's setData() function, if the passed in index is for 
column 1 or 2, then I make sure to emit column 0 in the dataChanged() signal, which then forces the 
view to call the setEditorData() function, and then in there I update the editor widget with all three 
types of data since I don't really know which column changed at that point.

This was more long winded than I wanted, hopefully you can follow all of this!

More information about the Interest mailing list