I am just curious if I can make a nested QRubberband
. (I or someone might find a use to it). I managed to edit the code from this answer to make a nested QRubberband
. It is all fine and working until I move the QRubberband
inside its parent QRubberband
. I was very confused as it moves wildly when I'm dragging it.
This is the sample code:
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class ResizableRubberBand(QRubberBand):
moving = False
def __init__(self, parent=None):
super(ResizableRubberBand, self).__init__(QRubberBand.Rectangle, parent)
self.setAttribute(Qt.WA_TransparentForMouseEvents, False)
self.draggable = True
self.dragging = False
self.is_dragging = False
self.dragging_threshold = 5
self.mousePressPos = None
self.borderRadius = 5
self.setWindowFlags(Qt.SubWindow)
layout = QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(
QSizeGrip(self), 0,
Qt.AlignLeft | Qt.AlignTop)
layout.addWidget(
QSizeGrip(self), 0,
Qt.AlignRight | Qt.AlignBottom)
self.show()
def resizeEvent(self, event):
self.clearMask()
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing)
qp.translate(.5, .5)
qp.drawRoundedRect(self.rect().adjusted(0, 0, -1, -1),
self.borderRadius, self.borderRadius)
def mousePressEvent(self, event):
if self.draggable and event.button() == Qt.RightButton:
self.mousePressPos = event.pos()
if event.button() == Qt.LeftButton:
self.first_mouse_location = (event.x(), event.y())
self.band = ResizableRubberBand(self)
self.band.setGeometry(event.x(), event.y(), 0, 0)
super(ResizableRubberBand, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.draggable and event.buttons() & Qt.RightButton:
diff = event.pos() - self.mousePressPos
if not self.dragging:
if diff.manhattanLength() > self.dragging_threshold:
self.dragging = True
if self.dragging:
geo = self.geometry()
parentRect = self.parent().rect()
geo.translate(diff)
if not parentRect.contains(geo):
if geo.right() > parentRect.right():
geo.moveRight(parentRect.right())
elif geo.x() < parentRect.x():
geo.moveLeft(parentRect.x())
if geo.bottom() > parentRect.bottom():
geo.moveBottom(parentRect.bottom())
elif geo.y() < parentRect.y():
geo.moveTop(parentRect.y())
self.move(geo.topLeft())
if event.buttons() & Qt.LeftButton:
first_mouse_location_x = self.first_mouse_location[0]
first_mouse_location_y = self.first_mouse_location[1]
new_x, new_y = event.x(), event.y()
difference_x = new_x - first_mouse_location_x
difference_y = new_y - first_mouse_location_y
self.band.resize(difference_x, difference_y)
super(ResizableRubberBand, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self.mousePressPos is not None:
if event.button() == Qt.RightButton and self.dragging:
event.ignore()
self.dragging = False
self.mousePressPos = None
super(ResizableRubberBand, self).mouseReleaseEvent(event)
class mQLabel(QLabel):
def __init__(self, parent=None):
QLabel.__init__(self, parent)
self.setContentsMargins(0,0,0,0)
self.setAlignment(Qt.AlignTop | Qt.AlignLeft)
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.first_mouse_location = (event.x(), event.y())
self.band = ResizableRubberBand(self)
self.band.setGeometry(event.x(), event.y(), 0, 0)
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
first_mouse_location_x = self.first_mouse_location[0]
first_mouse_location_y = self.first_mouse_location[1]
new_x, new_y = event.x(), event.y()
difference_x = new_x - first_mouse_location_x
difference_y = new_y - first_mouse_location_y
self.band.resize(difference_x, difference_y)
class App(QWidget):
def __init__(self):
super().__init__()
## Set main window attributes
self.setFixedSize(1000,600)
# Add Label
self.label = mQLabel()
self.label.setStyleSheet("border: 1px solid black;")
self.label_layout = QHBoxLayout(self)
self.label_layout.addWidget(self.label)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
I'm trying to figure it out for 2 hours but I can't really seem to figure out what causes the unnecessary movement. My best guess is it is coming from the mouseMoveEvent
but I'm not quite sure if it is from the parent QRubberband
or from the QRubberband
inside. I hope someone can figure out what is happening here.