pythonpyqt5signals-slotsqtableviewqaction

PyQt5: Get row number from button-menu action in QTableView index-widget


Basically, I have a QTableView and the last column of each row contains a QMenu where if triggered, the row should be deleted. I tried the code below, but if I click on the menu that is in a row number > 1, the returned rowNum is -1:

Code:

def addrowIntable(self, a, b):
    Column1 = QStandardItem("%s" % (a))
    Column2 = QStandardItem("%s" % (b))

    actionBTN = QPushButton("")
    actionMenu = QMenu()

    self.RemList = QtWidgets.QAction("Remove row", actionMenu)
    actionMenu.addAction(self.RemList)

    actionMenu.raise_()
    actionBTN.setMenu(actionMenu)
    self.rulesWhitelistWidgetModel.appendRow([Column1, Column2])
    self.rulesWhiteListFileTBL.setIndexWidget(
        self.rulesWhitelistWidgetModel.index(self.rulesWhitelistWidgetModel.rowCount() - 1,
                                             self.rulesWhiteListFileTBL.model().columnCount() - 1), actionBTN)
    self.RemList.triggered.connect(lambda: self.deleteRow("Hello"))

def deleteRow(self, str):
    rowNum = self.rulesWhiteListFileTBL.rowAt(self.rulesWhiteListFileTBL.viewport().mapFromGlobal(self.sender().parent().pos()).y())
    print(self.rulesWhiteListFileTBL.indexAt(self.sender().parent().pos()).row())
    print(rowNum)

I just need to know which row number was the sender from inside deleteRow where I could then use model.removeRow() to delete it.


Solution

  • The main reason why your code doesn't work as expected is because you set the menu as the parent of the action. A menu is a popup window, so its position will be in global coordinates, whereas you want the position relative to the table. A simple way to achieve this is to make the button the parent of the action instead.

    The following revision of your code should do what you want:

    def addrowIntable(self, a, b):
        Column1 = QStandardItem("%s" % (a))
        Column2 = QStandardItem("%s" % (b))
        actionBTN = QPushButton()
        actionMenu = QMenu()
        actionRem = QtWidgets.QAction("Remove row", actionBTN)
        actionMenu.addAction(actionRem)
        actionBTN.setMenu(actionMenu)
        self.rulesWhitelistWidgetModel.appendRow([Column1, Column2])
        self.rulesWhiteListFileTBL.setIndexWidget(Column2.index(), actionBTN)
        actionRem.triggered.connect(lambda: self.deleteRow("Hello"))
    
    def deleteRow(self, str):
        pos = self.sender().parent().pos()
        index = self.rulesWhiteListFileTBL.indexAt(pos)
        self.rulesWhitelistWidgetModel.removeRow(index.row())