Прилипание виджета к курсору во время перетаскивания. Drag and drop. PyQt5
В приведённой ниже программе осуществлена возможность перетаскивания кнопок между виджетами.
Хотелось бы узнать, возможно ли сделать так, чтобы кнопка или её изображение прилипало к курсору во время перетаскивания?
from PyQt5 import QtCore, QtGui, QtWidgets
class MyButton(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def mouseMoveEvent(self, e):
mimeData = QtCore.QMimeData()
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
#print(f'class MyButton(QPushButton):{e.pos()} - {self.rect().topLeft()}')
dropAction = drag.exec_(QtCore.Qt.MoveAction)
class MyFrame(QtWidgets.QFrame):
def __init__(self, parent):
super(MyFrame, self).__init__(parent)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
position = e.pos()
e.source().setParent(self)
e.source().move(position)
e.source().show()
e.setDropAction(QtCore.Qt.MoveAction)
e.accept()
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1051, 800)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalFrame = MyFrame(Dialog)
self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
self.horizontalFrame.setObjectName("horizontalFrame")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.pushButton_3 = MyButton(self.horizontalFrame)
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout_6.addWidget(self.pushButton_3)
self.pushButton_2 = MyButton(self.horizontalFrame)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout_6.addWidget(self.pushButton_2)
self.pushButton = MyButton(self.horizontalFrame)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout_6.addWidget(self.pushButton)
self.verticalLayout.addWidget(self.horizontalFrame)
self.horizontalFrame_2 = MyFrame(Dialog)
self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
self.horizontalFrame_2.setObjectName("horizontalFrame_2")
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.verticalLayout.addWidget(self.horizontalFrame_2)
self.horizontalFrame_3 = MyFrame(Dialog)
self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
self.horizontalFrame_3.setObjectName("horizontalFrame_3")
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.verticalLayout.addWidget(self.horizontalFrame_3)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton_3.setText(_translate("Dialog", "PushButton 3"))
self.pushButton_2.setText(_translate("Dialog", "PushButton 2"))
self.pushButton.setText(_translate("Dialog", "PushButton"))
# -----------------------------> vvvvvvv, vvvvvvvvv # <----------------
class PlayGroundWidget(QtWidgets.QDialog, Ui_Dialog):
def __init__(self):
super(PlayGroundWidget, self).__init__()
self.setupUi(self)
self.horizontalFrame.setAcceptDrops(True)
self.horizontalFrame_2.setAcceptDrops(True)
self.horizontalFrame_3.setAcceptDrops(True)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = PlayGroundWidget()
w.show()
sys.exit(app.exec_())
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Я немного изменил ваш класс MyButton() и еще одну строку, проверьте.
from PyQt5 import QtCore, QtGui, QtWidgets
'''
class MyButton(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def mouseMoveEvent(self, e):
mimeData = QtCore.QMimeData()
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
#print(f'class MyButton(QPushButton):{e.pos()} - {self.rect().topLeft()}')
dropAction = drag.exec_(QtCore.Qt.MoveAction)
'''
class MyButton(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super(MyButton, self).__init__(*args, **kwargs)
self._pos = QtCore.QPoint()
def mouseMoveEvent(self, event):
if event.buttons() != QtCore.Qt.LeftButton:
super(MyButton, self).mouseMoveEvent(event)
return
btn_img = self.grab()
painter = QtGui.QPainter(btn_img)
painter.setCompositionMode(painter.CompositionMode_DestinationIn)
painter.fillRect(btn_img.rect(), QtGui.QColor(0, 0, 0, 150))
painter.end()
data = QtCore.QMimeData()
drag = QtGui.QDrag(self)
drag.setMimeData(data)
drag.setPixmap(btn_img)
drag.setHotSpot(event.pos())
self._pos = event.pos()
drag.exec_(QtCore.Qt.CopyAction)
super(MyButton, self).mouseMoveEvent(event)
class MyFrame(QtWidgets.QFrame):
def __init__(self, parent):
super(MyFrame, self).__init__(parent)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
position = e.pos()
e.source().setParent(self)
# e.source().move(position)
e.source().move(position - e.source()._pos) # +++ e.source()._pos
e.source().show()
e.setDropAction(QtCore.Qt.MoveAction)
e.accept()
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1051, 800)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalFrame = MyFrame(Dialog)
self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
self.horizontalFrame.setObjectName("horizontalFrame")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.pushButton_3 = MyButton(self.horizontalFrame)
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout_6.addWidget(self.pushButton_3)
self.pushButton_2 = MyButton(self.horizontalFrame)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout_6.addWidget(self.pushButton_2)
self.pushButton = MyButton(self.horizontalFrame)
self.pushButton.setIcon(QtGui.QIcon("Ok.png")) # +++
self.pushButton.setIconSize(QtCore.QSize(50, 50)) # +++
self.pushButton.setObjectName("pushButton")
self.horizontalLayout_6.addWidget(self.pushButton)
self.verticalLayout.addWidget(self.horizontalFrame)
self.horizontalFrame_2 = MyFrame(Dialog)
self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
self.horizontalFrame_2.setObjectName("horizontalFrame_2")
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.verticalLayout.addWidget(self.horizontalFrame_2)
self.horizontalFrame_3 = MyFrame(Dialog)
self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
self.horizontalFrame_3.setObjectName("horizontalFrame_3")
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.verticalLayout.addWidget(self.horizontalFrame_3)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton_3.setText(_translate("Dialog", "PushButton 3"))
self.pushButton_2.setText(_translate("Dialog", "PushButton 2"))
self.pushButton.setText(_translate("Dialog", "PushButton"))
class PlayGroundWidget(QtWidgets.QDialog, Ui_Dialog):
def __init__(self):
super(PlayGroundWidget, self).__init__()
self.setupUi(self)
self.horizontalFrame.setAcceptDrops(True)
self.horizontalFrame_2.setAcceptDrops(True)
self.horizontalFrame_3.setAcceptDrops(True)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setFont(QtGui.QFont("Times", 12, QtGui.QFont.Bold))
w = PlayGroundWidget()
w.show()
sys.exit(app.exec_())
