Чтение или передача данных вне класса события мыши - PullRequest
0 голосов
/ 18 октября 2018

У меня есть виджет, который использует резиновую полосу, чтобы выбрать область на изображении, он может быть изменен в любом аспекте.Мне нужно добавить функции, чтобы после того, как резиновая лента была помещена, она снова могла быть изменяемого размера или редактируемой, поэтому моя идея состоит в том, чтобы сохранить точки региона (x, y, w, h) после события отпускания мыши.

Но теперь проблема в том, как передать данные, прочитанные в событии отпускания мыши, за пределы моего класса с резинкой.

Вот мой код перетаскивания и редактирования резиновой ленты.

class rubberBandWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.tweaking = False
        self.tweakingpart = ""

    def mousePressEvent(self, event):
        pt = self.mapFromGlobal(event.globalPos())
        rg = self.rubberBand.geometry()

        if rg.isValid():
            tl, tr, bl, br = rg.topLeft(), rg.topRight(), rg.bottomLeft(), rg.bottomRight()
            off, offx, offy = QPoint(3, 3), QPoint(4, -3), QPoint(-3, 4)

            if QRect(tl - off, tl + off).contains(pt):
                self.tweakingpart = "topLeft";
                self.setCursor(Qt.SizeFDiagCursor)
            elif QRect(tr - off, tr + off).contains(pt):
                self.tweakingpart = "topRight";
                self.setCursor(Qt.SizeBDiagCursor)
            elif QRect(bl - off, bl + off).contains(pt):
                self.tweakingpart = "bottomLeft";
                self.setCursor(Qt.SizeBDiagCursor)
            elif QRect(br - off, br + off).contains(pt):
                self.tweakingpart = "bottomRight";
                self.setCursor(Qt.SizeFDiagCursor)
            elif QRect(tl + offx, tr - offx).contains(pt):
                self.tweakingpart = "top";
                self.setCursor(Qt.SizeVerCursor)
            elif QRect(bl + offx, br - offx).contains(pt):
                self.tweakingpart = "bottom"
                self.setCursor(Qt.SizeVerCursor)
            elif QRect(tl + offy, bl - offy).contains(pt):
                self.tweakingpart = "left";
                self.setCursor(Qt.SizeHorCursor)
            elif QRect(tr + offy, br - offy).contains(pt):
                self.tweakingpart = "right";
                self.setCursor(Qt.SizeHorCursor)

            if self.tweakingpart != "":
                self.tweaking = True
                return

        self.origin = pt
        self.rubberBand.setGeometry(QRect(self.origin, QtCore.QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, event):
        pt = self.mapFromGlobal(event.globalPos())
        if self.tweaking:
            rg = self.rubberBand.geometry()
            if self.tweakingpart == "topLeft":
                rg.setTopLeft(pt)
            elif self.tweakingpart == "topRight":
                rg.setTopRight(pt)
            elif self.tweakingpart == "bottomLeft":
                rg.setBottomLeft(pt)
            elif self.tweakingpart == "bottomRight":
                rg.setBottomRight(pt)
            elif self.tweakingpart == "top":
                rg.setTop(pt.y())
            elif self.tweakingpart == "bottom":
                rg.setBottom(pt.y())
            elif self.tweakingpart == "left":
                rg.setLeft(pt.x())
            elif self.tweakingpart == "right":
                rg.setRight(pt.x())
            self.rubberBand.setGeometry(rg)
        else:
            self.rubberBand.setGeometry(QRect(self.origin, pt).normalized())

А вот мой код события релиза и данные (x, y, w, h), которые необходимобыть пропущенным или прочитанным вне класса.

def mouseReleaseEvent(self, event):
    self.tweaking = False
    self.tweakingpart = ""
    self.unsetCursor()

    if self.rubberBand.width() != 0 and self.rubberBand.height() != 0:
        print(self.rubberBand.x(), self.rubberBand.y(), self.rubberBand.width(), self.rubberBand.height())

Мне нужны данные при каждом отпускании мыши и их сохранение.Поэтому, как только пользователю потребуется изменить размер и снова отредактировать, моя идея состоит в том, чтобы установить геометрию круглой резинки и повторно запустить класс, чтобы он снова мог редактироваться.

1 Ответ

0 голосов
/ 18 октября 2018

Если вы хотите представить данные вне класса, вы должны использовать сигналы, как показано ниже:

import sys

from PyQt4 import QtCore, QtGui

class rubberBandWidget(QtGui.QWidget):
    rectChanged = QtCore.pyqtSignal(QtCore.QRect) # create signal
    ...
    def mouseReleaseEvent(self, event):
        self.tweaking = False
        self.tweakingpart = ""
        self.unsetCursor()

        if not self.rubberBand.geometry().isNull():
            self.rectChanged.emit(self.rubberBand.geometry()) # emit signal


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    w = rubberBandWidget()
    def on_rectChanged(rect):
        # receiver
        print(rect.x(), rect.y(), rect.width(), rect.height())
    w.rectChanged.connect(on_rectChanged) # connect signal
    w.show()
    sys.exit(app.exec_())

С другой стороны, я вижу, что ваш код очень связан, потому что если вы хотитечтобы использовать ту же функциональность в другом виджете, вам придется скопировать весь код, а это нежелательно, поэтому я потрачу время на создание пользовательского QRubberband, который обладает такими функциями. В следующей части я покажу пример.

import sys

from PyQt4 import QtCore, QtGui


class RubberBand(QtGui.QRubberBand):
    rectChanged = QtCore.pyqtSignal(QtCore.QRect)

    TopLeft, TopRight, BottomLeft, BottomRight, Top, Bottom, Left, Right, NonePos = range(9)

    def __init__(self, parent=None):
        super(RubberBand, self).__init__(QtGui.QRubberBand.Rectangle, parent)
        self._widget = None
        self.setWidget(parent)
        self.tweakingpart = RubberBand.NonePos

        self.cursors = [QtCore.Qt.SizeFDiagCursor,
                        QtCore.Qt.SizeBDiagCursor,
                        QtCore.Qt.SizeBDiagCursor,
                        QtCore.Qt.SizeFDiagCursor,
                        QtCore.Qt.SizeVerCursor,
                        QtCore.Qt.SizeVerCursor,
                        QtCore.Qt.SizeHorCursor,
                        QtCore.Qt.SizeHorCursor]

    def setWidget(self, widget):
        if widget is None:
            return
        if self._widget is not None:
            self._widget.removeEventFilter(self)
        self._widget = widget
        self._widget.installEventFilter(self)
        self.setParent(widget)

    def eventFilter(self, obj, event):
        if self._widget is obj:
            if event.type() == QtCore.QEvent.MouseButtonPress:
                self.handleMousePressEvent(event.pos())
                return True
            elif event.type() == QtCore.QEvent.MouseMove:
                self.handleMouseMoveEvent(event.pos())
                return True
            elif event.type() == QtCore.QEvent.MouseButtonRelease:
                self.handleMouseReleaseEvent(event.pos())
                return True
        return super(RubberBand, self).eventFilter(obj, event)

    def handleMousePressEvent(self, pt):
        rg = self.geometry()
        if not rg.isValid():
            return
        off, offx, offy = QtCore.QPoint(3, 3), QtCore.QPoint(4, -3), QtCore.QPoint(-3, 4)
        rect = QtCore.QRect(-off, off)
        tl, tr, bl, br = rg.topLeft(), rg.topRight(), rg.bottomLeft(), rg.bottomRight()
        for i, coord in enumerate([tl, tr, bl, br]):
            rect.moveCenter(coord)
            if rect.contains(pt):
                self.tweakingpart = i
        if QtCore.QRect(tl + offx, tr - offx).contains(pt):
            self.tweakingpart = RubberBand.Top
        elif QtCore.QRect(bl + offx, br - offx).contains(pt):
            self.tweakingpart = RubberBand.Bottom
        elif QtCore.QRect(tl + offy, bl - offy).contains(pt):
            self.tweakingpart = RubberBand.Left
        elif QtCore.QRect(tr + offy, br - offy).contains(pt):
                self.tweakingpart = RubberBand.Right

        if 0 <= self.tweakingpart < RubberBand.NonePos:
            self._widget.setCursor(self.cursors[self.tweakingpart])
            return
        self.setGeometry(QtCore.QRect(pt, QtCore.QSize()))
        self.show()

    def handleMouseMoveEvent(self, pt):
        rg = self.geometry()
        if 0 <= self.tweakingpart < RubberBand.NonePos:
            if self.tweakingpart == RubberBand.TopLeft:
                rg.setTopLeft(pt)
            elif self.tweakingpart == RubberBand.TopRight:
                rg.setTopRight(pt)
            elif self.tweakingpart == RubberBand.BottomLeft:
                rg.setBottomLeft(pt)
            elif self.tweakingpart == RubberBand.BottomRight:
                rg.setBottomRight(pt)
            elif self.tweakingpart == RubberBand.Top:
                rg.setTop(pt.y())
            elif self.tweakingpart == RubberBand.Bottom:
                rg.setBottom(pt.y())
            elif self.tweakingpart == RubberBand.Left:
                rg.setLeft(pt.x())
            elif self.tweakingpart == RubberBand.Right:
                rg.setRight(pt.x())
        else:
            rg = QtCore.QRect(rg.topLeft(), pt).normalized()
        self.setGeometry(rg)

    def handleMouseReleaseEvent(self, pt):
        self.tweakingpart = RubberBand.NonePos
        self._widget.unsetCursor()
        if not self.geometry().isNull():
            self.rectChanged.emit(self.geometry())


class TestWidget(QtGui.QWidget):
    pass


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    w = TestWidget()
    rubberBand = RubberBand(w)
    def on_rectChanged(rect):
        print(rect.x(), rect.y(), rect.width(), rect.height())
    rubberBand.rectChanged.connect(on_rectChanged)
    w.show()
    sys.exit(app.exec_())
...