I want to simulate QDockWidget/QToolBar behavior for custom widget, unpin widget with mousePressEvent
from one location and pin it to another location. Like place upper frame to 'sub' location:
I'm able to unpin it with the following code:
class DraggableSpectralFrame(SpectralFrame):
def __init__(self, parent=None):
super().__init__(parent)
self.setMouseTracking(True)
self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint)
self.oldPos = QPointF(self.pos())
self.local= QPointF(self.pos())
self.floating = False
def mousePressEvent(self, event):
self.oldPos = event.globalPos()
if self.hoverRect.contains(event.localPos()) and \
event.button() == Qt.LeftButton:
self.floating = True
self.local = event.localPos()
self.setParent(None)
self.show()
self.move((self.oldPos - self.local).toPoint())
def mouseMoveEvent(self, event):
self.oldPos = event.globalPos()
if self.floating:
self.move((self.oldPos - self.local).toPoint())
The problem that I'm loosing pressed functionality after morphing DraggableSpectralFrame
into window and to move window in a proper way I have to click/press again. Without extra click window still reacts on cursors moves(due to self.floating
being True
) but easily looses focus on sharp movements.
May be there is an easier way to implement that idea, if that is the case - please let me know!
One way to implement dragging and dropping is to use a QDrag
object to display the widget while dragging. For the widget that should accept the dragged widget you need to set acceptDrops
to True and reimplement at the very least dragEnterEvent
and dropEvent
. Here is a very simple example how this can be done. In this example the "Move me" label can be dragged back and forth between the two windows.
from PyQt5 import QtWidgets, QtCore, QtGui
class DropFrame(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.vlayout = QtWidgets.QVBoxLayout(self)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if isinstance(event.source(), DraggableLabel):
event.accept()
def dropEvent(self, event):
event.accept()
widget = event.source()
if widget:
self.vlayout.addWidget(widget)
class DraggableLabel(QtWidgets.QLabel):
def __init__(self, text, parent=None):
super().__init__(text, parent)
self.setFrameShape(self.Box)
def mousePressEvent(self, event):
self.drag = QtGui.QDrag(self)
self.mime_data = QtCore.QMimeData()
self.drag.setMimeData(self.mime_data)
# capture image of self to use as pixmap while dragging
self.pixmap = self.grab()
self.drag.setPixmap(self.pixmap)
self.hide()
self.drag.exec(QtCore.Qt.MoveAction)
self.show()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget1 = DropFrame()
label = DraggableLabel('Move me')
widget1.layout().addWidget(label)
widget1.show()
widget2 = DropFrame()
widget2.show()
widget2.move(widget1.pos().x(),widget1.pos().y()+150)
app.exec()