Programmatically select multiple rows in Qtableview

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 (Display tables in PyQt5, QTableView with conditional formatting, numpy and 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: GitHub - 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:

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)

This is the closest thing I can find in Stack Exchange:

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) –

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.

1 Like

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

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.