PyQt/QListWidget/DragDrop.py

193 lines
6.7 KiB
Python
Raw Normal View History

2018-09-14 16:42:45 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2018年9月14日
@author: Irony
2018-12-28 23:09:46 +08:00
@site: https://pyqt5.com , https://github.com/892768447
2018-09-14 16:42:45 +08:00
@email: 892768447@qq.com
@file: DragListWidget
@description:
"""
from PyQt5.QtCore import Qt, QSize, QRect, QPoint
from PyQt5.QtGui import QColor, QPixmap, QDrag, QPainter, QCursor
from PyQt5.QtWidgets import QListWidget, QListWidgetItem, QLabel, QRubberBand
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = "Copyright (c) 2018 Irony"
__Version__ = "Version 1.0"
class DropListWidget(QListWidget):
# 可以拖进来的QListWidget
def __init__(self, *args, **kwargs):
super(DropListWidget, self).__init__(*args, **kwargs)
self.resize(400, 400)
self.setAcceptDrops(True)
# 设置从左到右、自动换行、依次排列
self.setFlow(self.LeftToRight)
self.setWrapping(True)
self.setResizeMode(self.Adjust)
# item的间隔
self.setSpacing(5)
def makeItem(self, size, cname):
item = QListWidgetItem(self)
item.setData(Qt.UserRole + 1, cname) # 把颜色放进自定义的data里面
item.setSizeHint(size)
label = QLabel(self) # 自定义控件
label.setMargin(2) # 往内缩进2
label.resize(size)
pixmap = QPixmap(size.scaled(96, 96, Qt.IgnoreAspectRatio)) # 调整尺寸
pixmap.fill(QColor(cname))
label.setPixmap(pixmap)
self.setItemWidget(item, label)
def dragEnterEvent(self, event):
mimeData = event.mimeData()
if not mimeData.property('myItems'):
event.ignore()
else:
event.acceptProposedAction()
def dropEvent(self, event):
# 获取拖放的items
items = event.mimeData().property('myItems')
event.accept()
for item in items:
# 取出item里的data并生成item
self.makeItem(QSize(100, 100), item.data(Qt.UserRole + 1))
class DragListWidget(QListWidget):
# 可以往外拖的QListWidget
def __init__(self, *args, **kwargs):
super(DragListWidget, self).__init__(*args, **kwargs)
self.resize(400, 400)
# 隐藏横向滚动条
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# 不能编辑
self.setEditTriggers(self.NoEditTriggers)
# 开启拖功能
self.setDragEnabled(True)
# 只能往外拖
self.setDragDropMode(self.DragOnly)
# 忽略放
self.setDefaultDropAction(Qt.IgnoreAction)
# ****重要的一句作用是可以单选多选。Ctrl、Shift多选可从空白位置框选****
# ****不能用ExtendedSelection,因为它可以在选中item后继续框选会和拖拽冲突****
self.setSelectionMode(self.ContiguousSelection)
# 设置从左到右、自动换行、依次排列
self.setFlow(self.LeftToRight)
self.setWrapping(True)
self.setResizeMode(self.Adjust)
# item的间隔
self.setSpacing(5)
# 橡皮筋(用于框选效果)
self._rubberPos = None
self._rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.initItems()
# 实现拖拽的时候预览效果图
# 这里演示拼接所有的item截图(也可以自己写算法实现堆叠效果)
def startDrag(self, supportedActions):
items = self.selectedItems()
drag = QDrag(self)
mimeData = self.mimeData(items)
# 由于QMimeData只能设置image、urls、str、bytes等等不方便
# 这里添加一个额外的属性直接把item放进去,后面可以根据item取出数据
mimeData.setProperty('myItems', items)
drag.setMimeData(mimeData)
pixmap = QPixmap(self.viewport().visibleRegion().boundingRect().size())
pixmap.fill(Qt.transparent)
painter = QPainter()
painter.begin(pixmap)
for item in items:
rect = self.visualRect(self.indexFromItem(item))
painter.drawPixmap(rect, self.viewport().grab(rect))
painter.end()
drag.setPixmap(pixmap)
drag.setHotSpot(self.viewport().mapFromGlobal(QCursor.pos()))
drag.exec_(supportedActions)
def mousePressEvent(self, event):
# 列表框点击事件,用于设置框选工具的开始位置
super(DragListWidget, self).mousePressEvent(event)
if event.buttons() != Qt.LeftButton or self.itemAt(event.pos()):
return
self._rubberPos = event.pos()
self._rubberBand.setGeometry(QRect(self._rubberPos, QSize()))
self._rubberBand.show()
def mouseReleaseEvent(self, event):
# 列表框点击释放事件,用于隐藏框选工具
super(DragListWidget, self).mouseReleaseEvent(event)
self._rubberPos = None
self._rubberBand.hide()
def mouseMoveEvent(self, event):
# 列表框鼠标移动事件,用于设置框选工具的矩形范围
super(DragListWidget, self).mouseMoveEvent(event)
if self._rubberPos:
pos = event.pos()
lx, ly = self._rubberPos.x(), self._rubberPos.y()
rx, ry = pos.x(), pos.y()
size = QSize(abs(rx - lx), abs(ry - ly))
self._rubberBand.setGeometry(
QRect(QPoint(min(lx, rx), min(ly, ry)), size))
def makeItem(self, size, cname):
item = QListWidgetItem(self)
item.setData(Qt.UserRole + 1, cname) # 把颜色放进自定义的data里面
item.setSizeHint(size)
label = QLabel(self) # 自定义控件
label.setMargin(2) # 往内缩进2
label.resize(size)
pixmap = QPixmap(size.scaled(96, 96, Qt.IgnoreAspectRatio)) # 调整尺寸
pixmap.fill(QColor(cname))
label.setPixmap(pixmap)
self.setItemWidget(item, label)
def initItems(self):
size = QSize(100, 100)
for cname in QColor.colorNames():
self.makeItem(size, cname)
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
app.setStyleSheet("""QListWidget {
outline: 0px;
background-color: transparent;
}
QListWidget::item:selected {
border-radius: 2px;
border: 1px solid rgb(0, 170, 255);
}
QListWidget::item:selected:!active {
border-radius: 2px;
border: 1px solid transparent;
}
QListWidget::item:selected:active {
border-radius: 2px;
border: 1px solid rgb(0, 170, 255);
}
QListWidget::item:hover {
border-radius: 2px;
border: 1px solid rgb(0, 170, 255);
}"""
)
wa = DragListWidget()
wa.show()
wo = DropListWidget()
wo.show()
sys.exit(app.exec_())