python - 获取拖放目标pyqt5
问题描述
我正在使用 pyqt5 中的拖放 GUI 并试图获取拖放操作的目标小部件,但是当我尝试 QDrag 对象的 target() 函数时,我返回 < main .MainWindow object at 0x0000025FDAC09EE0> 并且我不知道怎么用。我想访问 QGridLayout 中小部件的索引,以便我可以使两个小部件交换位置。
这是我的代码:
import sys
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QPushButton, QWidget, QApplication, QGridLayout, QScrollArea, QMainWindow, QSlider
class Stroj:
def __init__(self, rok, naziv, trajanje):
self.rok = rok
self.naziv = naziv
self.trajanje = trajanje
class Button(QPushButton):
drag = 0
def __init__(self, title, parent):
super().__init__(title, parent)
def mouseMoveEvent(self, e):
if e.buttons() != Qt.LeftButton:
return
mimeData = QMimeData()
mimeData.setText(self.text())
self.drag = QDrag(self)
self.drag.setMimeData(mimeData)
self.drag.setPixmap(self.grab())
self.drag.setHotSpot(self.rect().center())
dropAction = self.drag.exec_(Qt.MoveAction)
class MainWindow(QMainWindow):
layout = QGridLayout()
btns = []
snd = ""
i = 0
j = 0
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setAcceptDrops(True)
self.scroll = QScrollArea()
self.widget = QWidget()
self.drag = QDrag(self)
SL = []
for x in range(30):
self.btns.append(x)
for x in range(30):
self.btns[x] = Button(str(x), self)
self.btns[x].setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
self.layout.addWidget(self.btns[x], self.i, self.j)
if(self.j > 5):
self.j = 0
self.i += 1
else:
self.j += 1
self.widget.setLayout(self.layout)
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.widget)
self.setCentralWidget(self.scroll)
self.setWindowTitle('Raspored')
self.setGeometry(350, 75, 950, 750)
def dragEnterEvent(self, e):
self.snd = e.mimeData().text()
e.accept()
def dragMoveEvent(self, e):
e.accept()
def dropEvent(self, e):
sender = self.snd
position = e.pos()
position.setX(int(position.x() - self.btns[int(sender)].width() / 2))
position.setY(int(position.y() - self.btns[int(sender)].height() / 2))
self.btns[int(sender)].move(position)
print(self.layout.indexOf(e.source()))
print(e.source().drag.target())
e.setDropAction(Qt.MoveAction)
e.accept()
def main():
app = QApplication(sys.argv)
main = MainWindow()
main.show()
app.exec_()
if __name__ == '__main__':
main()
解决方案
放置事件的目标始终是接收放置操作的小部件,因此很明显,如果您从主窗口实例拦截事件,您将获得主窗口作为目标。如果需要在特定位置查找小部件,则需要使用QApplication.widgetAt(pos)
.
Button
在以下示例中,根据给定代码进行了修改,仅当源是实例且目标不同时,我才接受 dragEnter/dragMove 事件。然后我使用它们在布局中的位置来切换这些按钮。
class MainWindow(QMainWindow):
# ...
def dragEnterEvent(self, e):
e.accept()
def dragMoveEvent(self, e):
source = e.source()
target = QApplication.widgetAt(self.mapToGlobal(e.pos()))
if (isinstance(e.source(), Button) and isinstance(target, Button) and target != source):
e.accept()
else:
e.ignore()
def dropEvent(self, e):
source = e.source()
target = QApplication.widgetAt(self.mapToGlobal(e.pos()))
if (not isinstance(source, Button) or not isinstance(target, Button)
or target == source):
return
layout = self.widget.layout()
sourceIndex = layout.indexOf(source)
sourcePos = layout.getItemPosition(sourceIndex)
targetIndex = layout.indexOf(target)
targetPos = layout.getItemPosition(targetIndex)
layout.addWidget(source, *targetPos)
layout.addWidget(target, *sourcePos)
e.accept()
考虑这是一个非常简单的实现:您还应该确保这些小部件实际上是同一个窗口的子窗口并且处于相同的布局中。
推荐阅读
- python - Pytorch - 如何沿轴索引具有不同大小的张量
- android - Jetpack compose:BottomSheet 状态更改回调
- swift - Swift 将约束扩展添加到具有关联类型的协议
- anylogic - 如何编写查询以在 AnyLogic 中获取不相等?
- python - 是什么让多武装老虎机问题与上下文相关,以及 TensorFlow 和 Stable Baseline 等框架如何实现这些
- mysql - 无效使用组函数从两个不同的表中获取字段总和
- android-jetpack-compose - Animation*asState - 合成后触发目标状态变化
- python - 当我通过 GUI 打开显示图形时,是否可以在图形中显示多光标?
- html - 尝试在边距中显示 HTML 元素时如何避免出现问题?
- java - OpenShift CreateContainerError - 错误:mkdir /../../ 不是目录