如何让QTableView的拖拽选择行为与QTreeView一致?
让QTableView实现QTreeView式的空白区域拖拽多选
QTableView与QTreeView在鼠标拖拽多选时存在行为差异:QTreeView允许从视图的空白区域(无项目的区域)开始拖拽,划过项目即可选中它们;但QTableView默认不支持此操作,必须从某个项目上开始拖拽才能触发多选。
以下示例可直观展示二者差异:
from PyQt6.QtCore import QAbstractTableModel, Qt from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QTableView, QTreeView class TModel(QAbstractTableModel): def __init__(self): super().__init__() self.d = [[1, 2], [3, 4], [5, 6]] def columnCount(self, parent=None): return 2 def rowCount(self, parent=None): return len(self.d) def data(self, index, role=1): if role == Qt.ItemDataRole.DisplayRole: return self.d[index.row()][index.column()] return None class Window(QWidget): def __init__(self): super().__init__() view1 = QTreeView() view2 = QTableView() for v in (view1, view2): v.setSelectionMode(v.SelectionMode.ExtendedSelection) model = TModel() view1.setModel(model) view2.setModel(model) lay = QVBoxLayout(self) lay.addWidget(view1) lay.addWidget(view2) app = QApplication([]) win = Window() win.show() app.exec()
解决方案
要让QTableView支持空白区域拖拽多选,只需子类化QTableView并重写mousePressEvent方法,在点击空白区域时手动启动拖拽选择逻辑:
from PyQt6.QtCore import QAbstractTableModel, Qt, QPoint from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QTableView, QTreeView, QAbstractItemView class TModel(QAbstractTableModel): def __init__(self): super().__init__() self.d = [[1, 2], [3, 4], [5, 6]] def columnCount(self, parent=None): return 2 def rowCount(self, parent=None): return len(self.d) def data(self, index, role=1): if role == Qt.ItemDataRole.DisplayRole: return self.d[index.row()][index.column()] return None class CustomTableView(QTableView): def mousePressEvent(self, event): # 获取点击位置对应的索引 index = self.indexAt(event.pos()) if not index.isValid(): # 点击空白区域,启动拖拽选择 self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.startDragSelection(event.pos()) else: # 点击项目,执行默认逻辑 super().mousePressEvent(event) class Window(QWidget): def __init__(self): super().__init__() view1 = QTreeView() view2 = CustomTableView() for v in (view1, view2): v.setSelectionMode(v.SelectionMode.ExtendedSelection) model = TModel() view1.setModel(model) view2.setModel(model) lay = QVBoxLayout(self) lay.addWidget(view1) lay.addWidget(view2) app = QApplication([]) win = Window() win.show() app.exec()
原理说明
- QTreeView内部在空白区域点击时,会自动调用
startDragSelection初始化选择框;而QTableView默认仅在点击有效索引时才触发选择逻辑。 - 子类化后,我们判断点击位置是否对应有效索引,若无效(空白区域),则手动调用
startDragSelection,从而实现和QTreeView一致的拖拽多选行为。
内容的提问来源于stack exchange,提问作者mahkitah
相关产品推荐
相关产品推荐

