Как добавить меню правой кнопки мыши в каждую ячейку QTableView в PyQt

Я хочу добавить меню правой кнопки мыши, чтобы удалить, переименовать или открыть изображение в каждой ячейке QTAbleView в меню жесткого щелчка, я попытался и обнаружил, что каждый пытается добавить меню в заголовок в виде таблицы, я попробовал ниже но это, кажется, не работает в коде ниже..

class GalleryUi(QtGui.QTableView):
    """ Class contains the methods that forms the
        UI of Image galery
    """
    def __init__(self, imagesPathLst=None, parent=None):
        super(GalleryUi, self).__init__(parent)
        self.__sw = QtGui.QDesktopWidget().screenGeometry(self).width()
        self.__sh = QtGui.QDesktopWidget().screenGeometry(self).height()
        self.__animRate = 1200
        self._imagesPathLst = imagesPathLst
        self._thumb_width = 200
        self._thumb_height = self._thumb_width + 20
        self.setUpWindow(initiate=True)

        self._startControlBar()

        self._connections()

    def contextMenuEvent(self, event):

        index = self.indexAt(event.pos())
        menu = QtGui.QMenu()
        renameAction = QtGui.QAction('Exit', self)
        renameAction.triggered.connect(self.close)
        self.menu.addAction(renameAction)
        self.menu.popup(QtGui.QCursor.pos())

    def closeEvent(self,event):
        # in case gallery is launched by Slideshow this is not needed
        if hasattr(self, 'bar'):
            self.bar.close()

    def _startControlBar(self):
        if not self._slideShowWin:
            self.bar = controlBar.ControlBar()
            self.bar.show()
            self.bar.exitBtn.clicked.connect(self.close)
            self.bar.openBtn.clicked.connect(self.selectSetNewPath)


    def _connections(self):
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.connect(self, QtCore.SIGNAL(self.customContextMenuRequested(QtCore.QPoint)), self, QtCore.SLOT(displayMenu(QtCore.QPoint)))

    def displayMenu(self, pos):
        self.menu = QtGui.QMenu()
        self.menu.addAction(self.close)
        self.menu.exec_(self.mapToGlobal(event.pos()))

    def selectSetNewPath(self):

        path = utils._browseDir("Select the directory that contains images")
        self._imagesPathLst = utils.ingestData(path)
        # sets model when new folder is choosen
        self.updateModel()

    def setUpWindow(self, initiate=False):
        """ Method to setup window frameless and fullscreen,
            setting up thumbnaul size and animation rate
        """

        if not self._imagesPathLst:
            self.selectSetNewPath()
        # sets model once at startup when window is being drawn!
        if initiate:
            self.updateModel()
        self.setGeometry(0, 0, self.__sw, self.__sh)
        self.setColumnWidth(self._thumb_width, self._thumb_height)
        self.setShowGrid(False)
        self.setWordWrap(True)
        self.show()

        self.resizeColumnsToContents()
        self.resizeRowsToContents()
        self.selectionModel().selectionChanged.connect(self.selChanged)

    def updateModel(self):
        col = self.__sw/self._thumb_width 
        self._twoDLst = utils.convertToTwoDList(self._imagesPathLst, col)
        lm = MyListModel(self._twoDLst, col,
            (self._thumb_width, self._thumb_height), self)
        self.setModel(lm)



    def keyPressEvent(self, keyevent):
        """ Capture key to exit, next image, previous image,
            on Escape , Key Right and key left respectively.
        """
        event = keyevent.key()
        if event == QtCore.Qt.Key_Escape:
            self._exitGallery()



def main(imgLst=None):
    """ method to start gallery standalone
    """
    app = QtGui.QApplication(sys.argv)
    window =  GalleryUi(imgLst)
    window.raise_()
    sys.exit(app.exec_())

if __name__ == '__main__':
    current_path = os.getcwd()
    if len(sys.argv) > 1:
        current_path = sys.argv[1:]
    main(utils.ingestData(current_path))

Ответ 1

QTableView имеет событие contextMenuEvent(), чтобы отобразить контекстное меню:

  • Создайте QMenu внутри этого события
  • Добавьте несколько QAction в QMenu
  • подключите каждый QAction к слотам с помощью сигнала triggered QAction
  • вызов popup(QCursor.pos()) на QMenu

Когда пользователь щелкнет правой кнопкой мыши таблицу, ячейка под указателем мыши будет выбрана, и в то же время появится меню. Когда пользователь выбирает действие в меню, будет вызываться подключенный слот, получить выбранную ячейку таблицы в этом слоте и выполнить требуемое действие в этой ячейке.

...
def contextMenuEvent(self, event):
    self.menu = QtGui.QMenu(self)
    renameAction = QtGui.QAction('Rename', self)
    renameAction.triggered.connect(lambda: self.renameSlot(event))
    self.menu.addAction(renameAction)
    # add other required actions
    self.menu.popup(QtGui.QCursor.pos())
    ...

def renameSlot(self, event):
    print "renaming slot called"
    # get the selected row and column
    row = self.tableWidget.rowAt(event.pos().y())
    col = self.tableWidget.columnAt(event.pos().x())
    # get the selected cell
    cell = self.tableWidget.item(row, col)
    # get the text inside selected cell (if any)
    cellText = cell.text()
    # get the widget inside selected cell (if any)
    widget = self.tableWidget.cellWidget(row, col)
...

Ответ 2

Наконец я реализовал его!

def contextMenuEvent(self, pos):
    if self.selectionModel().selection().indexes():
        for i in self.selectionModel().selection().indexes():
            row, column = i.row(), i.column()
        menu = QtGui.QMenu()
        openAction = menu.addAction("Open")
        deleAction = menu.addAction("Delete")
        renaAction = menu.addAction("Rename")
        action = menu.exec_(self.mapToGlobal(pos))
        if action ==openAction:
            self.openAction(row, column)

def openAction(self, row, column):
    if self._slideShowWin:
        self._slideShowWin.showImageByPath(self._twoDLst[row][column])
        self._animateUpOpen()

def deleteSelected(self):
    # TODO
    pass

который работает как шарм!!!