You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 09:22:34