【问题标题】:How to change window/widget with PyQt5 using .ui files?如何使用 .ui 文件使用 PyQt5 更改窗口/小部件?
【发布时间】:2020-07-09 07:15:59
【问题描述】:

首先感谢您抽出宝贵时间,抱歉问题太长了,真正的问题只是第一部分。 我无法理解如何实现“页面”更改,例如 Web 应用程序。 我想使用代表小部件或主窗口的 .ui 文件来做到这一点。 基本上,我希望有两个类,每个类都映射有一个实现视图的 .ui 文件,并在单击按钮时在两个视图之间切换。

我想要的是这样的:

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        # then load the home page file home.ui

class HomePage:
    def method_0(self):
        # method to load and show the home.ui file, at startup

    def method_1(self):
        # method to load and show the home.ui file, when a button in Second Page is pressed

class SecondPage
    def method_1(self):
        # method to load and show the second.ui file when a button in HomePage is pressed

if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

经过大量研究,我编写了下面的代码,几乎意识到,我说几乎是因为我必须为所有人使用同一个类。相反,我想要的是为每个 .ui 文件创建一个 .py 文件以保持分离。

from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow, QStackedWidget

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.resize(800, 620)
        self.central_widget = QStackedWidget()
        self.setCentralWidget(self.central_widget)
        self.home_page()

    def home_page(self):
        widget = uic.loadUi('home.ui')
        self.central_widget.addWidget(widget)
        self.central_widget.setCurrentWidget(widget)
        widget.change_btn.clicked.connect(self.second_page)

    def second_page(self):
        widget = uic.loadUi('second.ui')
        self.central_widget.addWidget(widget)
        self.central_widget.setCurrentWidget(widget)
        widget.change_btn.clicked.connect(self.home_page)


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

这是两个 .ui 文件的代码,只需将文件名更改为 home.uisecond.ui,并更改 btn 文本以查看页面更改。它们是简单的小部件,每个都有一个按钮

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>620</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Application</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <property name="title" stdset="0">
    <string>GroupBox</string>
   </property>
   <widget class="QPushButton" name="change_btn">
    <property name="geometry">
     <rect>
      <x>285</x>
      <y>170</y>
      <width>230</width>
      <height>40</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>12</pointsize>
     </font>
    </property>
    <property name="text">
     <string>Change page</string>
    </property>
   </widget>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

【问题讨论】:

  • 我不确定我是否完全理解你。您想要一个单个主窗口,并显示应该加载自己的 .ui 文件的不同“页面”,并在单独的文件中加载这些“页面”的代码?
  • 是的,完全正确。它不必是“单个主窗口”,如果它工作一切都很好,但我不希望用户看到窗口关闭并重新打开新页面(当我尝试使用时发生在我身上两个主窗口)
  • 例如一个带有 {HomePage} 类的 'Home.py' 文件,它加载 'home.ui 文件并具有按钮功能的方法,最重要的是转到另一个类的方法另一个 .ui 代码。我现在拥有的代码没有针对不同页面的不同类。

标签: python user-interface pyqt pyqt5


【解决方案1】:

您需要做的是创建单独的小部件(不是窗口)。虽然其他类似问题(如this)已经涵盖了这一点,但由于文件请求不同,我还是会回答。

解决方案还是一样的,使用QStackedWidget,它允许您在占据窗口相同部分的不同小部件之间切换,类似于 QTabWidget 所做的,但没有标签栏。

首先,您需要在设计器中创建一个主窗口,在其中添加一个 QStackedWidget 并确保删除其所有页面(右键单击堆叠的小部件,然后在“第 x 页,共 x 页”子菜单)。
然后为每个页面创建单独的widgets(只需在创建新表单时出现的对话框中选择“Widget”)。

最后,在主窗口和每个子窗口小部件上使用loadUi。 我建议您将页面切换的逻辑保留在主窗口的代码中,而不是将其放在不同的页面中,因为在处理这种情况时,使用“父”控制器是一种更好、更简洁的方法。

pages.py:

from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow

from first import First
from second import Second

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi('pages.ui', self)
        self.first = First()
        self.stackedWidget.addWidget(self.first)
        self.first.change_btn.clicked.connect(self.go_to_second)
        self.second = Second()
        self.stackedWidget.addWidget(self.second)
        self.second.change_btn.clicked.connect(self.go_to_first)

    def go_to_first(self):
        self.stackedWidget.setCurrentIndex(0)

    def go_to_second(self):
        self.stackedWidget.setCurrentIndex(1)


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

first.py

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget

class First(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        uic.loadUi('first.ui', self)

second.py

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget

class Second(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        uic.loadUi('second.ui', self)

也可以使用QWizard,但通常建议用于比您的情况更复杂的情况。

【讨论】:

  • 谢谢你,这正是我想要的。只是另一个问题,以确保我正确理解您:您建议将所有切换小部件逻辑编码到主窗口中,并在单个小部件类中编码小部件本身的逻辑,对吗?如果我将使用 10-12 个小部件,这也有效吗?最后,我是否必须关心堆叠的小部件长度?或者我可以在其中放入任意数量的小部件?再次感谢您的宝贵时间。
  • @mda 是的,完全正确:您应该始终(或至少,只要有可能)将逻辑保留在执行它的对象中。小部件的所有内部对象在它们之间进行交互都将在类中这样做,您应该只在 other 类之间进行交互时对父类进行操作(例如在您的情况下,更改页面),否则将所有内容放在不同的类中没有多大意义。如果您有类似的小部件,您可以对自己的子类进行子类化。除了 ram 和 int 之外,小部件的数量“理论上”没有限制。
猜你喜欢
  • 2019-09-14
  • 2021-08-29
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
  • 2016-12-23
  • 2020-10-16
  • 1970-01-01
相关资源
最近更新 更多