Get the index of a QTableWidget row knowing its el

2019-08-15 14:05发布

问题:

[I'm using PyQt4, but I think this Qt4 issue is not Python specific.]

I have a QTableWidget. In each row, the first column holds a button. When clicked, the row is removed.

To remove the row, I use removeRow(int row) method, which takes as argument the index of the row. When connecting the signal, I can't know the index of the row because it might change in the meantime (for instance if the first row is removed, all row indexes are changed).

The accepted answer here suggests to pass the callback an instance of a QTableWidgetItem in the line, then get the row number from this item at deletion time.

This would be nice, except none of the elements of the row is a QTableWidgetItem. The elements are the button itself and a few ComboBoxes.

I can't figure out a way around this.

Can I somehow fit one of my elements into a QTableWidgetItem? Should I add a QTableWidgetItem in some sort of hidden column?

Our current implementation uses indexAt(QtGui.qApp.focusWidget()) (see other answer to question mentioned above), which looks like a sorry workaround to me.

If I replace the button with a checkable QTableWidgetItem like this

rm_item = QtGui.QTableWidgetItem()
rm_item.setFlags(QtCore.Qt.ItemIsUserCheckable |
                 QtCore.Qt.ItemIsEnabled)

I have a QTableWidgetItem I can use to get back to the row index. But I don't know how to catch a "checked" or "clicked" event from it like I do with the button. All I found is the itemClicked signal of QTableWidget, but then I'd have to filter all the other widgets out.

There has to be something obvious I'm missing.

Edit

From what I read here, I could add both a QTableWidgetItem with setItem and a Button widget with setCellWidget to the same cell. This doesn't seem so natural to me, but apparently it works (can't test right now).

I guess I'll do that. Add the Button, plus a dummy QTableWidgetItem on the same cell to pass as a reference to the row.

Is this how it is meant to be?

Edit 2

Or maybe QTableWidget is not the proper Widget and I should be using a Layout, as suggested here.

回答1:

It seems that using a layout rather than a table is possibly the most "correct" answer, but that may come with it's own difficulties, as seen in my answer to this question:

  • How to delete widgets from gridLayout

If you want to continue using a table, a somewhat cleaner solution than adding dummy items would be to use a persistent model index:

            button = QtGui.QPushButton(text, self.table)
            self.table.setCellWidget(row, column, button)
            index = QtCore.QPersistentModelIndex(
                self.table.model().index(row, column))
            button.clicked.connect(
                lambda *args, index=index: self.handleButton(index))

    def handleButton(self, index):
        print('button clicked:', index.row())
        if index.isValid():
            self.table.removeRow(index.row())


回答2:

If I understand your question correctly:

def set_button(self, row, col):
    # create a push button 
    btn = QtGui.QPushButton('Remove row')
    # connect to action
    btn.clicked.connect(self.remove_row)
    # set in cell 
    self.setCellWidget(row, col, btn)


def remove_row(self):
    # find what is clicked 
    clicked = QtGui.qApp.focusWidget()
    # position 
    idx = self.indexAt(clicked.pos())
    # remove this row
    self.removeRow(idx.row())