【问题标题】:Dropped customised QWidget item disappears in the QListWidget after internal drag/drop Pyside PyQt内部拖放Pyside PyQt后,丢弃的自定义QWidget项目在QListWidget中消失
【发布时间】:2021-11-26 17:33:35
【问题描述】:

我采用了可用的代码 Drag'N'Drop custom widget items between QListWidgets 与 PySide6 一起工作,经过一些修改后,我设法运行了代码并且它可以正常工作。

但是此代码存在一个错误或缺陷。 如果 QListWidget 中的一个项目拖放到同一个 QListWidget 中的另一个项目上 object 项目开始相互消失或相互堆叠或有时显示为空白项目。 如下所示

我不确定导致问题的已实现代码有什么问题或缺失。

此外,我想在拖放时禁用复制,如果用户在内部拖放时按住 CTRL 按钮,则 Flash 符号将更改为 对 + 符号的更改并将项目添加到列表中。

这个功能应该被禁用,如果不是,我不知道该怎么做 可以在删除时禁用复制功能我想知道是否有任何可用的解决方法,因为在任何一个 QWidgetList 对象 [listWidgetA 和 listWidgetB] 中不应存在超过一个项目,两个列表中都不允许有任何项目的重复.

总结一下,我想解决以下问题。

  1. 在同一列表中拖放项目时项目消失或堆叠的缺陷或问题。

  2. 在拖放时按住 CTRL 键时禁用复制项目的可能性或建议解决方法以防止将项目复制到同一列表或其他列表中。

下面我附上了错误代码。

from PySide6 import QtGui, QtCore, QtWidgets
import sys, os, pathlib


class ThumbListWidget(QtWidgets.QListWidget):
    def __init__(self, type, parent=None):
        super(ThumbListWidget, self).__init__(parent)
        self.setIconSize(QtCore.QSize(124, 124))
        self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.setDefaultDropAction(QtCore.Qt.MoveAction)
        self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
        self.setAcceptDrops(True)
        self.model().rowsInserted.connect(
            self.handleRowsInserted, QtCore.Qt.QueuedConnection)

    def handleRowsInserted(self, parent, first, last):
        print(f"first:{first} last:{last} parent:{parent}")
        for index in range(first, last + 1):
            item = self.item(index)
            if item is not None and self.itemWidget(item) is None:
                index, name, icon = item.data(QtCore.Qt.UserRole)
                widget = QCustomQWidget()
                widget.setTextUp(index)
                widget.setTextDown(name)
                widget.setIcon(icon)
                item.setSizeHint(widget.sizeHint())
                self.setItemWidget(item, widget)


class Dialog_01(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.listItems = {}

        myQWidget = QtWidgets.QWidget()
        myBoxLayout = QtWidgets.QHBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.myQListWidget = ThumbListWidget(self)

        myBoxLayout.addWidget(self.myQListWidget)

        images_files_dir = pathlib.Path(__file__).parent.absolute().joinpath("custom_qlistwidget")
        for data in [
            ('No.1', 'Meyoko', pathlib.Path(images_files_dir).joinpath('among-us-small-green.png')),
            ('No.2', 'Nyaruko', pathlib.Path(images_files_dir).joinpath('among-us-small-yellow.png')),
            ('No.3', 'Louise', pathlib.Path(images_files_dir).joinpath('among-us-small-red.png'))]:
            myQListWidgetItem = QtWidgets.QListWidgetItem(self.myQListWidget)
            # store the data needed to create/re-create the custom widget
            myQListWidgetItem.setData(QtCore.Qt.UserRole, data)
            self.myQListWidget.addItem(myQListWidgetItem)

        self.listWidgetB = ThumbListWidget(self)
        myBoxLayout.addWidget(self.listWidgetB)


class QCustomQWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        # super(QCustomQWidget, self).__init__(parent)
        super().__init__(parent)
        self.textQVBoxLayout = QtWidgets.QVBoxLayout()
        self.textUpQLabel = QtWidgets.QLabel()
        self.textDownQLabel = QtWidgets.QLabel()
        self.textQVBoxLayout.addWidget(self.textUpQLabel)
        self.textQVBoxLayout.addWidget(self.textDownQLabel)
        self.allQHBoxLayout = QtWidgets.QHBoxLayout()
        self.iconQLabel = QtWidgets.QLabel()
        self.allQHBoxLayout.addWidget(self.iconQLabel, 0)
        self.allQHBoxLayout.addLayout(self.textQVBoxLayout, 1)
        self.setLayout(self.allQHBoxLayout)
        # setStyleSheet
        self.textUpQLabel.setStyleSheet('''
            color: rgb(0, 0, 255);
        ''')
        self.textDownQLabel.setStyleSheet('''
            color: rgb(255, 0, 0);
        ''')

    def setTextUp(self, text):
        self.textUpQLabel.setText(text)

    def setTextDown(self, text):
        self.textDownQLabel.setText(text)

    def setIcon(self, imagePath):
        self.iconQLabel.setPixmap(QtGui.QPixmap(imagePath))


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(480, 320)
    app.exec() 

【问题讨论】:

    标签: python drag-and-drop pyside qlistwidget pyside6


    【解决方案1】:

    使用DragDrop 标志自动允许复制内部项目的可能性,因为这是由 Ctrl 修饰符启用的,您只需要在 dragMoveEventdropEvent 中检查它,并最终忽略它:

    class ThumbListWidget(QtWidgets.QListWidget):
        # ...
        def dragMoveEvent(self, event):
            if event.keyboardModifiers():
                event.ignore()
            else:
                super().dragMoveEvent(event)
    
        def dropEvent(self, event):
            if event.keyboardModifiers():
                event.ignore()
            else:
                super().dropEvent(event)
    

    关于另一点,我能够重现“空”单元格问题,但只是随机的。这可能是由列表小部件的几何形状和项目小部件之间的交互引起的错误(特别是考虑到有一个带有像素图的 QLabel 可能会导致一些布局和抛光问题),但实际上很难找到真正的原因,因此,几乎不可能找到合适的解决方案或解决方法。
    如果您能够找到一致地重现该问题的方法,我建议您相应地更新您的问题(但请注意,这并不意味着 我们 也可以重现它)。

    考虑到虽然在许多简单情况下使用项目小部件似乎是合理的,但更好的解决方案是使用自定义委托并覆盖其paint 函数来绘制内容。

    【讨论】:

    • 谢谢,您能否详细说明如何在自定义小部件的委托中覆盖绘制方法,以实现 textUP、textDown 或 Icon 中的哪个项目!?
    • @新浪。对不起,但这将是这个问题的主题。我建议您对该主题进行一些研究,因为该主题有数十篇文章。
    猜你喜欢
    • 2011-10-15
    • 2017-05-26
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多