Search code examples
pythonpysidepyside6

PySide6: The errors "Fatal Python error: Cannot recover from stack overflow" occurrs when I use my custom class' rewritten function sizeHint()


I imatates QT's official documentation to write a calcuator example.

I try to rewrite the source code into python and make some changes. My code is as blow:

import sys

from PySide6.QtWidgets import (QApplication, QSizePolicy, QWidget, QToolButton, QGridLayout)
from PySide6 import QtCore


class Advanced_Calculator(QWidget):
    def __init__(self):
        super(Advanced_Calculator, self).__init__()

        self.mainwindow = QGridLayout(self)

        # Digit buttons and operator buttons

        self.widget_button = QWidget()

        self.button_digit = []

        for i in range(0, 10):
            self.button_digit.append(Button(str(i)))

        self.button_factor = Button("!")
        self.button_lbracket = Button("(")
        self.button_rbracket = Button(")")
        self.button_backspace = Button("<-")
        self.button_division = Button("/")
        self.button_log = Button("log")
        self.button_multiply = Button("X")
        self.button_sqrt = Button("√")
        self.button_minus = Button("-")
        self.button_power = Button("^")
        self.button_plus = Button("+")
        self.button_abs = Button("|x|")
        self.button_const = Button("Const")
        self.button_dot = Button(".")
        self.button_equal = Button("=")

        # Buttons layout with 0 spacing

        self.layout_button = QGridLayout()
        self.layout_button.setSpacing(0)

        self.layout_button.addWidget(self.button_factor, 0, 0, 1, 1)
        self.layout_button.addWidget(self.button_lbracket, 0, 1, 1, 1)
        self.layout_button.addWidget(self.button_rbracket, 0, 2, 1, 1)
        self.layout_button.addWidget(self.button_backspace, 0, 3, 1, 1)
        self.layout_button.addWidget(self.button_division, 0, 4, 1, 1)
        self.layout_button.addWidget(self.button_log, 1, 0, 1, 1)

        for i in range(1, 10):
            self.layout_button.addWidget(self.button_digit[i], 3 - ((i - 1) // 3), (i - 1) % 3 + 1, 1, 1)

        self.layout_button.addWidget(self.button_multiply, 1, 4, 1, 1)
        self.layout_button.addWidget(self.button_sqrt, 2, 0, 1, 1)
        self.layout_button.addWidget(self.button_minus, 2, 4, 1, 1)
        self.layout_button.addWidget(self.button_power, 3, 0, 1, 1)
        self.layout_button.addWidget(self.button_plus, 3, 4, 1, 1)
        self.layout_button.addWidget(self.button_power, 3, 0, 1, 1)
        self.layout_button.addWidget(self.button_power, 3, 0, 1, 1)
        self.layout_button.addWidget(self.button_power, 3, 0, 1, 1)
        self.layout_button.addWidget(self.button_power, 3, 0, 1, 1)
        self.layout_button.addWidget(self.button_abs, 4, 0, 1, 1)
        self.layout_button.addWidget(self.button_const, 4, 1, 1, 1)
        self.layout_button.addWidget(self.button_digit[0], 4, 2, 1, 1)
        self.layout_button.addWidget(self.button_dot, 4, 3, 1, 1)
        self.layout_button.addWidget(self.button_equal, 4, 4, 1, 1)

        self.widget_button.setLayout(self.layout_button)

        # button layout set to mainwindow

        self.mainwindow.addWidget(self.widget_button)


class Button(QToolButton):
    def __init__(self, text, parent=None):
        super(Button, self).__init__(parent)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.setText(text)

    def sizeHint(self) -> QtCore.QSize:
        size = self.sizeHint()
        size.setHeight(size.height + 20)
        size.setWidth(max(size.width(), size.height()))
        # size.rheight() += 20
        # size.rwidth() = max(size.width(), size.height())

        return size


if __name__ == "__main__":
    app = QApplication([])

    Calculator = Advanced_Calculator()
    Calculator.show()

    sys.exit(app.exec())

When I debug these code, the "Fatal Python error: Cannot recover from stack overflow" occurs. And now it is known to me that the error is caused by the sizeHint() function. Where is the problem?

By the way, the function was rewrite by me with my comprehending of the sizeHint() function. And the official documentation uses the two lines code blow which I made them comments, and it doesn't work, too. Well, I also can't figure out where is the problem.


Solution

  • Consider the code...

    def sizeHint(self) -> QtCore.QSize:
        size = self.sizeHint()
        size.setHeight(size.height + 20)
        size.setWidth(max(size.width(), size.height()))
        # size.rheight() += 20
        # size.rwidth() = max(size.width(), size.height())
    
        return size
    

    The line...

    size = self.sizeHint()
    

    causes Button::sizeHint to call itself leading to infinite recursion and, hence, a stack overflow. Perhaps you meant to call the base class implementation instead...

    size = super(Button, self).sizeHint()