PySide6:如何通过上下箭头移动光标时选中表格行?按键事件未触发
问题解决:通过上下箭头键选中表格行
问题原因
你的keyPressEvent未触发,核心原因是当前焦点在QTableWidget控件上,而非主窗口。QTableWidget本身会处理上下箭头事件(仅移动单元格焦点),但不会自动选中整行,因此需要针对表格控件处理键盘事件。
解决方案1:自定义表格类重写键盘事件
创建继承自QTableWidget的自定义类,重写keyPressEvent方法,在上下箭头按下时选中对应行:
import sys from PySide6 import QtCore from PySide6.QtGui import QKeyEvent from PySide6.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QTableWidget, QVBoxLayout, QWidget from loguru import logger class CustomTableWidget(QTableWidget): def keyPressEvent(self, event: QKeyEvent) -> None: # 处理上下箭头逻辑 if event.key() in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down): # 先执行表格默认的焦点移动逻辑 super().keyPressEvent(event) # 获取当前焦点行并选中整行 current_row = self.currentRow() self.selectRow(current_row) logger.info(f"选中行:{current_row}") else: # 其他按键交给默认处理 super().keyPressEvent(event) class TableWindow(QMainWindow): def __init__(self, data, parent=None): super(TableWindow, self).__init__(parent) # 使用自定义表格控件 self.table_widget = CustomTableWidget() self.table_widget.cellClicked.connect(self.clicked) self.populate_cells(data) layout = QVBoxLayout() layout.addWidget(self.table_widget) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) # 初始化时给表格设置焦点,避免手动点击 self.table_widget.setFocus() def clicked(self, row, col): logger.info(f"{row}, {col}") self.table_widget.selectRow(row) def populate_cells(self, data): self.table_widget.setRowCount(len(data)) self.table_widget.setColumnCount(len(data[0])) for row in range(len(data)): for col in range(len(data[0])): value = data[row][col] self.table_widget.setItem(row, col, QTableWidgetItem(value)) if __name__ == "__main__": data_sample = [ ["customer1", "address1"], ["customer2", "address2"] ] app = QApplication(sys.argv) window = TableWindow(data_sample) window.show() sys.exit(app.exec())
解决方案2:给表格安装事件过滤器
如果不想自定义表格类,可在主窗口中给QTableWidget安装事件过滤器,拦截键盘事件:
import sys from PySide6 import QtCore from PySide6.QtGui import QKeyEvent from PySide6.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QTableWidget, QVBoxLayout, QWidget from loguru import logger class TableWindow(QMainWindow): def __init__(self, data, parent=None): super(TableWindow, self).__init__(parent) self.table_widget = QTableWidget() self.table_widget.cellClicked.connect(self.clicked) # 给表格安装事件过滤器 self.table_widget.installEventFilter(self) self.populate_cells(data) layout = QVBoxLayout() layout.addWidget(self.table_widget) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) # 初始化时给表格设置焦点 self.table_widget.setFocus() def eventFilter(self, obj, event): if obj == self.table_widget and event.type() == QtCore.QEvent.KeyPress: if event.key() in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down): # 执行表格默认的焦点移动逻辑 self.table_widget.keyPressEvent(event) # 选中当前焦点所在行 current_row = self.table_widget.currentRow() self.table_widget.selectRow(current_row) logger.info(f"选中行:{current_row}") return True # 非目标事件交给父类处理 return super().eventFilter(obj, event) def clicked(self, row, col): logger.info(f"{row}, {col}") self.table_widget.selectRow(row) def populate_cells(self, data): self.table_widget.setRowCount(len(data)) self.table_widget.setColumnCount(len(data[0])) for row in range(len(data)): for col in range(len(data[0])): value = data[row][col] self.table_widget.setItem(row, col, QTableWidgetItem(value)) if __name__ == "__main__": data_sample = [ ["customer1", "address1"], ["customer2", "address2"] ] app = QApplication(sys.argv) window = TableWindow(data_sample) window.show() sys.exit(app.exec())
额外说明
两种方案均保留了表格默认的上下箭头焦点移动逻辑,同时添加了整行选中的功能,和点击单元格时的行为完全一致。初始化时设置self.table_widget.setFocus()可避免用户手动点击表格获取焦点。
内容的提问来源于stack exchange,提问作者Ronin
相关产品推荐
相关产品推荐

