首页 > 解决方案 > Recursion Error on PyQt QStackedWidget when using enterEvent and leaveEvent

问题描述

I am using a QStackedWidget which has its own enterEvent and leaveEvent. When I move my mouse to the QStackedWidget the enterEvent sets the current index to 1 and on the leaveEvent it sets the current index to 0 so that a different widget is shown on mouse enter and mouse leave in the area of QStackedWidget. It does what I want only if I quickly move my mouse in and out, if I place my mouse too long in the area I get RecursionError: maximum recursion depth exceeded.

Is this because the widgets are changing so fast that the internal stack can't keep up? My question is "How can I make sure this error doesn't occur? I want to display one widget as long as the mouse is over the QStackedWidget and when it is not I want to display the original widget."

The following is the code that I modified (Original Source used buttons to set the index and it is PyQt4)

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTimeLine
from PyQt5.QtGui import *

class FaderWidget(QWidget):

    def __init__(self, old_widget, new_widget):
        QWidget.__init__(self, new_widget)
        self.old_pixmap = QPixmap(new_widget.size())
        old_widget.render(self.old_pixmap)
        self.pixmap_opacity = 1.0
        self.timeline = QTimeLine()
        self.timeline.valueChanged.connect(self.animate)
        self.timeline.finished.connect(self.close)
        self.timeline.setDuration(333)
        self.timeline.start()

        self.resize(new_widget.size())
        self.show()


    def animate(self, value):

        self.pixmap_opacity = 1.0 - value
        self.repaint()

class StackedWidget(QStackedWidget):

    def __init__(self, parent = None):
        QStackedWidget.__init__(self, parent)

    def setCurrentIndex(self, index):
        self.fader_widget = FaderWidget(self.currentWidget(), self.widget(index))
        super().setCurrentIndex(index)

    def enterEvent(self,event):
        self.setCurrentIndex(1)

    def leaveEvent(self,event):
        self.setCurrentIndex(0)


if __name__ == "__main__":

    app = QApplication(sys.argv)

    window = QWidget()

    stack = StackedWidget()
    cal=QCalendarWidget()
    stack.addWidget(cal)
    editor = QTextEdit()
    editor.setPlainText("Hello world! "*100)
    stack.addWidget(editor)

    layout = QGridLayout(window)
    layout.addWidget(stack, 0, 0, 1, 2)

    window.show()
    sys.exit(app.exec_())

标签: pythonpyqt5

解决方案


发生递归是因为当您启动 FaderWidget 时,它会更改焦点并再次调用 enterEvent,从而创建一个新的 FaderWidget。

解决方法是验证旧索引与新索引不同,只创建FadeWidget:

import sys

from PyQt5.QtCore import QTimeLine
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtWidgets import (
    QApplication,
    QCalendarWidget,
    QGridLayout,
    QStackedWidget,
    QTextEdit,
    QWidget,
)


class FaderWidget(QWidget):
    def __init__(self, old_widget, new_widget):
        QWidget.__init__(self, new_widget)
        self.pixmap_opacity = 1.0
        self.old_pixmap = QPixmap(new_widget.size())
        old_widget.render(self.old_pixmap)

        self.timeline = QTimeLine()
        self.timeline.valueChanged.connect(self.animate)
        self.timeline.finished.connect(self.close)
        self.timeline.setDuration(333)
        self.timeline.start()

        self.resize(new_widget.size())
        self.show()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setOpacity(self.pixmap_opacity)
        painter.drawPixmap(0, 0, self.old_pixmap)

    def animate(self, value):
        self.pixmap_opacity = 1.0 - value
        self.update()


class StackedWidget(QStackedWidget):
    def setCurrentIndex(self, index):
        if self.currentIndex() != index:
            self.fader_widget = FaderWidget(self.currentWidget(), self.widget(index))
        super().setCurrentIndex(index)

    def enterEvent(self, event):
        self.setCurrentIndex(1)

    def leaveEvent(self, event):
        self.setCurrentIndex(0)


if __name__ == "__main__":

    app = QApplication(sys.argv)

    window = QWidget()

    stack = StackedWidget()
    cal = QCalendarWidget()
    stack.addWidget(cal)
    editor = QTextEdit()
    editor.setPlainText("Hello world! " * 100)
    stack.addWidget(editor)

    layout = QGridLayout(window)
    layout.addWidget(stack, 0, 0, 1, 2)

    window.show()
    sys.exit(app.exec_())

推荐阅读