在同一个 Qwidget 中显示不同的 Paint class

Showing different Paint class in same Qwidget

下图显示了一个带有一个输入小部件和一个绘画小部件的应用程序。

并且代码中有两个 paint classes。这个想法是当一个按钮被点击时,调用第一个 paint class 并在 Paintwidget 中显示它,当另一个 paint class 被调用时,想要在同一个 Paintwidget 中显示。并没有真正相互重叠,而是显示在同一个小部件中。

这怎么可能?

当单击圆形按钮时,此代码行从

    self.mainSplitter.addWidget(self.paint1)

    self.mainSplitter.addWidget(self.paint2)

反之亦然

可视化:

代码:

from PyQt5 import QtCore, QtGui, QtWidgets

class Foo(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Foo, self).__init__(parent)
        self.setGeometry(QtCore.QRect(200, 100, 800, 650))

        self.button = Button()
        self.paint1 = Paintwidget1()
        self.paint2 = Paintwidget2()
        self.button.valuesChanged.connect(self.paint1.set_size_squares)
        self.button.valueChanged.connect(self.paint2.set_size_round)

        self.mainSplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
        self.mainSplitter.addWidget(self.button)
        self.mainSplitter.addWidget(self.paint1)

        self.setCentralWidget(self.mainSplitter)

class Paintwidget1(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.sizeHint()        
        self.setBackgroundRole(QtGui.QPalette.Base)     
        self.setAutoFillBackground(True)

        self._size = QtCore.QSizeF()
        self._path = QtGui.QPainterPath()
        self._rect = QtCore.QRectF()
        self._type = QtGui.QRegion.Rectangle
        self._factor = 1.0

        self._pos = QtCore.QPointF()
        self._initial_flag = False
        fnt = self.font() 
        fnt.setPointSize(20) 
        self.setFont(fnt) 

    def showEvent(self, event):
        if not self._initial_flag:
            self._pos = self.rect().center()
            self._initial_flag = True

    @QtCore.pyqtSlot(int, int)
    def set_size_squares(self, w, h):
        self._path = QtGui.QPainterPath()
        self._size = QtCore.QSizeF(w, h)
        self._type = QtGui.QRegion.Rectangle
        self.updatePath()

    def paintEvent(self, event):
        pen = QtGui.QPen()
        brush = QtGui.QBrush(QtCore.Qt.black)
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(pen)
        painter.setBrush(brush)

        painter.translate(self.rect().center())
        painter.scale(self._factor, self._factor)
        painter.translate(-self.rect().center())

        painter.translate(self._pos)
        painter.drawPath(self._path)
        if self._type == QtGui.QRegion.Rectangle:
            painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
            painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
            painter.drawRect(self._rect)


    def mousePressEvent(self, event):
        QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
        self._initial_pos = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        delta = event.pos() - self._initial_pos
        self._path.translate(delta)
        self._rect.translate(delta)
        self.update()
        self._initial_pos = event.pos()
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        QtWidgets.QApplication.restoreOverrideCursor()
        super().mouseReleaseEvent(event)

    def updatePath(self):
        r = QtCore.QRectF(QtCore.QPointF(), self._size)
        r.moveCenter(QtCore.QPointF())
        self._rect = QtCore.QRectF(r)
        self.update()

    def wheelEvent(self, event):
        self._factor *= 1.01**(event.angleDelta().y()/15.0)
        self.update()
        super().wheelEvent(event)

class Paintwidget2(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.sizeHint()        
        self.setBackgroundRole(QtGui.QPalette.Base)     
        self.setAutoFillBackground(True)

        self._size = QtCore.QSizeF()
        self._path = QtGui.QPainterPath()
        self._rect = QtCore.QRectF()
        self._type = QtGui.QRegion.Rectangle
        self._factor = 1.0

        self._pos = QtCore.QPointF()
        self._initial_flag = False
        fnt = self.font() 
        fnt.setPointSize(20) 
        self.setFont(fnt) 

    def showEvent(self, event):
        if not self._initial_flag:
            self._pos = self.rect().center()
            self._initial_flag = True

    @QtCore.pyqtSlot(int)
    def set_size_round(self, v):
        self._path = QtGui.QPainterPath()
        self._size = QtCore.QSizeF(v, 0.8*v)
        self._type = QtGui.QRegion.Ellipse
        self.updatePath()

    def paintEvent(self, event):
        pen = QtGui.QPen()
        brush = QtGui.QBrush(QtCore.Qt.black)
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(pen)
        painter.setBrush(brush)

        painter.translate(self.rect().center())
        painter.scale(self._factor, self._factor)
        painter.translate(-self.rect().center())

        painter.translate(self._pos)
        painter.drawPath(self._path)
        if self._type == QtGui.QRegion.Ellipse:
            painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
            painter.drawEllipse(self._rect)

    def mousePressEvent(self, event):
        QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
        self._initial_pos = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        delta = event.pos() - self._initial_pos
        self._path.translate(delta)
        self._rect.translate(delta)
        self.update()
        self._initial_pos = event.pos()
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        QtWidgets.QApplication.restoreOverrideCursor()
        super().mouseReleaseEvent(event)

    def updatePath(self):
        r = QtCore.QRectF(QtCore.QPointF(), self._size)
        r.moveCenter(QtCore.QPointF())
        self._rect = QtCore.QRectF(r)
        self.update()

    def wheelEvent(self, event):
        self._factor *= 1.01**(event.angleDelta().y()/15.0)
        self.update()
        super().wheelEvent(event)

class Button(QtWidgets.QWidget):
    valueChanged = QtCore.pyqtSignal(int)
    valuesChanged = QtCore.pyqtSignal(int,int)
    def __init__(self, parent=None):
        super(Button, self).__init__(parent)
        roundbutton = QtWidgets.QPushButton('Round')
        squarebutton = QtWidgets.QPushButton('Square')
        Alay = QtWidgets.QVBoxLayout(self)
        Alay.addWidget(roundbutton)
        Alay.addWidget(squarebutton)
        self.value = QtWidgets.QLabel()
        roundbutton.clicked.connect(self.getbuttonfunc)
        squarebutton.clicked.connect(self.sqaurebuttonfunc)

    @QtCore.pyqtSlot()
    def getbuttonfunc(self):
        number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
                                         self.tr("Input:"), 1, 1)
        if ok:
            self.valueChanged.emit(number)

    @QtCore.pyqtSlot()
    def sqaurebuttonfunc(self):
        number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
                                         self.tr("Input:"), 1, 1)
        if ok:
            self.valuesChanged.emit(number, number)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Foo()
    w.show()
    sys.exit(app.exec_())

你必须使用QStackedWidget来交换插件,还要设置sizeHint() of Paintwidget1Paintwidget2:

class Foo(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Foo, self).__init__(parent)
        self.setGeometry(QtCore.QRect(200, 100, 800, 650))
        self.button = Button()
        self.paint1 = Paintwidget1()
        self.paint2 = Paintwidget2()
        self.button.valuesChanged.connect(self.on_paint1)
        self.button.valueChanged.connect(self.on_paint2)
        self.mainSplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
        self._stacked_widget = QtWidgets.QStackedWidget()
        self.mainSplitter.addWidget(self.button)
        self.mainSplitter.addWidget(self._stacked_widget)
        self.setCentralWidget(self.mainSplitter)
        self._stacked_widget.addWidget(self.paint1)
        self._stacked_widget.addWidget(self.paint2)

    @QtCore.pyqtSlot(int, int)
    def on_paint1(self, w, h):
        self._stacked_widget.setCurrentIndex(0)
        self.paint1.set_size_squares(w, h)

    @QtCore.pyqtSlot(int)
    def on_paint2(self, v):
        self._stacked_widget.setCurrentIndex(1)
        self.paint2.set_size_round(v)

class Paintwidget1(QtWidgets.QWidget):
    # ...
    def sizeHint(self):
        return QtCore.QSize(640, 480)

class Paintwidget2(QtWidgets.QWidget):
    # ...
    def sizeHint(self):
        return QtCore.QSize(640, 480)