当前位置: 首页 > article >正文

PyQt 的Tree Widget中拖放和点击的异常行为

在 PyQt 的 QTreeWidget 中,如果你遇到 拖放点击 的异常行为,可能是由于信号处理、事件拦截、拖放设置或树结构配置等问题导致的。以下是一些可能的常见问题和解决方案。

在这里插入图片描述

1、问题背景

一个 PyQt 应用程序中包含两个 Tree Widget,当用户从一个 Tree Widget 拖动项目并将其释放到另一个 Tree Widget 时,程序运行良好。但是,如果用户将项目拖动并释放到相同的 Tree Widget(这是一种不希望的行为,因此我在代码中禁用了接受拖放操作),Tree Widget 会忽略用户接下来的鼠标点击事件。

当用户拖动一个项目并将其释放到相同的 Tree Widget 时,可以看到以下问题:

  1. 用户点击左侧 Tree Widget 中的任何项目,而不会发生任何变化。
  2. 用户再次点击相同或其他项目时,选择才会发生改变。
  3. 试图点击展开图标,无论用户点击多少次,都不会触发任何事件。

要重现此问题,请运行代码并执行以下步骤:

  1. 从左侧的树中拖动一个项目,并将其释放到相同的树中。
  2. 单击左侧树中的任何项目,您将注意到没有任何变化
  3. 再次单击相同或其他项目,选择就会更改。

2、解决方案

为了解决这个问题,我修改了 MyTreeWidgetmousePressEvent 方法,以确保在用户点击 Tree Widget 时鼠标按下位置被正确记录。之前,mousePressEvent 方法只在左键点击时记录鼠标按下位置,这导致了上述异常行为。现在,只要用户点击 Tree Widge,即使没有按下左键,鼠标按下位置都会被记录。

修改后的 mousePressEvent 方法如下:

class MyTreeWidget(QtGui.QTreeWidget):
    # ...

    def mousePressEvent(self, event):
        super(MyTreeWidget, self).mousePressEvent(event)
        self.mousePressPos = event.pos()

这样可以确保鼠标按下位置始终被正确记录,从而解决了上述异常行为。

完整的代码如下:

from PyQt4 import QtGui, QtCore
import cPickle

class MyTreeItem(QtGui.QTreeWidgetItem):
    def __init__(self, parent=None):
        super(MyTreeItem, self).__init__(parent)
        self.setFlags(QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDropEnabled)


    def getPath(self):
        """
        Rebuild path from the tree.
        """
        if isinstance(self.parent(), MyTreeItem):
           path = '{0}/{1}'.format(self.parent().getPath() ,str(self.text(0)))
        #The top level item
        else:
           path = '/{0}'.format(str(self.text(0)))

        return path


    def getParents(self):
        """
        Get all the parents to the top level.
        """
        parents = []

        while self:
            self = self.parent()
            if isinstance(self, MyTreeItem):
                parents.append(self)

        return parents


    def getChildren(self):
        """
        Get all the children(flatten).
        """
        children = []
        if not self:
            return children

        childrenCount = self.childCount()

        if childrenCount == 0:
            return children

        for idx in range(childrenCount):
            citem = self.child(idx)
            if citem:
                children.append(citem)
                children.extend(citem.getChildren())

        return children

class MyTreeWidget(QtGui.QTreeWidget):
    def __init__(self, parent = None):
        super(MyTreeWidget, self).__init__(parent)
        self.setDragEnabled(True)
        self.setAcceptDrops(True)
        self.setHeaderLabels(["Select Members"])
        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.mousePressPos = QtCore.QPoint(0,0)


    def mousePressEvent(self, event):
        super(MyTreeWidget, self).mousePressEvent(event)
        self.mousePressPos = event.pos()


    def mouseMoveEvent(self, event):
        super(MyTreeWidget, self).mouseMoveEvent(event)

        self.setAcceptDrops(False)
        drag = QtGui.QDrag(self)
        mime_data = QtCore.QMimeData()
        passme = []
        for sel in self.selectedItems():
            dnddict = {}
            dnddict['disp'] = sel.getPath()
            dnddict['val'] = sel.getPath()

            passme.append(dnddict)

        bstream = cPickle.dumps(passme)
        mime_data.setData("application/x-ltreedata", bstream)
        drag.setMimeData(mime_data)
        self.setAcceptDrops(True)
        action = drag.exec_()


    def mouseReleaseEven(self, event):
        self.setAcceptDrop(True)
        event.accept()


    def dragMoveEvent(self, event):
        if event.mimeData().hasFormat("application/x-ltreedata"):
            event.accept()
        else:
            event.ignore()


    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat("application/x-ltreedata"):
            event.accept()
        else:
            event.ignore()


    def dropEvent(self, event):
        if event.source() == self:
            event.ignore()
        else:
            for item in event.source().selectedItems():
                print item.text(0)

    def addItems(self, itemList):
        """
        Take a list of path-like strings
        """
        for item in itemList:
            self.addItem(item)


    def addItem(self, item):
        """
        Convert each item to a tree item
        """
        joints = item.strip('/').split('/')

        joint = None
        while joints:
            joint = self.addTreeJoint(joints.pop(0), joint)


    def addTreeJoint(self, jointName, parent=None):
        """
        Add item to the tree widget
        """
        returnItem = None
        #If it the top of the tree
        if not parent:
            #Find existing item
            for item in self.findItems(QtCore.QString(jointName),QtCore.Qt.MatchExactly):
                if jointName == item.text(0):

                    return item
            #Create new top level item
            returnItem = MyTreeItem(self)
            returnItem.setText(0, jointName)

        #We search all the children of this tree level and figure out if
        #we need to create a new tree item.
        else:
            for idx in range(parent.childCount()):
                if parent.childCount() == 0:
                    break
                if jointName == parent.child(idx).text(0):
                    return parent.child(idx)

            #Create new item
            returnItem = MyTreeItem(parent)
            returnItem.setText(0, jointName)

        return returnItem


class GeometrySelector(QtGui.QWidget):
    accepted = QtCore.pyqtSignal(list)
    def __init__(self, parent = None):
        super(GeometrySelector, self).__init__(parent)


        self.treeWidget = MyTreeWidget(self)
        self.treeWidget.addItems(get_objs())

        button = QtGui.QPushButton('Add Members', self)
        button.setFocusPolicy(QtCore.Qt.NoFocus)
        button.clicked.connect(self.cb_accept)

        filterLabel = QtGui.QLabel(self)
        filterLabel.setText('Filter:')
        filterField = QtGui.QLineEdit(self)
        filterField.textChanged.connect(self.filterChanged)


        filterBox = QtGui.QHBoxLayout()
        filterBox.addWidget(filterLabel)
        filterBox.addWidget(filterField)

        mainLayout = QtGui.QGridLayout()
        mainLayout.addWidget(self.treeWidget,0,0)
        mainLayout.addLayout(filterBox,1,0)
        mainLayout.addWidget(button,2,0)
        self.setLayout(mainLayout)

        pal = self.palette()
        pal.setColor(QtGui.QPalette.Base, QtGui.QColor(80, 80, 80))
        pal.setColor(QtGui.QPalette.Text, QtGui.QColor(230, 230, 230))
        self.setPalette(pal)
        button.setPalette(pal)
        self.treeWidget.setPalette(pal)


    def filterChanged(self, filterStr):
        showedItem = []

        matchFlag = QtCore.Qt.MatchFlags(QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive | QtCore.Qt.MatchRegExp)
        allItems = self.treeWidget.findItems(QtCore.

过这些调整,通常可以解决 PyQt QTreeWidget 中的拖放和点击行为异常问题。


http://www.kler.cn/news/342867.html

相关文章:

  • 【LeetCode】动态规划—673. 最长递增子序列的个数(附完整Python/C++代码)
  • 014 属性分组
  • 牛客SQL29详解 计算用户的平均次日留存率
  • MySQL数据库表分区
  • DBO-BP回归预测 | MATLAB实现DBO-BP蜣螂优化算法优化神经网络多输入单输出回归预测
  • 20241011给荣品RD-RK3588-AHD开发板刷荣品预编译的Buildroot之后打开AP6275P的BT【命令行】
  • 单通道 LVDS 差分线路接收器MS21112S
  • 10.10 工作笔记
  • go 的 timer reset
  • 报错笔记
  • 基于模型的强化学习方法4大类灌水范式
  • 分布式常见面试题总结
  • 视频如何转换mp4模式?格式转换软件带你高清无损一秒转换
  • 猫头虎分享:Python库 Django 的简介、安装、用法详解入门教程
  • CANoe_调用C#控件的方法_DEMO方法演示
  • R知识图谱1—tidyverse玩转数据处理120题
  • 在 Linux 上使用 GPG 加解密文件
  • html渲染优先级
  • MySQL(B站CodeWithMosh)——2024.10.4(7)
  • Vue组件库Element-ui