如何刷新Qwidget以显示当前信息?

发布于 2025-01-23 07:27:50 字数 2722 浏览 0 评论 0原文

我有一个Pyside2 GUI,该GUI接受了第一页的用户的数字,然后进行一些计算,并在第二页上显示结果。每个页面都是qstackedwidget中的Qwidget。第二页的“结果”页面上有一个按钮,该页面将用户发送回第一页以输入新号码。

我的问题是,当我输入新数时,结果永远不会从第一个数字变化。我使用打印语句确认结果页面上的标签正在更新,但显示器保持不变。

# importing the module
import os
import sys
from PySide2 import QtWidgets
import PySide2.QtUiTools as QtUiTools


class IncomeScreen(QtWidgets.QMainWindow):
    def __init__(self):
        super(IncomeScreen, self).__init__()

        # Load the IncomeScreen ui
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "main.ui")
        self.main = loader.load(path, self)

        # Connect the signals with custom slots
        self.main.calculate_pushButton.clicked.connect(self.calculate)

    def calculate(self):
        init_amount = self.main.income_lineEdit.text()
        IncomeScreen.init_amount = float(init_amount)
        # Create an instance of DistributionScreen class
        self.distribution = DistributionScreen()
        # Add DistributionScreen to the stacked widget
        widget.addWidget(self.distribution)
        # Change index to show DownloadPage
        widget.setCurrentIndex(widget.currentIndex()+1)


class DistributionScreen(QtWidgets.QMainWindow):
    def __init__(self):
        super(DistributionScreen, self).__init__()
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "dialog.ui")
        self.dialog = loader.load(path, self)

        # Set initial amount to label
        self.dialog.initialAmount_label.setText(str(IncomeScreen.init_amount))
        print("Initial Amount = {:0.2f}".format(IncomeScreen.init_amount))

        # 10 Percent
        ten = IncomeScreen.init_amount * 0.1
        print("10% = {:0.2f}".format(ten))
        self.dialog.label_10percent.setText("{:0.2f}".format(ten))
        print(self.dialog.label_10percent.text())

        # 20 percent
        twenty = IncomeScreen.init_amount * 0.2
        print("20% = {:0.2f}".format(twenty))
        self.dialog.label_20percent.setText("{:0.2f}".format(twenty))
        print(self.dialog.label_20percent.text())

        # Update widget
        self.dialog.update()

        # Connect the signals with custom slots
        self.dialog.reset_pushButton.clicked.connect(self.reset)

    def reset(self):
        print("reset")
        # Change index to show IncomeScreen
        widget.setCurrentIndex(widget.currentIndex()-1)


# main
# if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
income = IncomeScreen()
widget = QtWidgets.QStackedWidget()
widget.addWidget(income)
widget.show()
try:
    sys.exit(app.exec_())
except:
    print("Exiting")

另外,我正在使用Python 3.7.4

编辑:您可以下载UI文件

I have a PySide2 GUI that accepts a number from the user on page one then does some calculations and displays the results on page two. Each page is a QWidget within a QStackedWidget. There is a pushbutton on page two, the results page, that sends the user back to page one to enter a new number.

My problem is that when I enter a new number the results never change from the first number. I use print statements to confirm that the labels on the results page are updating but the display stays the same.

# importing the module
import os
import sys
from PySide2 import QtWidgets
import PySide2.QtUiTools as QtUiTools


class IncomeScreen(QtWidgets.QMainWindow):
    def __init__(self):
        super(IncomeScreen, self).__init__()

        # Load the IncomeScreen ui
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "main.ui")
        self.main = loader.load(path, self)

        # Connect the signals with custom slots
        self.main.calculate_pushButton.clicked.connect(self.calculate)

    def calculate(self):
        init_amount = self.main.income_lineEdit.text()
        IncomeScreen.init_amount = float(init_amount)
        # Create an instance of DistributionScreen class
        self.distribution = DistributionScreen()
        # Add DistributionScreen to the stacked widget
        widget.addWidget(self.distribution)
        # Change index to show DownloadPage
        widget.setCurrentIndex(widget.currentIndex()+1)


class DistributionScreen(QtWidgets.QMainWindow):
    def __init__(self):
        super(DistributionScreen, self).__init__()
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "dialog.ui")
        self.dialog = loader.load(path, self)

        # Set initial amount to label
        self.dialog.initialAmount_label.setText(str(IncomeScreen.init_amount))
        print("Initial Amount = {:0.2f}".format(IncomeScreen.init_amount))

        # 10 Percent
        ten = IncomeScreen.init_amount * 0.1
        print("10% = {:0.2f}".format(ten))
        self.dialog.label_10percent.setText("{:0.2f}".format(ten))
        print(self.dialog.label_10percent.text())

        # 20 percent
        twenty = IncomeScreen.init_amount * 0.2
        print("20% = {:0.2f}".format(twenty))
        self.dialog.label_20percent.setText("{:0.2f}".format(twenty))
        print(self.dialog.label_20percent.text())

        # Update widget
        self.dialog.update()

        # Connect the signals with custom slots
        self.dialog.reset_pushButton.clicked.connect(self.reset)

    def reset(self):
        print("reset")
        # Change index to show IncomeScreen
        widget.setCurrentIndex(widget.currentIndex()-1)


# main
# if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
income = IncomeScreen()
widget = QtWidgets.QStackedWidget()
widget.addWidget(income)
widget.show()
try:
    sys.exit(app.exec_())
except:
    print("Exiting")

Also I'm using Python 3.7.4

EDIT: You can download the ui files here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

指尖上的星空 2025-01-30 07:27:50

您的代码有各种问题,但最重要的是,每次都称为,一个新的distributionscreen it 添加到堆叠widget,但是widget.setCurrentIndex(widget.currentIndex()+1)将始终转到堆叠式窗口的 second index(这是 first em>您创建的实例)。

可能的简单解决方法可能是使用addwidget返回的小部件的索引或使用setCurrentWidget

    def calculate(self):
        init_amount = self.main.income_lineEdit.text()
        IncomeScreen.init_amount = float(init_amount)
        self.distribution = DistributionScreen()
        index = widget.addWidget(self.distribution)
        widget.setCurrentIndex(index)
        # alternatively:
        widget.setCurrentWidget(self.distribution)

不幸的是,虽然这会使您的代码工作,但它不是有效的解决方案,但由于还有其他重要问题,这些问题迟早会造成其他问题:

  • 一个堆叠的小部件像tab窗口小部件一样工作:它旨在允许小部件的可重复使用性;您不应该每次都会不断创建一个新实例,而应该使用现有的实例;
  • 您应该不设置或使用class属性作为取决于实例的变量(就像使用Incomemescreen.init_amount一样);
  • 您正在将QMainWindows添加到一个堆叠的小部件中,因为主窗口应用作顶级窗口(它具有依赖于该方面的功能);请注意,即使是Qdialog也不是有效的候选人,您应该选择基本的Qwidget或Qframe或Qgroupbox之类的容器。
  • 您正在使用quiloader作为主窗口的孩子加载小部件,而是不将其添加到布局(或设置为中央窗口小部件),这将使它无法在任何时候调整大小调整了顶级窗口:如果主窗口变得太小,则某些内容将看不到,如果它太大,则会有很多未使用的空间;
  • 您正在尝试从一个实例访问全局变量(widget),而不能保证该变量是有效的;无论如何,它应该不是 是创建新小部件并设置堆叠式小部件的索引的实例,而是堆叠的小部件本身(或其任何祖先);
  • 最后一个尝试/除块非常危险,因为它可以防止您捕获异常(因为它是通用除外:),或者知道程序崩溃时出了什么问题;

这是您的代码的可能修订(未经测试,因为您没有提供ui文件)。

import os
import sys
from PySide2 import QtWidgets, QtCore
import PySide2.QtUiTools as QtUiTools


class IncomeScreen(QtWidgets.QWidget):
    # a custom signal to notify that we want to show the distribution page
    # with the provided value
    goToDistribution = QtCore.Signal(float)
    def __init__(self):
        super(IncomeScreen, self).__init__()

        # Load the IncomeScreen ui
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "main.ui")
        self.main = loader.load(path, self)

        # a proper layout that manages the contents loaded with QUiLoader
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.main)

        # Connect the signals with custom slots
        self.main.calculate_pushButton.clicked.connect(self.calculate)

    def calculate(self):
        init_amount = self.main.income_lineEdit.text()
        self.goToDistribution.emit(float(init_amount))


class DistributionScreen(QtWidgets.QWidget):
    reset = QtCore.Signal()
    def __init__(self):
        super(DistributionScreen, self).__init__()
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "dialog.ui")
        self.dialog = loader.load(path, self)

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.dialog)

        self.dialog.reset_pushButton.clicked.connect(self.reset)

    def setIncome(self, value):
        # Set initial amount to label
        self.dialog.initialAmount_label.setText(str(value))
        print("Initial Amount = {:0.2f}".format(value))

        # 10 Percent
        ten = value * 0.1
        print("10% = {:0.2f}".format(ten))
        self.dialog.label_10percent.setText("{:0.2f}".format(ten))
        print(self.dialog.label_10percent.text())

        # 20 percent
        twenty = value * 0.2
        print("20% = {:0.2f}".format(twenty))
        self.dialog.label_20percent.setText("{:0.2f}".format(twenty))
        print(self.dialog.label_20percent.text())


class MainWidget(QtWidgets.QStackedWidget):
    def __init__(self):
        super(MainWidget, self).__init__()
        # create *both* the pages here
        self.income = IncomeScreen()
        self.addWidget(self.income)
        self.distribution = DistributionScreen()
        self.addWidget(self.distribution)

        self.income.goToDistribution.connect(self.goToDistribution)
        self.distribution.reset.connect(self.reset)

    def goToDistribution(self, value):
        # we received the notification signal, then we set the value and 
        # show the related page by switching to it
        self.distribution.setIncome(value)
        self.setCurrentWidget(self.distribution)

    def reset(self):
        self.setCurrentWidget(self.income)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWidget = MainWidget()
    mainWidget.show()
    sys.exit(app.exec_())

请注意:

  • 如果需要数字控件,则应使用 qspinbox or 或a href =“ https://doc.qt.io/qt-5/qdoublespinbox.html” rel =“ nofollow noreferrer”> qdoublespinbox (对于浮点数),或设置a qintvalidator
  • 尽管Quiloader很有用,但它具有始终创建小部件的缺点,因此您永远无法覆盖其方法。解决此问题的唯一解决方案是使用pyside-uic生成的文件,并使用多重继承方法,或切换到PYQT并使用其uic.loadui current widget上的UI;
  • 代码中的大多数问题都是由于最近共享的一些教程(YouTube上的一些教程):不幸的是,这些教程表明 很多可怕的东西 对于Pyqt和Python,应该做 不是 。我强烈建议您寻找其他资源,最重要的是,始终研究文档。

There are various problems with your code, but the most important one is that every time calculate is called, a new DistributionScreen is added to the stacked widget, but widget.setCurrentIndex(widget.currentIndex()+1) will always go to the second index of the stacked widget (which is the first instance you created).

A possible simple workaround could be to use the index of the widget returned by addWidget or use setCurrentWidget:

    def calculate(self):
        init_amount = self.main.income_lineEdit.text()
        IncomeScreen.init_amount = float(init_amount)
        self.distribution = DistributionScreen()
        index = widget.addWidget(self.distribution)
        widget.setCurrentIndex(index)
        # alternatively:
        widget.setCurrentWidget(self.distribution)

Unfortunately, while this would make your code work, it's not a valid solution, as there are other important issues that would create other problems sooner or later:

  • a stacked widget works like a tab widget: it's intended to allow reusability of the widgets; you should not constantly create a new instance every time, but possibly use the existing one;
  • you should not set nor use a class attribute for a variable that depends on an instance (as you did with IncomeScreen.init_amount);
  • you're adding QMainWindows to a stacked widget, which is discouraged, as a main window should be used as a top level window (it has features that rely on that aspect); note that even QDialog is not a valid candidate, and you should opt for a basic QWidget or a container like QFrame or QGroupBox;
  • you're using QUiLoader to load the widget as a child of the main window, but without adding it to a layout (or setting as central widget), and this will make it unable to resize itself whenever the top level window is resized: if the main window becomes too small, some of the contents won't be visible, if it's too big there will be a lot of unused space;
  • you're trying to access a global variable (widget) from an instance, while it's not guaranteed that the variable would be valid; in any case, it should not be the instance to create new widgets and set the index of the stacked widget, but the stacked widget itself (or any of its ancestors);
  • the last try/except block is very dangerous, as it prevents you to capture exceptions (since it's a generic except:) or know what was wrong with your program if it crashes;

This is a possible revision of your code (untested, as you didn't provide the ui files).

import os
import sys
from PySide2 import QtWidgets, QtCore
import PySide2.QtUiTools as QtUiTools


class IncomeScreen(QtWidgets.QWidget):
    # a custom signal to notify that we want to show the distribution page
    # with the provided value
    goToDistribution = QtCore.Signal(float)
    def __init__(self):
        super(IncomeScreen, self).__init__()

        # Load the IncomeScreen ui
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "main.ui")
        self.main = loader.load(path, self)

        # a proper layout that manages the contents loaded with QUiLoader
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.main)

        # Connect the signals with custom slots
        self.main.calculate_pushButton.clicked.connect(self.calculate)

    def calculate(self):
        init_amount = self.main.income_lineEdit.text()
        self.goToDistribution.emit(float(init_amount))


class DistributionScreen(QtWidgets.QWidget):
    reset = QtCore.Signal()
    def __init__(self):
        super(DistributionScreen, self).__init__()
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "dialog.ui")
        self.dialog = loader.load(path, self)

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.dialog)

        self.dialog.reset_pushButton.clicked.connect(self.reset)

    def setIncome(self, value):
        # Set initial amount to label
        self.dialog.initialAmount_label.setText(str(value))
        print("Initial Amount = {:0.2f}".format(value))

        # 10 Percent
        ten = value * 0.1
        print("10% = {:0.2f}".format(ten))
        self.dialog.label_10percent.setText("{:0.2f}".format(ten))
        print(self.dialog.label_10percent.text())

        # 20 percent
        twenty = value * 0.2
        print("20% = {:0.2f}".format(twenty))
        self.dialog.label_20percent.setText("{:0.2f}".format(twenty))
        print(self.dialog.label_20percent.text())


class MainWidget(QtWidgets.QStackedWidget):
    def __init__(self):
        super(MainWidget, self).__init__()
        # create *both* the pages here
        self.income = IncomeScreen()
        self.addWidget(self.income)
        self.distribution = DistributionScreen()
        self.addWidget(self.distribution)

        self.income.goToDistribution.connect(self.goToDistribution)
        self.distribution.reset.connect(self.reset)

    def goToDistribution(self, value):
        # we received the notification signal, then we set the value and 
        # show the related page by switching to it
        self.distribution.setIncome(value)
        self.setCurrentWidget(self.distribution)

    def reset(self):
        self.setCurrentWidget(self.income)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWidget = MainWidget()
    mainWidget.show()
    sys.exit(app.exec_())

Note that:

  • if you want a numeric control, you should use QSpinBox or QDoubleSpinBox (for floating point numbers), or set a QIntValidator or QDoubleValidator, otherwise if the user enters a non numeric value your program will crash (due to the usage of float() done without previously checking if the string is actually a valid number);
  • while QUiLoader is useful, it has the drawback of always creating a widget, so you can never override its methods; the only solution to this is to use files generated by pyside-uic and use the multiple inheritance method, or switch to PyQt and use its uic.loadUi which instead allows setting up the UI on the current widget;
  • most of the problems in your code are due to some tutorials that have been shared lately (some of them on youtube): unfortunately, those tutorials suggest a lot of terrible things that should not be done, both for PyQt and Python; I strongly suggest you to look for other resources and, most importantly, always study the documentation.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文