pyqt5中drag事件

import sys
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QMainWindow, QVBoxLayout, QWidget, QApplication
from PyQt5.QtCore import QMimeData, Qt
from PyQt5.QtGui import QDrag, QPainter, QPixmap, QColor


class DragBaseLayout(QWidget):
    def __init__(self, parent=None):
        super(DragBaseLayout, self).__init__(parent)
        self.setAcceptDrops(True)  # 必须开启接受拖拽

        self.setLayoutType(QVBoxLayout)  # 设置布局类型并且设定好布局
        self.createComponent()  # 生成控件
        self.assembleComponent()  # 组装控件

    # 设定控件的layout类型
    def setLayoutType(self, Alayout):
        self.layout = Alayout()
        self.setLayout(self.layout)

    # 初始化内部的控件
    def createComponent(self):
        self.lb1 = QLabel()
        self.lb1.setPixmap(QPixmap("A.png"))
        self.lb2 = QLabel()
        self.lb2.setPixmap(QPixmap("../qss学习/B.png"))
        self.lb3 = QLabel()
        self.lb3.setPixmap(QPixmap("C.png"))
        self.line = LineLable(self)

    def assembleComponent(self):
        self.layout.addWidget(self.lb1)
        self.layout.addWidget(self.lb2)
        self.layout.addWidget(self.lb3)

    # 自定义插入控件的函数
    def addWidget(self, widget):
        self.layout.addWidget(widget)

    # 设定鼠标按下事件
    def mousePressEvent(self, event):
        item = self.childAt(event.pos())  # 通过位置获得控件
        if item == None: return  # 如果为空则直接跳过
        index = self.layout.indexOf(item)  # 获得当前控件所处的布局中的索引位置
        self.drag = QDrag(item)  # 创建QDrag对象
        mimedata = QMimeData()  # 然后必须要有mimeData对象,用于传递拖拽控件的原始index信息
        mimedata.setText(str(index))  # 携带索引位置信息
        self.drag.setMimeData(mimedata)
        pixmap = QPixmap(item.size())
        pixmap.fill(QColor(255, 255, 255, 0.5))  # 绘制为透明度为0.5的白板
        painter = QPainter(pixmap)
        painter.setOpacity(0.5)  # painter透明度为0.5
        painter.drawPixmap(item.rect(), item.grab())  # 这个很有用,自动绘制整个控件
        painter.end()
        self.drag.setPixmap(pixmap)
        self.drag.setHotSpot(event.pos() - item.pos())
        self.drag.exec_(Qt.MoveAction)  # 这个作为drag对象必须执行

    # 拖拽移动事件(通过实时监测鼠标的位置,并根据位置决定标志线是否显示)
    def dragMoveEvent(self, event):
        point = event.pos()
        currentItem = self.childAt(point)
        if type(currentItem) == QLabel:
            geometry = currentItem.geometry()
            if type(self.layout) == QHBoxLayout:
                self.Hline(point, geometry, currentItem)
            elif type(self.layout) == QVBoxLayout:
                self.Vline(point, geometry, currentItem)
        else:
            self.line.hide()

    # 拖拽放下事件
    def dropEvent(self, event):
        point = event.pos()  # 获得落点的坐标
        otherItem = self.childAt(point)  # 获得当前落点上的控件
        if type(otherItem) == QLabel:
            if type(self.layout) == QHBoxLayout:
                self.HInsert(point, otherItem)  # 改变指定控件的位置(适用于水平布局)
            elif type(self.layout) == QVBoxLayout:
                self.VInsert(point, otherItem)  # 改变指定控件的位置(适用于垂直布局)

    # 鼠标拖拽接受事件
    def dragEnterEvent(self, event):
        event.setDropAction(Qt.MoveAction)
        event.accept()

    # 判定模式(横向判断)
    def Hline(self, point, geometry, item):
        x = geometry.x()
        x2 = geometry.x() + geometry.width()
        y = geometry.y()
        if point.x() <= x + 15:  # 横向模式,鼠标处于控件左边
            self.line.resize(5, item.height())
            self.line.move(x, y)  # 将原本设定好的标示线(QLabel)移动到指定位置
            self.line.raise_()  # 设置为最顶层
            self.line.show()  # 显示
        elif x2 - 15 <= point.x():  # 横向模式,鼠标处于控件右边
            self.line.resize(5, item.height())
            self.line.move(x2 - 5, y)
            self.line.raise_()
            self.line.show()
        else:
            self.line.hide()

    # 判定模式(竖向判断)
    def Vline(self, point, geometry, item):
        y = geometry.y()
        y2 = geometry.y() + geometry.height()
        x = geometry.x()
        if point.y() <= y + 15:
            self.line.resize(item.width(), 5)
            self.line.move(x, y)
            self.line.raise_()
            self.line.show()
        elif y2 - 15 <= point.y():
            self.line.resize(item.width(), 5)
            self.line.move(x, y2 - 5)
            self.line.raise_()
            self.line.show()
        else:
            self.line.hide()

    # 插入模式(横向判断)
    def HInsert(self, point, otherItem):
        geometry = otherItem.geometry()
        x = geometry.x()
        x2 = geometry.x() + geometry.width()
        y = geometry.y()

        oldIndex = int(self.drag.mimeData().text())  # 获得原先存储在mimeData中的索引信息
        if oldIndex == self.layout.indexOf(otherItem): return  # 如果otherItem和oldItem实属同一个控件,则不做改变
        if point.x() <= x + 15:  # 插入在控件的左边
            oldItem = self.layout.takeAt(oldIndex).widget()
            index = self.layout.indexOf(otherItem)  # 重新获得当前控件所处的布局中的索引位置
            self.layout.insertWidget(index, oldItem)
        elif x2 - 15 <= point.x():  # 插入在控件的右边
            oldItem = self.layout.takeAt(oldIndex).widget()
            index = self.layout.indexOf(otherItem)  # 重新获得当前控件所处的布局中的索引位置
            self.layout.insertWidget(index + 1, oldItem)
        else:
            pass
        self.line.hide()

    # 插入模式(竖向判断)
    def VInsert(self, point, otherItem):
        geometry = otherItem.geometry()
        y = geometry.y()
        y2 = geometry.y() + geometry.height()
        x = geometry.x()

        oldIndex = int(self.drag.mimeData().text())  # 获得原先存储在mimeData中的索引信息
        if oldIndex == self.layout.indexOf(otherItem): return  # 如果otherItem和oldItem实属同一个控件,则不做改变
        if point.y() <= y + 15:  # 插入在控件的上边
            oldItem = self.layout.takeAt(oldIndex).widget()
            index = self.layout.indexOf(otherItem)  # 重新获得当前控件所处的布局中的索引位置
            self.layout.insertWidget(index, oldItem)
        elif y2 - 15 <= point.y():  # 插入在控件的下边
            oldItem = self.layout.takeAt(oldIndex).widget()
            index = self.layout.indexOf(otherItem)  # 重新获得当前控件所处的布局中的索引位置
            self.layout.insertWidget(index + 1, oldItem)
        else:
            pass
        self.line.hide()


# 指示条纹(实际是个QLabel)
class LineLable(QLabel):
    def __init__(self, parent=None):
        super(LineLable, self).__init__(parent)
        self.setStyleSheet("background-color:red;")
        self.hide()  # 一开始隐藏


class mainWidget(QMainWindow):
    def __init__(self, parent=None):
        super(mainWidget, self).__init__(parent)
        self.centerWidget = DragBaseLayout()
        self.setCentralWidget(self.centerWidget)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = mainWidget()
    win.show()
    sys.exit(app.exec_())

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值