Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the right table row index in pyQt5 contextMenuEvent

I need to get the table row index during a contextMenuEvent in pyQt5, but I keep getting odd row offsets. Since this is my first pyQt project, I'm quite lost. I have the following code.

def contextMenuEvent(self, event):

    menu = QMenu(self)
    openAction = menu.addAction('Open in browser')
    action = menu.exec_(event.globalPos())

    if action == openAction:
        row = self.tableWidget.rowAt(event.y())  # Should this be event.globalY? 
        self.so_something(row)

Edit: adding code sample. You can see that when the execution gets to the event produced when right-clicking on a row, the printed number is not the correct row number. Usually it has an offset, and last rows produce -1.

import sys
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QLabel, QLineEdit, QWidget, \
                            QPushButton, QVBoxLayout, QHBoxLayout, QComboBox, \
                            QTableWidget, QHeaderView, QTableWidgetItem, \
                            QMenu, QApplication


class MainWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # Window size and title
        self.setWindowTitle('Test')
        self.resize(700, 700)
        self.setMinimumWidth(700)

        # Label
        addressLabel = QLabel('Testing')
        addressLabel.setAlignment(Qt.AlignCenter)

        # Dropdown
        self.addressDropdown = QComboBox(self)
        self.addressDropdown.addItem('A')
        self.addressDropdown.addItem('B')

        # Refresh button
        refreshButton = QPushButton()
        refreshButton.setMaximumSize(40, 40)

        # Address layout
        addressayout = QHBoxLayout()
        addressayout.addWidget(addressLabel, 1)
        addressayout.addWidget(self.addressDropdown, 7)
        addressayout.addWidget(refreshButton)

        # Balance label
        balaceLabel = QLabel()
        balaceLabel.setText('Testing')
        balaceLabel.setAlignment(Qt.AlignCenter)

        # Balance amount label
        self.balaceAmountLabel = QLabel()
        self.balaceAmountLabel.setText('Testing')
        self.balaceAmountLabel.setAlignment(Qt.AlignCenter)

        # Balance layout
        balanceLayout = QVBoxLayout()
        balanceLayout.addWidget(balaceLabel)
        balanceLayout.addWidget(self.balaceAmountLabel)

        # Transactions label
        transactionsLabel = QLabel('Testing')
        transactionsLabel.setAlignment(Qt.AlignCenter)

        # Transactions table
        self.tableWidget = QTableWidget()
        self.tableWidget.setRowCount(10)
        self.tableWidget.setColumnCount(1)
        self.tableWidget.verticalHeader().setVisible(False)
        self.tableWidget.horizontalHeader().setVisible(False)
        self.tableWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        item = QTableWidgetItem('Testing')
        item.setTextAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
        self.tableWidget.setItem(0, 0, item)

        # Transactions layout
        transactionsLayout = QVBoxLayout()
        transactionsLayout.addWidget(transactionsLabel)
        transactionsLayout.addWidget(self.tableWidget)

        # Send label A
        sendLabelA = QLabel('Send')
        sendLabelA.setAlignment(Qt.AlignCenter)

        # Send amount
        self.sendAmount = QLineEdit()
        self.sendAmount.setAlignment(Qt.AlignCenter)

        # Send label B
        sendLabelB = QLabel('to')
        sendLabelB.setAlignment(Qt.AlignCenter)

        # Send address
        self.sendAddress = QLineEdit()
        self.sendAddress.setAlignment(Qt.AlignCenter)

        # Send button
        sendButton = QPushButton()
        sendButton.setMaximumSize(40, 40)
        sendIcon = QIcon.fromTheme("mail-send")
        sendButton.setIcon(sendIcon)
        sendButton.setIconSize(QSize(24,24))

        # Send layout
        sendLayout = QHBoxLayout()
        sendLayout.addWidget(sendLabelA)
        sendLayout.addWidget(self.sendAmount, 2)
        sendLayout.addWidget(sendLabelB)
        sendLayout.addWidget(self.sendAddress, 4)
        sendLayout.addWidget(sendButton)

        # Window layout
        layout = QVBoxLayout()
        layout.addLayout(addressayout)
        layout.addLayout(balanceLayout)
        layout.addLayout(transactionsLayout)
        layout.addLayout(sendLayout)
        self.setLayout(layout)

    def contextMenuEvent(self, event):
        menu = QMenu(self)
        openAction = menu.addAction('Open in browser')
        action = menu.exec_(event.globalPos())
        row = self.tableWidget.rowAt(event.y())

        if action == openAction:
            print(row)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()
like image 390
dvilela Avatar asked Dec 05 '25 19:12

dvilela


1 Answers

The coordinate that rowAt() method requires must be with respect to the viewport of the QTableWidget so you must convert the global position to local using mapFromGlobal() method:

def contextMenuEvent(self, event):
    gp = event.globalPos()
    menu = QMenu(self)
    openAction = menu.addAction("Open in browser")
    action = menu.exec_(gp)
    vp_pos = self.tableWidget.viewport().mapFromGlobal(gp)
    row = self.tableWidget.rowAt(vp_pos.y())

    if action == openAction:
        print(row)
like image 51
eyllanesc Avatar answered Dec 08 '25 09:12

eyllanesc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!