Programmatically select multiple rows in Qtableview

Heads up! You've already completed this tutorial.

Paul_Inkenbrandt | 2020-10-10 16:43:49 UTC | #1

I am creating an app with three different tableviews that are on three tabs. All three tables have a "join" field that could be used to connect them. I brought in the tables from pandas using the very useful tutorial on the subject (https://www.pythonguis.com/courses/model-views/qtableview-modelviews-numpy-pandas/). I want my script to automatically select rows in the other tables (based on the common field) if I select a row in the third table.

How would I programmatically select multiple rows given their indices? I want to select rows from one table automatically when I select rows from the other table.

Here is a link to my repository for those who are curious: https://github.com/inkenbrandt/wqxsde

Here is my best attempt to do what I am asking about, but it only appears to select one row in the other table, and not all the rows with a matching field:

python
def stationsel(self,s):
        self.stationselection = self.StationTableView.selectionModel()
        indexes = self.stationselection.selectedRows(column=2)
        df = self.ResultModel._data
        role = Qt.DisplayRole
        dg = df[df['monitoringlocationid'].isin([self.StationModel.data(i, role) for i in indexes])]
        print(dg)
        mode = QItemSelectionModel.Select | QtCore.QItemSelectionModel.Rows
        for i in dg.index:
            self.ResultTableView.selectRow(i)
        #for i in dg.index:
        #    self.ResultTableView.selectRow(i)

GUICapture|690x477

This is the closest thing I can find in Stack Exchange: https://stackoverflow.com/questions/9678138/how-to-select-next-row-in-qtableview-programmatically/9678278

Create GUI Applications with Python & Qt5 by Martin Fitzpatrick — (PyQt5 Edition) The hands-on guide to making apps with Python — Over 10,000 copies sold!

More info Get the book


martin | 2020-10-11 15:56:46 UTC | #2

Hey @Paul_Inkenbrandt I think you're very close here.

The .selectRow() method on the view is a convenience method for single selection. For selecting multiple rows it looks as though you need to do this via the view's selection model. You've already got the selection model in self.stationselection here, so it should be fairly straightforward.

QSelectionModel has two .select() methods -- one which takes individual QModelIndex objects (single selection) and another that accepts a QItemSelection.

A QItemSelection is basically a list of selection ranges, see QItemSelectionRange

You can either build QItemSelectionRange objects, or use the simpler method of passing a top left and bottom right QModelIndex to QItemSelection.select(topLeft, bottomRight). Each additional call adds a new selection.

If you have non-contiguous selection blocks, what I think you're looking for is something like the following (code untested) --

python
def stationsel(self,s):
    self.stationselection = self.StationTableView.selectionModel()
    indexes = self.stationselection.selectedRows(column=2)
    df = self.ResultModel._data
    role = Qt.DisplayRole
    dg = df[df['monitoringlocationid'].isin([self.StationModel.data(i, role) for i in indexes])]

    model = self.StationTableView.model() # get data model for indexes.
    selection = QItemSelection()

    for i in dg.index:
        # Get the model index for selection.
        # Column shouldn't matter for row-wise.
        model_index = model.index(i, 0)
        # Select single row.
        selection.select(model_index, model_index)  # top left, bottom right identical

    mode = QItemSelectionModel.Select | QtCore.QItemSelectionModel.Rows
    # Apply the selection, using the row-wise mode.
    self.stationselection.select(selection, mode)

If that doesn't do it let me know and I'll put together a complete example.


Paul_Inkenbrandt | 2020-10-11 16:04:07 UTC | #3

That worked! Thanks Martin! Here is my revised code.

python
def stationsel(self,s):
    self.stationselection = self.StationTableView.selectionModel()
    indexes = self.stationselection.selectedRows(column=2)
    df = self.ResultModel._data
    role = Qt.DisplayRole
    dg = df[df['monitoringlocationid'].isin([self.StationModel.data(i, role) for i in indexes])]
    print(dg)
    model = self.ResultTableView.model()  # get data model for indexes.
    selection = QItemSelection()
    for i in dg.index:
        self.ResultTableView.selectRow(i)
        model_index = model.index(i, 0)
        # Select single row.
        selection.select(model_index, model_index)  # top left, bottom right identical
    mode = QItemSelectionModel.Select | QtCore.QItemSelectionModel.Rows
    # Apply the selection, using the row-wise mode.
    self.resultselection = self.ResultTableView.selectionModel()
    self.resultselection.select(selection, mode)

By the way, thank you for providing these resources. I bought the book and access to the videos, and I love it. The best resource for pyqt5 that I can find.


PyQt/PySide 1:1 Coaching with Martin Fitzpatrick — Get one on one help with your Python GUI projects. Working together with you I'll identify issues and suggest fixes, from bugs and usability to architecture and maintainability.

More info 60 mins ($195)

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Programmatically select multiple rows in Qtableview was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt.