python pyqt QPainter 小部件不显示在布局中

python pyqt QPainter widgets don't show up in layout

我是 python3 pyqt GUI 开发的新手。我正在尝试制作一个简单的 GUI,它在包含许多 QHBoxLayout 的 QVBoxLayout 的复合布局结构中很好地具有各种小部件 spaced。在构建布局时,我使用 addStretch() 方法 space 出小部件,但绘制的圆圈不会显示在 GUI 显示中。但是,如果我注释掉所有 addStretch() 函数调用,则 GUI 会显示所有需要的小部件(但是间距不好看)。圆圈去哪儿了?

请帮忙!

不显示圆形小部件的代码。

#!/usr/bin/python3

import sys

from PyQt4 import QtCore, QtGui

class DrawCircle(QtGui.QWidget):
    def __init__(self, color, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.color = color

    def setColor(self,color):
        self.color = color

    def paintEvent(self,event):
        self.paint = QtGui.QPainter()
        self.paint.begin(self)
        self.paint.setRenderHint(QtGui.QPainter.Antialiasing)
        radx = 30
        rady = radx
        if self.color == 'red':
            self.paint.setPen(QtCore.Qt.red)
            self.paint.setBrush(QtCore.Qt.red)
        elif self.color == 'green':
            self.paint.setPen(QtCore.Qt.green)
            self.paint.setBrush(QtCore.Qt.green)
        k = int(radx * 1.5)
        center = QtCore.QPoint(k,k)
        self.paint.drawEllipse(center,radx,rady)
        self.paint.end()


class Window(QtGui.QMainWindow, QtGui.QGraphicsView):
    def __init__(self):
        super(Window,self).__init__()

        # GUI Setup
        self.myWid = QtGui.QWidget()

        # Establish a Vertical Box Layout
        # The layout will be a vertical box layout comprised of horizontal
        # box layouts
        self.vbox_fullDisplay = QtGui.QVBoxLayout()


        # Add a Zero-width spacer-item before the area where the
        # text label will appear
        self.vbox_fullDisplay.addStretch(1)

        ###############################
        # Build horizontal box layout #
        ###############################
        self.hbox_top = QtGui.QHBoxLayout()
        # The text should be centered on the screen so zero-width
        # spacer items will be added to the left and right of the label
        self.hbox_top.addStretch(1)

        self.top_text_label = QtGui.QLabel(self)
        self.top_text_label.setFont(QtGui.QFont("Times",32,QtGui.QFont.Bold))
        self.top_text_label.setText("Top of window")
        self.top_text_label.adjustSize()
        self.hbox_top.addWidget(self.top_text_label)

        self.hbox_top.addStretch(1)

        # Add the horizontal box layout to the vertical box layout
        self.vbox_fullDisplay.addLayout(self.hbox_top)

        # Add space between the text and the row of circles
        self.vbox_fullDisplay.addStretch(1)

        ############################
        # Build the row of buttons #
        ############################
        self.hbox_buttons = QtGui.QHBoxLayout()
        # The text should be centered on the screen so zero-width
        # spacer items will be added to the left and right of the label
        self.hbox_buttons.addStretch(1)

        # These buttons will be used to toggle the color of the circles
        btn1 = QtGui.QPushButton('Circle 1')
        btn1.clicked.connect(self.circle1Meth)

        btn2 = QtGui.QPushButton('Circle 2')
        btn2.clicked.connect(self.circle2Meth)

        self.hbox_buttons.addWidget(btn1)
        self.hbox_buttons.addStretch(1)
        self.hbox_buttons.addWidget(btn2)
        self.hbox_buttons.addStretch(1)

        # Add the horizontal box layout to the vertical box layout
        self.vbox_fullDisplay.addLayout(self.hbox_buttons)

        # Add space between the text and the row of circles
        self.vbox_fullDisplay.addStretch(1)

        ############################
        # Build the row of circles #
        ############################
        self.hbox_circles = QtGui.QHBoxLayout()
        self.hbox_circles.addStretch(1)
        self.__circleColors = ['red','green']
        self.__circle1Color = 0;
        self.circle1 = DrawCircle(self.__circleColors[self.__circle1Color])
        print("const draw circ2")
        self.__circle2Color = 1
        self.circle2 = DrawCircle(self.__circleColors[self.__circle2Color])

        self.hbox_circles.addWidget(self.circle1)
        self.hbox_circles.addStretch(1)
        self.hbox_circles.addWidget(self.circle2)
        self.hbox_circles.addStretch(1)

        # Add the row of circles to the vertical box layout
        self.vbox_fullDisplay.addLayout(self.hbox_circles)

        # Add space between the circles and the slot machine pictures
        self.vbox_fullDisplay.addStretch(1)

        self.bottomLabel = QtGui.QLabel(self)
        self.bottomLabel.setText("Bottom Of GUI")
        self.bottomLabel.adjustSize()
        self.vbox_fullDisplay.addWidget(self.bottomLabel)

        self.myWid.setLayout(self.vbox_fullDisplay)
        self.setCentralWidget(self.myWid)

        self.setGeometry(100,200,600,500)
        self.setWindowTitle('Does this work')

    def circle1Meth(self):
        print("Circ1 change")
        if self.__circle1Color == 1:
            self.__circle1Color = 0
        else:
            self.__circle1Color = 1

        # Set the color for circle 1
        self.circle1.setColor(self.__circleColors[self.__circle1Color])

        # force a repaint by updating the widget Using the repaint() method
        # could cause infinite recursion
        self.update()

    def circle2Meth(self):
        print("Circ2 change")
        if self.__circle2Color == 1:
            self.__circle2Color = 0
        else:
            self.__circle2Color = 1

        # Set the color for circle 1
        self.circle2.setColor(self.__circleColors[self.__circle2Color])

        # force a repaint by updating the widget Using the repaint() method
        # could cause infinite recursion
        self.update()

###
# Run GUI
###
app = QtGui.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())

显示圆形小部件的代码(所有 addStretch() 调用都已注释掉)

#!/usr/bin/python3

import sys

from PyQt4 import QtCore, QtGui

class DrawCircle(QtGui.QWidget):
    def __init__(self, color, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.color = color

    def setColor(self,color):
        self.color = color

    def paintEvent(self,event):
        self.paint = QtGui.QPainter()
        self.paint.begin(self)
        self.paint.setRenderHint(QtGui.QPainter.Antialiasing)
        radx = 30
        rady = radx
        if self.color == 'red':
            self.paint.setPen(QtCore.Qt.red)
            self.paint.setBrush(QtCore.Qt.red)
        elif self.color == 'green':
            self.paint.setPen(QtCore.Qt.green)
            self.paint.setBrush(QtCore.Qt.green)
        k = int(radx * 1.5)
        center = QtCore.QPoint(k,k)
        self.paint.drawEllipse(center,radx,rady)
        self.paint.end()


class Window(QtGui.QMainWindow, QtGui.QGraphicsView):
    def __init__(self):
        super(Window,self).__init__()

        # GUI Setup
        self.myWid = QtGui.QWidget()

        # Establish a Vertical Box Layout
        # The layout will be a vertical box layout comprised of horizontal
        # box layouts
        self.vbox_fullDisplay = QtGui.QVBoxLayout()


        # Add a Zero-width spacer-item before the area where the
        # text label will appear
        #self.vbox_fullDisplay.addStretch(1)

        ###############################
        # Build horizontal box layout #
        ###############################
        self.hbox_top = QtGui.QHBoxLayout()
        # The text should be centered on the screen so zero-width
        # spacer items will be added to the left and right of the label
        #self.hbox_top.addStretch(1)

        self.top_text_label = QtGui.QLabel(self)
        self.top_text_label.setFont(QtGui.QFont("Times",32,QtGui.QFont.Bold))
        self.top_text_label.setText("Top of window")
        self.top_text_label.adjustSize()
        self.hbox_top.addWidget(self.top_text_label)

        #self.hbox_top.addStretch(1)

        # Add the horizontal box layout to the vertical box layout
        self.vbox_fullDisplay.addLayout(self.hbox_top)

        # Add space between the text and the row of circles
        #self.vbox_fullDisplay.addStretch(1)

        ############################
        # Build the row of buttons #
        ############################
        self.hbox_buttons = QtGui.QHBoxLayout()
        # The text should be centered on the screen so zero-width
        # spacer items will be added to the left and right of the label
        #self.hbox_buttons.addStretch(1)

        # These buttons will be used to toggle the color of the circles
        btn1 = QtGui.QPushButton('Circle 1')
        btn1.clicked.connect(self.circle1Meth)

        btn2 = QtGui.QPushButton('Circle 2')
        btn2.clicked.connect(self.circle2Meth)

        self.hbox_buttons.addWidget(btn1)
        #self.hbox_buttons.addStretch(1)
        self.hbox_buttons.addWidget(btn2)
        #self.hbox_buttons.addStretch(1)

        # Add the horizontal box layout to the vertical box layout
        self.vbox_fullDisplay.addLayout(self.hbox_buttons)

        # Add space between the text and the row of circles
        #self.vbox_fullDisplay.addStretch(1)

        ############################
        # Build the row of circles #
        ############################
        self.hbox_circles = QtGui.QHBoxLayout()
        #self.hbox_circles.addStretch(1)
        self.__circleColors = ['red','green']
        self.__circle1Color = 0;
        self.circle1 = DrawCircle(self.__circleColors[self.__circle1Color])
        print("const draw circ2")
        self.__circle2Color = 1
        self.circle2 = DrawCircle(self.__circleColors[self.__circle2Color])

        self.hbox_circles.addWidget(self.circle1)
        #self.hbox_circles.addStretch(1)
        self.hbox_circles.addWidget(self.circle2)
        #self.hbox_circles.addStretch(1)

        # Add the row of circles to the vertical box layout
        self.vbox_fullDisplay.addLayout(self.hbox_circles)

        # Add space between the circles and the slot machine pictures
        #self.vbox_fullDisplay.addStretch(1)

        self.bottomLabel = QtGui.QLabel(self)
        self.bottomLabel.setText("Bottom Of GUI")
        self.bottomLabel.adjustSize()
        self.vbox_fullDisplay.addWidget(self.bottomLabel)

        self.myWid.setLayout(self.vbox_fullDisplay)
        self.setCentralWidget(self.myWid)

        self.setGeometry(100,200,600,500)
        self.setWindowTitle('Does this work')

    def circle1Meth(self):
        print("Circ1 change")
        if self.__circle1Color == 1:
            self.__circle1Color = 0
        else:
            self.__circle1Color = 1

        # Set the color for circle 1
        self.circle1.setColor(self.__circleColors[self.__circle1Color])

        # force a repaint by updating the widget Using the repaint() method
        # could cause infinite recursion
        self.update()

    def circle2Meth(self):
        print("Circ2 change")
        if self.__circle2Color == 1:
            self.__circle2Color = 0
        else:
            self.__circle2Color = 1

        # Set the color for circle 1
        self.circle2.setColor(self.__circleColors[self.__circle2Color])

        # force a repaint by updating the widget Using the repaint() method
        # could cause infinite recursion
        self.update()

###
# Run GUI
###
app = QtGui.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())

当您使用 addStrech() 时,布局将使用 sizeHint() 作为尺寸,因为未设置尺寸所以它不可见,解决方案是设置 属性。另一个建议是不要将 QPainter 设为 class 的成员,因为它不可避免地会消耗内存,只需将其设为局部变量即可。另一个建议是你在 setColor() 方法中调用 update() 并且它不会节省你的代码行并且你有一个更清晰的代码。

class DrawCircle(QtGui.QWidget):
    def __init__(self, color, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.color = color

    def setColor(self,color):
        self.color = color
        self.update()

    def paintEvent(self,event):
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        radx = 5
        rady = radx
        if self.color in ('red', 'green'):
            col = QtGui.QColor(self.color)
            painter.setPen(col)
            painter.setBrush(col)
        k = int(radx * 1.5)
        center = QtCore.QPoint(k,k)
        painter.drawEllipse(center,radx,rady)

    def sizeHint(self):
        return QtCore.QSize(15, 15)