I have a table in my main GUI. I want to test my ability to delete items in the table using a menu that comes up upon right-clicking on an item. I'm using pytest-qt to conduct testing. Using qtbot.mouseClick seems to work well when clicking on widgets (such as pushbuttons), but when I try to pass it a table item it gives me a type error (due to the table item not being a widget). The line of code that's giving me the error is as follows:
qtbot.mouseClick(maingui.tablename.item(row, col), Qt.RightButton)
with the error:
TypeError: arguments did not match any overloaded call:
mouseClick(QWidget, Qt.MouseButton, modifier: Union[Qt.KeyboardModifiers, Qt.KeyboardModifier] = Qt.KeyboardModifiers(), pos: QPoint = QPoint(), delay: int = -1): argument 1 has unexpected type 'QTableWidgetItem'
Given the documentation, this error makes sense to me. My question is, is there a way that this can be done?
I don't think it should be relevant to the question, but the function that gets called by a right-click on a table item uses a QPoint decorator. My code reacts to right-clicks as follows:
@pyqtSlot(QPoint)
def on_tablename_customContextMenuRequested(self, point):
current_cell = self.tablename.itemAt(point)
if current_cell:
row = current_cell.row()
deleteAction = QAction('Delete item', self)
editAction = QAction('Edit item', self)
menu.addAction(deleteAction)
menu.addAction(editAction)
action = menu.exec_(self.tablename.mapToGlobal(point))
if action == deleteAction:
# <do delete stuff>
elif action == editAction:
# <do edit stuff>
Edit: I was able to select an item in the table using the suggestion of eyllanesc, but the right click on that item does not bring up the custom context menu. Here is a minimum reproducible example of my issue, using a two column table with a custom context menu. I need to be able to automatically select the "Delete Item" option during testing:
from time import sleep
import pytest
from PyQt5.QtCore import QPoint, Qt, QTimer, pyqtSlot
from PyQt5.QtWidgets import QMainWindow, QTableWidgetItem, QMenu, QAction, QAbstractItemView
from tests.test_ui_generated import ui_minimum_main
pytest.main(['-s'])
class TestTable(ui_minimum_main.Ui_minimum_table, QMainWindow):
def __init__(self, args):
QMainWindow.__init__(self)
self.setupUi(self)
self.table_minimum.setContextMenuPolicy(Qt.CustomContextMenu)
self.table_minimum.setColumnCount(2)
self.detectorHorizontalHeaderLabels = ['Col A', 'Col B']
self.table_minimum.setHorizontalHeaderLabels(self.detectorHorizontalHeaderLabels)
self.table_minimum.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.table_minimum.setSelectionBehavior(QAbstractItemView.SelectRows)
self.table_minimum.setRowCount(1)
self.table_minimum.setRowHeight(0, 22)
item = QTableWidgetItem('test_col_a')
item.setData(Qt.UserRole, 'test_col_a')
self.table_minimum.setItem(0, 0, item)
item = QTableWidgetItem('test_col_b')
item.setData(Qt.UserRole, 'test_col_b')
self.table_minimum.setItem(0, 1, item)
self.table_minimum.resizeRowsToContents()
@pyqtSlot(QPoint)
def on_table_minimum_customContextMenuRequested(self, point):
print('context_menu_requested')
current_cell = self.table_minimum.itemAt(point)
if current_cell:
deleteAction = QAction('Option A- Delete Row', self)
nothingAction = QAction('Option B- Nothing', self)
menu = QMenu(self.table_minimum)
menu.addAction(deleteAction)
menu.addAction(nothingAction)
action = self.menu.exec_(self.table_minimum.mapToGlobal(point))
if action == deleteAction:
self.table_minimum.setRowCount(0)
return
def test_detector_create_delete_gui(qtbot):
w = TestTable([])
qtbot.addWidget(w)
w.show()
qtbot.waitForWindowShown(w)
sleep(.5)
item = w.table_minimum.item(0, 0)
assert item is not None
def interact_with_menu():
# ???????
pass
rect = w.table_minimum.visualItemRect(item)
QTimer.singleShot(100, interact_with_menu)
qtbot.mouseClick(w.table_minimum.viewport(), Qt.RightButton, pos=rect.center())