Qt modelview: views

From wikinotes

TODO:

rewrite this documentation, with special handling of traps in various view types (tree, table, list, signals, etc)

TODO:

using tmacoreLogin's model/view as a model, document a minimal, but full example of signal handling for a view - one that covers all of the common traps.

Keeping Headers with Empty Items

TODO:

somewhere in TMA codebase I came up with a good auto-adjusting solution. Also see QTBUG-36665

  • see appsettingsmodel

Views lose their header names/sizing if a model, or rootIndex is set without at least an empty QStandardItem for each column.


NOTE:

You can quickly create, then immediately delete a model item, and it seems to preserve your header settings

Add Delegates to Views

TODO:

  • problems styling delegates/workarounds
  • parenting issue

Add Widgets to Views

TODO:

  • mention is anti-pattern
  • workflow

Handling DoubleClick

TODO:

doubleclick registers lmb, or rmb -- also be careful that doubleclick was registered on same item, clearing selection

Adding ContextMenu to Views

class MyTableView(QtWidgets.QTableView):
    def __init__(self):
        super(MyTableView, self).__init__()
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self._handle_customContextMenuRequested)

    def _handle_customContextMenuRequested(self, local_pos):
        menu = QtWidgets.QMenu()  # your custom menu
        global_pos = self.mapToGlobal(local_pos)
        menu.popup(global_pos)

QActions

TODO:

how to use

DataWidgetMapper (widget represents row)

DataWidgetMappers are good at setting up a widget to represent one particular row in your data. Ex: more info about a particular user.


WARNING:

this may not work, I was unable to reproduce quickly in production

with QApplication():

    stylesheetdir = StyleSheet().stylesheetdir()

    # Create Model
    model = QtGui.QStandardItemModel()

    item_a = QtGui.QStandardItem('a')
    item_b = QtGui.QStandardItem('b')
    item_c = QtGui.QStandardItem('c')

    model.setItem( 0, 0, item_a )
    model.setItem( 1, 0, item_b )
    model.setItem( 2, 0, item_c )

    # Create widget
    text = QtWidgets.QLineEdit()

    # Create Mapper & map model to widget
    mapper = QtGui.QDataWidgetMapper()
    mapper.setModel( model )
    mapper.addMapping( text, 0 )        # sets column to observe


    # toFirst, toNext, toLast
    # used to set the current ROW displayed by the widget
    text.show()
    mapper.toFirst() # 'a'
    mapper.toNext()  # 'b'
    mapper.setCurrentModelIndex( item_c.index() ) # 'c'
    mapper.toNext()  # no items left, remains at 'c'

QAbstractItemView

Implementing your own custom views.

ftp://ftp.informatik.hu-berlin.de/pub/Linux/Qt/QT/videos/DevDays2011/TrainingDay/DevDays2011_-_Advanced_Qt_-_A_Deep_Dive.pdf excellent overview information about advanced Qt topics

Widgets

QTreeView

TODO:

adding a contextmenu to treeview

# expanding items
class YourModel(QtGui.QStandardItemModel):
    def load_modelindex_children(self, modelindex):
        child_data = your_getter()
        if not len(child_data):
            # create empty row so shows as expandable
        self.append_child_data(child_data)


# column widths/stretch
header = tree.header()
header.setStretchLastSection(False)  # VERY IMPORTANT, overrides setSectionResizeMode when set

header.setSectionResizeMode(0, header.Stretch)
tree.setColumnWidth(1, 200)
tree.setColumnHidden(0, True)

Troubleshooting

Model Data Mysteriously gets Deleted

I have a hunch this is often caused by connecting things to the model.dataChanged signal.

This signal is needed by the view. If you are also using it to inspect the view, you may have a race condition.

I think that wrapping model.update() to emit a different signal after it has been updated may make programs more stable.

NOTE:

My best results have come from overriding QAbstractItemView.dataChanged(), then emitting my own data_changed signal (guaranteed not to be handled by qt). This guarantees that the view has received an update from the model already.