自定义QListWidget控件和拖放事件

实现效果:

import sys
import time

from PyQt5.Qt import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import *


# 自定义的item 继承自QListWidgetItem  为了在每一项里面装多个控件(或者说把每一项变为一个widget)
class customQListWidgetItem(QListWidgetItem):
    """
    https://blog.csdn.net/Strengthennn/article/details/103747819
    QT的:https://blog.csdn.net/HES_C/article/details/127429982
    """

    def __init__(self, name, img):
        super().__init__()
        # 自定义item中的widget 用来显示自定义的内容 相当于个容器
        self.widget = QWidget()
        self.name = name  # 把widget里面的每个控件所需要的参数放进实例属性里面 下面拖拽功能里需要用
        self.img_path = img

        # 用来显示name
        self.nameLabel = QLabel()
        self.nameLabel.setText(self.name)

        # 用来显示avator(图像)
        self.avatorLabel = QLabel()
        # 设置图像源 和 图像大小
        self.avatorLabel.setPixmap(QPixmap(self.img_path).scaled(50, 50))
        self.avatorLabel.setScaledContents(True)  # 自适应大小

        # 设置布局用来对nameLabel和avatorLabel进行布局
        self.hbox = QHBoxLayout()
        self.hbox.addWidget(self.avatorLabel)
        self.hbox.addWidget(self.nameLabel)
        self.hbox.addStretch(1)  # 添加 空白伸缩 为了让标签靠左
        # 设置widget的布局
        self.widget.setLayout(self.hbox)
        # 设置自定义的QListWidgetItem的sizeHint,不然无法显示
        self.setSizeHint(self.widget.sizeHint())


# 自定义QListWidget类 QListWidget 为了可以拖动Item
class MyListWidget(QListWidget):
    """
    https://qa.1r1g.com/sf/ask/1835951981/ 重写类
    https://blog.csdn.net/kenfan1647/article/details/119277723 模式选择
    https://blog.csdn.net/mokemg/article/details/105286527 模式选择
    https://www.thinbug.com/q/30291628  模式选择
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)  # 调用父类

        self.setSelectionMode(QAbstractItemView.ExtendedSelection)  # 设置选择模式 这个可以按住control多选
        # 默认为同时支持拖和放 这个很重要,搜了很多都是 InternalMove 但是会导致拖动一个的时候出现混乱 下面会有判断如果选择多项的时候就改成这个InternalMove
        self.setDragDropMode(QAbstractItemView.DragDrop)

        # 以下都不用设置 默认就是的 https://blog.csdn.net/kenfan1647/article/details/119277723
        # self.setDragEnabled(True)  # 允许托动 默认就是True
        # self.setAcceptDrops(True)  # 允许放下 默认就是True
        # self.setDragDropOverwriteMode(False) # 保存视图的拖放行为
        # self.setDropIndicatorShown(True)  # https://zhidao.baidu.com/question/2079442716339294708.html
        # self.setAcceptDrops(True)  # 设置接收释放
        # self.setSelectionBehavior(QAbstractItemView.SelectRows)  # 选择行或者列等
        # self.setDefaultDropAction(Qt.TargetMoveAction) # 默认使用的放置操作。

    # 重写释放时间
    def dropEvent(self, event):
        if event.source() == self:  # 只接受自己的拖放
            # 所有被选择的Item的行 集合
            rows = set([mi.row() for mi in self.selectedIndexes()])
            # 释放时 事件的鼠标位置所在的索引 的行
            targetRow = self.indexAt(event.pos()).row()
            # 防止释放所在的行也被误选择了 所以移除目标行  应该也可以用row.remove(targetRow)
            rows.discard(targetRow)
            rows = sorted(rows)  # 排序
            # 如果没有选择行或者说 自己拖放到自己身上那么忽略事件
            if not rows:
                event.ignore()
                return
            # 如果拖动到超出QListWidget范围了 那么放在最后
            if targetRow == -1:
                targetRow = self.count()

            # 这步骤很重要,是否会导致拖下去然后下面增加了 上面删除了它附近项 会改变原来的QListWidget
            # 如果拖动了一项 那么自己重写 如果选择了多项 那么重新赋值setDragDropMode为InternalMove就可以
            if len(rows) > 1:
                self.setDragDropMode(QAbstractItemView.InternalMove)
                super(MyListWidget, self).dropEvent(event)
                event.ignore()
                self.setDragDropMode(QAbstractItemView.DragDrop)  # 一定要改回去
                return

            row_n_item = self.item(rows[0])  # 获取拖动的Item
            # 重新创建自定义的QListWidget对象  因为测试直接 调用上面获取的拖动Item 会显示空白
            item = customQListWidgetItem(row_n_item.name, row_n_item.img_path)
            # 删除QListWidget中的Item
            # https://qa.1r1g.com/sf/ask/1668509321/
            # https://blog.51cto.com/xiaohaiwa/5380507
            self.takeItem(rows[0])  # 删除拖动行
            self.insertItem(targetRow, item)  # 在目标行位置 插入上面重新创建的ITem
            self.setItemWidget(item, item.widget)  # 设置插入的Item的widget

            event.accept()
            return


if __name__ == "__main__":
    app = QApplication(sys.argv)

    # 主窗口
    w = QWidget()
    w.setWindowTitle("QListWindow")
    w.resize(300, 600)


    # 创建自定义的QListWidget对象
    listWidget = MyListWidget()

    item1 = customQListWidgetItem("1", "res/Img/子弹.png")
    item2 = customQListWidgetItem("2", "res/Img/小程序.png")
    item3 = customQListWidgetItem("3", "res/Img/手机.png")
    item4 = customQListWidgetItem("4", "res/Img/搜一搜.png")
    item5 = customQListWidgetItem("5", "res/Img/搜索.png")

    # 在listWidget中加入5个自定义的item
    listWidget.addItem(item1)
    listWidget.setItemWidget(item1, item1.widget)
    listWidget.addItem(item2)
    listWidget.setItemWidget(item2, item2.widget)
    listWidget.addItem(item3)
    listWidget.setItemWidget(item3, item3.widget)
    listWidget.addItem(item4)
    listWidget.setItemWidget(item4, item4.widget)
    listWidget.addItem(item5)
    listWidget.setItemWidget(item5, item5.widget)

    # 设置垂直布局
    layout = QVBoxLayout()
    # 把自定义QListWidget添加到垂直布局
    layout.addWidget(listWidget)
    # 把布局添加到主QWidget上面
    w.setLayout(layout)

    # 绑定点击槽函数 点击显示对应item中的所在的行号
    listWidget.itemClicked.connect(lambda item: print(listWidget.row(item)))

    w.show()
    sys.exit(app.exec_())

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值