Fre*_*tri 4 drag-and-drop pyqt qwidget qgridlayout pyqt5
我正在寻找一种方法来创建可以拖/放以重新排列顺序的图形网格。我的第一次尝试是使用 QDockWidgets,因为它们允许拖放,但是它们在很多其他方面受到限制。是否可以在 QGridLayout 中实现此功能?
现在我有一个带有 3x3 matplotlib 小部件的 QGridLayout。
这是所需布局结果的示例。
示例代码:
import sys
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import random
from PyQt5.QtWidgets import QGridLayout, QVBoxLayout, QHBoxLayout, QScrollArea, QWidget, QDialog, QApplication, QFrame
class IndicSelectWindow(QDialog):
def __init__(self, parent=None):
super(IndicSelectWindow, self).__init__(parent=parent)
self.resize(1000, 800)
self.layout = QtWidgets.QHBoxLayout(self)
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.layout.addWidget(self.scrollArea)
for i in range(3):
for j in range(3):
self.Frame = QFrame(self)
self.Frame.setStyleSheet("background-color: white;")
self.Frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.Frame.setLineWidth(2)
self.layout = QHBoxLayout(self.Frame)
self.figure = Figure() # a figure to plot on
self.canvas = FigureCanvas(self.figure)
self.ax = self.figure.add_subplot(111) # create an axis
data = [random.random() for i in range(10)]
self.ax.plot(data, '*-') # plot data
self.canvas.draw() # refresh canvas
self.layout.addWidget(self.canvas)
Box = QVBoxLayout()
Box.addWidget(self.Frame)
self.gridLayout.addLayout(Box, i, j)
self.gridLayout.setColumnStretch(i % 3, 1)
self.gridLayout.setRowStretch(j, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = IndicSelectWindow()
w.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
这是一个实现,它将交换拖/放中涉及的项目的位置。3个主要步骤是:
(1) 重新实现mousePressEvent获取LayoutItem基于鼠标坐标的索引。
(2) 重新实现mouseMoveEvent设置一个QDragFigureCanvas。
(3) 重新实现dropEvent以交换布局中的目标项目。
由于 matplotlib 小部件吸收鼠标事件,因此您还需要重新实现eventFilter以检测它们。
导入系统,随机
从 PyQt5.QtWidgets 导入 *
从 PyQt5.QtCore 导入 *
从 PyQt5.QtGui 导入 *
from matplotlib.figure 导入图
从 matplotlib.backends.backend_qt4agg 导入 FigureCanvasQTAgg 作为 FigureCanvas
类 IndicSelectWindow(QDialog):
def __init__(self, parent=None):
super(IndicSelectWindow, self).__init__(parent=parent)
self.resize(1000, 800)
self.target = 无
self.setAcceptDrops(True)
self.layout = QHBoxLayout(self)
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.layout.addWidget(self.scrollArea)
对于范围内的 i (3):
对于范围内的 j(3):
self.Frame = QFrame(self)
self.Frame.setStyleSheet("背景色:白色;")
self.Frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.Frame.setLineWidth(2)
self.layout = QHBoxLayout(self.Frame)
self.figure = Figure() # 要绘制的图形
self.canvas = FigureCanvas(self.figure)
self.ax = self.figure.add_subplot(111) # 创建一个轴
数据 = [random.random() for i in range(10)]
self.ax.plot(data, '*-') # 绘制数据
self.canvas.draw() # 刷新画布
self.canvas.installEventFilter(self)
self.layout.addWidget(self.canvas)
Box = QVBoxLayout()
Box.addWidget(self.Frame)
self.gridLayout.addLayout(Box, i, j)
self.gridLayout.setColumnStretch(i % 3, 1)
self.gridLayout.setRowStretch(j, 1)
def eventFilter(self, watched, event):
如果 event.type() == QEvent.MouseButtonPress:
self.mousePressEvent(事件)
elif event.type() == QEvent.MouseMove:
self.mouseMoveEvent(事件)
elif event.type() == QEvent.MouseButtonRelease:
self.mouseReleaseEvent(事件)
返回 super().eventFilter(watched, event)
def get_index(self, pos):
对于我在范围内(self.gridLayout.count()):
如果 self.gridLayout.itemAt(i).geometry().contains(pos) 和 i != self.target:
返回我
def mousePressEvent(self, event):
如果 event.button() == Qt.LeftButton:
self.target = self.get_index(event.windowPos().toPoint())
别的:
self.target = 无
def mouseMoveEvent(self, event):
如果 event.buttons() & Qt.LeftButton 和 self.target 不是 None:
拖动 = QDrag(self.gridLayout.itemAt(self.target))
pix = self.gridLayout.itemAt(self.target).itemAt(0).widget().grab()
mimedata = QMimeData()
mimedata.setImageData(pix)
drag.setMimeData(mimedata)
drag.setPixmap(pix)
drag.setHotSpot(event.pos())
拖动.exec_()
def mouseReleaseEvent(self, event):
self.target = 无
def dragEnterEvent(self, event):
如果 event.mimeData().hasImage():
事件.接受()
别的:
事件.忽略()
def dropEvent(self, event):
如果不是 event.source().geometry().contains(event.pos()):
source = self.get_index(event.pos())
如果来源是无:
返回
i, j = max(self.target, source), min(self.target, source)
p1, p2 = self.gridLayout.getItemPosition(i), self.gridLayout.getItemPosition(j)
self.gridLayout.addItem(self.gridLayout.takeAt(i), *p2)
self.gridLayout.addItem(self.gridLayout.takeAt(j), *p1)
如果 __name__ == '__main__':
app = QApplication(sys.argv)
w = IndicSelectWindow()
w.show()
sys.exit(app.exec_())