mda
mda

Reputation: 95

How to change window/widget with PyQt5 using .ui files?

first of all thanks for your time and sorry for the question length, the real question is just the first part. I can't understand ho to realize a 'page' change, like a web application. I would like to do that using .ui files, representing widgets or main windows. Basically, I would like to have two classes, each one mapped with an .ui file implementing a view, and switch between the two views when a button is clicked.

I would like to have is something like that:

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_()

After lots of researches I wrote the code below that almost realize that, I said almost because I must use the same class for all. What I want instead is to have one .py file for each .ui file to keep things separated.

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_()

And this is the code for both .ui files, just change the filename to home.ui and second.ui, and change btn text to see the page change. They are simple widgets with one button each

<?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>

Upvotes: 1

Views: 8114

Answers (1)

musicamante
musicamante

Reputation: 48489

What you need to do is to create separate widgets (not windows). While this is already covered in other similar questions (like this, I'll answer anyway due to the different files request.

The solution is still the same, using a QStackedWidget, that allows you to switch between different widgets that occupy the same part of the window, similarly to what QTabWidget does, but without the tab bar.

First, you need to create a main window in designer, add a QStackedWidget there and ensure that you remove all of its pages (right click on the stacked widget, and select "Delete" in the "Page x of x" sub menu).
Then create separate widgets (just select "Widget" in the dialog that appears when creating a new form) for each page.

Finally, use loadUi on the main window and on each child widget. I'll recommend you to keep the logic of the page switching in the code of the main window, instead of having it in the different pages, as it's a better and cleaner approach having a "parent" controller when dealing with this situations.

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)

There is also the possibility of using QWizard, but it's usually suggested for more complex cases than yours.

Upvotes: 3

Related Questions