class ResizableRubberBand(QWidget): """Wrapper to make QRubberBand mouse-resizable using QSizeGrip https://stackoverflow.com/questions/19066804/implementing-resize-handles-on-qrubberband-is-qsizegrip-relevant Source: http://stackoverflow.com/a/19067132/435253 """ def __init__(self, parent=None): super(ResizableRubberBand, self).__init__(parent) self.setMinimumSize(30, 30) self.setWindowFlags(Qt.SubWindow) self.layout = QHBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.grip1 = QSizeGrip(self) self.layout.addWidget(self.grip1, 0, Qt.AlignRight | Qt.AlignBottom) self.rubberband = QRubberBand(QRubberBand.Rectangle, self) self.rubberband.move(0, 0) self.rubberband.show() self.move_offset = None self.resize(150, 150) self.show() def resizeEvent(self, event): self.rubberband.resize(self.size()) def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: self.move_offset = event.pos() def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton: new_pos = self.mapToParent(event.pos() - self.move_offset) parent_rect = self.parent().rect() image_rect = self.parent().pixmap().rect() adjustment = parent_rect.bottomRight() - image_rect.bottomRight() y_offset = adjustment.y() / 2 x_offset = adjustment.x() / 2 new_pos.setX(max(x_offset, min(new_pos.x(), image_rect.width() - self.width() + x_offset))) new_pos.setY(max(y_offset, min(new_pos.y(), image_rect.height() - self.height() + y_offset))) self.move(new_pos) def mouseReleaseEvent(self, event): self.move_offset = None
class ImageCropperDropper(QLabel): '''A QLabel that displays a rectangle when drawing a rectangle with the mouse''' cropped = Signal(QPixmap) fileDropped = Signal(QUrl) def __init__(self, mainwin): QLabel.__init__(self) self.setAcceptDrops(True) self.marker = QRubberBand(QRubberBand.Rectangle, self) self.markOrigin = self.markEnd = None self.setContextMenuPolicy(Qt.ActionsContextMenu) self.addAction(mainwin.cropAction) self.addAction(mainwin.saveAction) def setPixmap(self, pix): QLabel.setPixmap(self, pix) self.resize(pix.size()) self.marker.hide() self.markOrigin = self.markEnd = None @Slot() def doCrop(self): '''Crop the pixmap using the user-drawn rectangle, emits cropped(QPixmap) signal''' if not self.markEnd: QMessageBox.warning(self, 'Error', 'Select a region to crop first') return cropzone = self._makeRect(self.markOrigin, self.markEnd) croppedpix = self.pixmap().copy(cropzone) self.setPixmap(croppedpix) self.cropped.emit(croppedpix) def _makeRect(self, p1, p2): '''Make a QRect based on QPoints p1 and p2. The 2 points must be 2 corners but don't need to be upper-left&lower-right''' x1, x2 = min(p1.x(), p2.x()), max(p1.x(), p2.x()) y1, y2 = min(p1.y(), p2.y()), max(p1.y(), p2.y()) return QRect().adjusted(x1, y1, x2, y2) def mouseMoveEvent(self, ev): if ev.buttons() != Qt.LeftButton: return QLabel.mouseMoveEvent(self, ev) self.markEnd = ev.pos() diffpoint = self.markEnd - self.markOrigin #~ self.marker.resize(diffpoint.x(), diffpoint.y()) self.marker.setGeometry(self._makeRect(self.markOrigin, self.markEnd)) #~ ev.accept() def mousePressEvent(self, ev): if ev.button() != Qt.LeftButton: return QLabel.mousePressEvent(self, ev) self.markOrigin = ev.pos() self.marker.move(ev.pos()) self.marker.resize(QSize()) self.marker.show() #~ ev.accept() def dragEnterEvent(self, ev): if ev.mimeData().hasUrls(): ev.setDropAction(Qt.CopyAction) ev.accept() def dropEvent(self, ev): if ev.mimeData().hasUrls(): ev.setDropAction(Qt.CopyAction) ev.accept() self.fileDropped.emit(ev.mimeData().urls()[0])
class ResizableRubberBandWithGrip(QWidget): # containerResized = Signal(QSize) enter_or_return_key_pressed = pyqtSignal(QRect) esc_key_pressed = pyqtSignal() # --------------------------------------------------------------------- def __init__(self, parent=None): super(ResizableRubberBandWithGrip, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowTitle("Defter: Screenshot") self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_NoSystemBackground) # self.setAttribute(Qt.WA_PaintOnScreen) # self.setAttribute(Qt.WA_OpaquePaintEvent, False) # self.setStyleSheet("QWidget{background:transparent;}") # self.setStyleSheet("QWidget{background-color:none;}") # self.setStyleSheet("background-color: rgba(255, 255, 255, 40%);") # self.setWindowOpacity(0.7) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) grip1 = MySizeGrip(self) # grip2 = QSizeGrip(self) # grip3 = QSizeGrip(self) grip4 = MySizeGrip(self) layout.addWidget(grip1, 0, Qt.AlignLeft | Qt.AlignTop) # layout.addWidget(grip3, 0, Qt.AlignRight | Qt.AlignTop) # layout.addWidget(grip2, 0, Qt.AlignLeft | Qt.AlignBottom) layout.addWidget(grip4, 0, Qt.AlignRight | Qt.AlignBottom) self.rubberband = QRubberBand(QRubberBand.Rectangle, self) self.rubberband.move(0, 0) self.rubberband.show() self.show() def mousePressEvent(self, event): self._mousePressPos = None self._mouseMovePos = None if event.button() == Qt.LeftButton: self._mousePressPos = event.globalPos() self._mouseMovePos = event.globalPos() super(ResizableRubberBandWithGrip, self).mousePressEvent(event) def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton: # adjust offset from clicked point to origin of widget currPos = self.mapToGlobal(self.pos()) globalPos = event.globalPos() diff = globalPos - self._mouseMovePos newPos = self.mapFromGlobal(currPos + diff) self.move(newPos) self._mouseMovePos = globalPos super(ResizableRubberBandWithGrip, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): if self._mousePressPos: moved = event.globalPos() - self._mousePressPos if moved.manhattanLength() > 3: event.ignore() return super(ResizableRubberBandWithGrip, self).mouseReleaseEvent(event) # --------------------------------------------------------------------- def resizeEvent(self, event): # self.containerResized.emit((self.size())) self.rubberband.resize(self.size()) super(ResizableRubberBandWithGrip, self).resizeEvent(event) # --------------------------------------------------------------------- def mouseDoubleClickEvent(self, event): self.hide() self.enter_or_return_key_pressed.emit(self.geometry()) # self.close() # self.deleteLater() # --------------------------------------------------------------------- def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.esc_key_pressed.emit() elif event.key() == Qt.Key_Enter or Qt.Key_Return: self.hide() self.enter_or_return_key_pressed.emit(self.geometry()) # self.close() # self.deleteLater() # return ResizableRubberBandWithGripForImageResizing.keyPressEvent(self, event) super(ResizableRubberBandWithGrip, self).keyPressEvent(event)
class RubberBand(QWidget): def __init__(self, parent=None): super().__init__(parent) self.draggable = True self.dragging_threshold = 5 self.mousePressPos = None self.mouseMovePos = None self.parent = parent self.setWindowFlags(Qt.SubWindow) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) top = QHBoxLayout() top.setContentsMargins(0, 0, 0, 0) top.addWidget( QSizeGrip(self), 0, Qt.AlignLeft | Qt.AlignTop) top.addWidget( HSizeGrip(self), 0, Qt.AlignHCenter | Qt.AlignTop) top.addWidget( QSizeGrip(self), 0, Qt.AlignRight | Qt.AlignTop) layout.addLayout(top) center = QHBoxLayout() center.setContentsMargins(0, 0, 0, 0) center.addWidget( VSizeGrip(self), 0, Qt.AlignLeft | Qt.AlignVCenter) center.addWidget( VSizeGrip(self), 0, Qt.AlignRight | Qt.AlignVCenter) layout.addLayout(center) bottom = QHBoxLayout() bottom.setContentsMargins(0, 0, 0, 0) bottom.addWidget( QSizeGrip(self), 0, Qt.AlignLeft | Qt.AlignBottom) bottom.addWidget( HSizeGrip(self), 0, Qt.AlignHCenter | Qt.AlignBottom) bottom.addWidget( QSizeGrip(self), 0, Qt.AlignRight | Qt.AlignBottom) layout.addLayout(bottom) self.setLayout(layout) self.rubberband = QRubberBand(QRubberBand.Rectangle, self) #self.rubberband.show() #self.show() cropSignal = pyqtSignal() sizeSignal = pyqtSignal(QRect) def resizeEvent(self, event): self.rubberband.resize(self.size()) #super(RubberBand, self).resizeEvent(event) def paintEvent(self, event): ## Get current window size window_size = self.size() qp = QPainter() bg = QColor(170,210,235,100) qp.begin(self) ## background qp.setBrush(bg) ## border lines qp.setPen(QColor(70,130,255,70)) qp.setRenderHint(QPainter.Antialiasing, True) qp.drawRect(0, 0, window_size.width(), window_size.height()) qp.end() def mousePressEvent(self, event): if self.draggable and self.underMouse(): self.mousePressPos = event.globalPos() # global self.mouseMovePos = event.globalPos() - self.pos() # local def mouseDoubleClickEvent(self, event): self.cropSignal.emit() def mouseMoveEvent(self, event): if self.draggable and self.underMouse(): globalPos = event.globalPos() moved = globalPos - self.mousePressPos if moved.manhattanLength() > self.dragging_threshold: # Move when user drag window more than dragging_threshold diff = globalPos - self.mouseMovePos self.move(diff) self.mouseMovePos = globalPos - self.pos() def mouseReleaseEvent(self, event): if self.mousePressPos is not None: if event.button() == Qt.RightButton: moved = event.globalPos() - self.mousePressPos if moved.manhattanLength() > self.dragging_threshold: # Do not call click event or so on event.ignore() self.mousePressPos = None def resizeEvent(self,event): #print('rubber geo : ',self.geometry()) self.sizeSignal.emit(self.geometry()) def moveEvent(self, event): self.sizeSignal.emit(self.geometry())