diff --git a/labelme/app.py b/labelme/app.py index e67abb1b3..6c7fa9101 100644 --- a/labelme/app.py +++ b/labelme/app.py @@ -186,6 +186,7 @@ def __init__( Qt.Horizontal: scrollArea.horizontalScrollBar(), } self.canvas.scrollRequest.connect(self.scrollRequest) + self.canvas.scrollDragRequest.connect(self.scrollDragRequest) self.canvas.newShape.connect(self.newShape) self.canvas.shapeMoved.connect(self.setDirty) @@ -1422,6 +1423,15 @@ def scrollRequest(self, delta, orientation): value = bar.value() + bar.singleStep() * units self.setScroll(orientation, value) + # Обработка события панорамирования + def scrollDragRequest(self, delta, orientation): + bar = self.scrollBars[orientation] + # Новое значение слайдера получается как предыдущее + нормированное смещение по координатам в окне + if orientation == QtCore.Qt.Vertical: + self.setScroll(orientation, bar.value() + delta * bar.height()) + else: + self.setScroll(orientation, bar.value() + delta * bar.width()) + def setScroll(self, orientation, value): self.scrollBars[orientation].setValue(int(value)) self.scroll_values[orientation][self.filename] = value diff --git a/labelme/widgets/__init__.py b/labelme/widgets/__init__.py index 6283ef1e8..a570f4ec6 100644 --- a/labelme/widgets/__init__.py +++ b/labelme/widgets/__init__.py @@ -2,8 +2,6 @@ from .ai_prompt_widget import AiPromptWidget -from .brightness_contrast_dialog import BrightnessContrastDialog - from .canvas import Canvas from .color_dialog import ColorDialog diff --git a/labelme/widgets/canvas.py b/labelme/widgets/canvas.py index ab234c606..9fd29b64a 100644 --- a/labelme/widgets/canvas.py +++ b/labelme/widgets/canvas.py @@ -33,6 +33,7 @@ class Canvas(QtWidgets.QWidget): drawingPolygon = QtCore.Signal(bool) vertexSelected = QtCore.Signal(bool) mouseMoved = QtCore.Signal(QtCore.QPointF) + scrollDragRequest = QtCore.Signal(float, int) # Сигнал для панорамирования CREATE, EDIT = 0, 1 @@ -228,6 +229,19 @@ def selectedEdge(self): return self.hEdge is not None def mouseMoveEvent(self, ev): + """ + Если зажато колёсико мыши, то запускаем панорамирование. + deltaX, deltaY -- нормированное смещение по соответствующей координате + """ + if ev.buttons() & QtCore.Qt.MiddleButton: + QtGui.QCursor.setPos(self.mapToGlobal(self._pan_start)) + deltaX = (ev.x() - self._pan_start.x()) / self.cropped_image.width() / self.scale + deltaY = (ev.y() - self._pan_start.y()) / self.cropped_image.height() / self.scale + self.scrollDragRequest.emit(deltaX, QtCore.Qt.Horizontal) + self.scrollDragRequest.emit(deltaY, QtCore.Qt.Vertical) + # self._pan_start = ev.pos() # Позволяет панорамировать относительно зажатого курсора + ev.accept() + return """Update line with last point and current coordinates.""" try: if QT5: @@ -379,7 +393,7 @@ def removeSelectedPoint(self): def zoomShape(self): """ - "Переходит" к элементу, ч тобы добавлять элементы + "Переходит" к элементу, чтобы добавлять элементы соответствующего типа. """ if len(self.selectedShapes) == 1: @@ -389,8 +403,6 @@ def zoomShape(self): self.visible.update((k, False) for k in self.visible) self.visible.update((shape.getId(), True) for shape in self.selectedShape.getAllChildren()) self.cropp() - else: - print("Необходимо выбрать 1 примоугольник.") def unZoomShape(self): """ @@ -481,6 +493,10 @@ def mousePressEvent(self, ev): self.selectShapePoint(pos, multiple_selection_mode=group_mode) self.repaint() self.prevPoint = pos + elif ev.button() == QtCore.Qt.MiddleButton: + self._pan_start = ev.pos() # Точка, относительно которой выполняется панорамирование + self.overrideCursor(CURSOR_MOVE) # Поменять курсор на сжатую ручку + ev.accept() def mouseReleaseEvent(self, ev): if ev.button() == QtCore.Qt.RightButton: @@ -500,6 +516,8 @@ def mouseReleaseEvent(self, ev): self.selectionChanged.emit( [x for x in self.selectedShapes if x != self.hShape] ) + elif ev.button() == QtCore.Qt.MiddleButton: + self.overrideCursor(CURSOR_GRAB) # Панорамирование окончено. Возвращение курсора к обычному виду. if self.movingShape and self.hShape: index = self.shapes.index(self.hShape)