Issue
I want to drag and drop labels, which my code does, but while moving it the label disappears. How can I keep the label visible while I am dragging it? I am using QDrag to copy the contents over.
I want to be able to drag these labels into a box with many slots, and have the label lock into one of the slots when its dropped in the vicinity. Since the label becomes invisible when being dragged, it is hard to visualize where exactly it will be dropped when I let go of the mouse button.
from PySide import QtCore, QtGui
myMimeType = 'application/MyWindow'
class MyLabel(QtGui.QLabel):
def __init__(self, parent):
super(MyLabel, self).__init__(parent)
self.setStyleSheet("""
background-color: black;
color: white;
font: bold;
padding: 6px;
border-width: 2px;
border-style: solid;
border-radius: 16px;
border-color: white;
""")
def mousePressEvent(self, event):
itemData = QtCore.QByteArray()
dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.WriteOnly)
dataStream.writeString(self.text())
dataStream << QtCore.QPoint(event.pos() - self.rect().topLeft())
print dataStream
mimeData = QtCore.QMimeData()
mimeData.setData(myMimeType, itemData)
mimeData.setText(self.text())
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(event.pos() - self.rect().topRight())
self.hide()
if drag.exec_(QtCore.Qt.MoveAction | QtCore.Qt.CopyAction, QtCore.Qt.CopyAction) == QtCore.Qt.MoveAction:
self.close()
else:
self.show()
class MyFrame(QtGui.QFrame):
def __init__(self, parent=None):
super(MyFrame, self).__init__(parent)
self.setStyleSheet("""
background-color: lightgray;
border-width: 2px;
border-style: solid;
border-color: black;
margin: 2px;
""")
y = 6
for labelNumber in range(6):
label = MyLabel(self)
label.setText("Label #{0}".format(labelNumber))
label.move(6, y)
label.show()
y += label.height() + 2
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat(myMimeType):
if event.source() in self.children():
event.setDropAction(QtCore.Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
def dropEvent(self, event):
if event.mimeData().hasFormat(myMimeType):
mime = event.mimeData()
itemData = mime.data(myMimeType)
dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.ReadOnly)
text = QtCore.QByteArray()
offset = QtCore.QPoint()
dataStream >> text >> offset
newLabel = MyLabel(self)
newLabel.setText(event.mimeData().text())
newLabel.move(event.pos() - offset)
newLabel.show()
if event.source() in self.children():
event.setDropAction(QtCore.Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
class MyWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.myFrame = MyFrame(self)
self.setCentralWidget(self.myFrame)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.resize(333, 333)
main.move(app.desktop().screen().rect().center() - main.rect().center())
main.show()
sys.exit(app.exec_())
Solution
You have to save the widget and set it in the QDrag:
from PySide import QtCore, QtGui
myMimeType = "application/MyWindow"
class MyLabel(QtGui.QLabel):
def __init__(self, parent):
super(MyLabel, self).__init__(parent)
self.setStyleSheet(
"""
background-color: black;
color: white;
font: bold;
padding: 6px;
border-width: 2px;
border-style: solid;
border-radius: 16px;
border-color: white;
"""
)
def mousePressEvent(self, event):
itemData = QtCore.QByteArray()
dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.WriteOnly)
dataStream.writeString(self.text())
dataStream << QtCore.QPoint(event.pos() - self.rect().topLeft())
mimeData = QtCore.QMimeData()
mimeData.setData(myMimeType, itemData)
mimeData.setText(self.text())
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(event.pos())
# pixmap = self.grab()
pixmap = QtGui.QPixmap(self.size())
self.render(pixmap)
drag.setPixmap(pixmap)
self.hide()
action = drag.exec_(
QtCore.Qt.MoveAction | QtCore.Qt.CopyAction, QtCore.Qt.CopyAction
)
if action == QtCore.Qt.MoveAction:
self.deleteLater()
else:
self.show()
class MyFrame(QtGui.QFrame):
def __init__(self, parent=None):
super(MyFrame, self).__init__(parent)
self.setStyleSheet(
"""
background-color: lightgray;
border-width: 2px;
border-style: solid;
border-color: black;
margin: 2px;
"""
)
y = 6
for labelNumber in range(6):
label = MyLabel(self)
label.setText("Label #{0}".format(labelNumber))
label.move(6, y)
label.show()
y += label.height() + 2
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat(myMimeType):
if event.source() in self.children():
event.acceptProposedAction()
def dropEvent(self, event):
if event.mimeData().hasFormat(myMimeType):
if (
event.source() in self.children()
and event.possibleActions() & QtCore.Qt.MoveAction
):
event.acceptProposedAction()
mime = event.mimeData()
itemData = mime.data(myMimeType)
dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.ReadOnly)
text = QtCore.QByteArray()
offset = QtCore.QPoint()
dataStream >> text >> offset
newLabel = MyLabel(self)
newLabel.setText(event.mimeData().text())
newLabel.move(event.pos() - offset)
newLabel.show()
event.setDropAction(QtCore.Qt.MoveAction)
else:
event.ignore()
class MyWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.myFrame = MyFrame()
self.setCentralWidget(self.myFrame)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName("MyWindow")
main = MyWindow()
main.resize(333, 333)
main.show()
sys.exit(app.exec_())
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.