PySide2:QListWidget等控件用ExtendedSelection时禁用拖拽多选
彻底禁用PySide2 QListWidget/QTreeWidget/QTableWidget的拖拽多选(保留Ctrl/Shift多选)
要实现保留ExtendedSelection模式下的Ctrl/Shift键多选,同时完全禁用鼠标拖拽多选,重写mouseMoveEvent的方式存在边界漏洞(比如快速拖拽时仍会触发多选),更可靠的方案是直接重写selectionCommand方法——这个方法负责决定用户操作对应的选择行为,从根源上拦截拖拽多选的命令。
核心思路
QAbstractItemView.selectionCommand()会在每次选择操作前被调用,返回对应的选择命令类型。我们可以在此处判断:如果是鼠标拖拽操作且未按住Ctrl/Shift键,就返回QAbstractItemView.NoSelection(不执行任何选择),其他情况保留原有逻辑,这样既能保留标准的多选快捷键,又彻底阻止拖拽多选。
示例代码(以QListWidget为例)
import sys from PySide2.QtWidgets import QListWidget, QApplication, QAbstractItemView from PySide2.QtCore import Qt, QEvent NAMES = ["sparrow", "robin", "crow", "raven", "woodpecker", "hummingbird"] class CustomListWidget(QListWidget): def __init__(self): super().__init__() self.setSelectionMode(QAbstractItemView.ExtendedSelection) for name in NAMES: self.addItem(name) def selectionCommand(self, index, event=None): # 判断是否是鼠标拖拽且未按住Ctrl/Shift键 if event and event.type() == QEvent.MouseMove: modifiers = QApplication.keyboardModifiers() if modifiers not in (Qt.ControlModifier, Qt.ShiftModifier, Qt.ControlModifier | Qt.ShiftModifier): return QAbstractItemView.NoSelection # 其他情况保留原有选择逻辑 return super().selectionCommand(index, event) if __name__ == '__main__': app = QApplication(sys.argv) custom_list = CustomListWidget() custom_list.show() sys.exit(app.exec_())
适配QTreeWidget/QTableWidget
只需把上述代码中的CustomListWidget继承类改成QTreeWidget或QTableWidget即可,逻辑完全通用——因为这三个控件都继承自QAbstractItemView,selectionCommand是它们的共同方法。
效果验证
- 单选:点击任意条目,仅选中该条目
- Ctrl键多选:按住Ctrl点击条目,可加选/取消选中
- Shift键连续选:选中一个条目后,按住Shift点击另一个条目,选中两者之间的所有条目
- 鼠标拖拽:按住鼠标左键拖拽,不会选中任何额外条目
内容的提问来源于stack exchange,提问作者laurapons
相关产品推荐
相关产品推荐

