本文为浙江大学数据库系统课程lab5进行图书管理系统设计过程中的经验总结
——zju gehao

问题的提出和基本前提

网上找了半天也没发现什么靠谱的解答,自己捣鼓着花费了好几个小时,总算是发现了两种能用的方法,先假设一下使用的场景:现在窗口的右半部分有两个界面想要切换显示

我们主体窗口的控件为self.main_widget,网格布局为self.main_layout,分为左右两部分:

  • 布局的左半部分为self.left_widget,它的作用是导航栏(标签和按钮),因此有一个就足够了
  • 布局的右半部分是self.right_widget,我想通过点击不同的按钮让这个区域显示不同的界面,但由于一个Qwidget只能容纳一组layout的布局,因此怎么切换界面是一个很令人苦恼的问题

我总结出了两种思路:

首先前提是,必须要有2个(或者两个以上的界面),每一个界面我都用一个Qwidget来表示,这个Qwidget里面可以使用QGridlayout网格布局(或者其他布局)来存放各种各样不同的子控件,比如按钮、标签、文本框等

假设我已经准备好了self.right_widget1和self.right_widget2,整体布局、左侧布局和右侧两个界面的布局如下所示:

class MainUi(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        '''
        初始化整体布局
        '''
        self.resize(1000, 800)
        self.desktopWidth = QApplication.desktop().width()  # 获取当前桌面的宽
        self.desktopHeight = QApplication.desktop().height()  # 获取当前桌面的高

        self.main_widget = QWidget()  # 创建窗口主部件
        self.main_widget.setObjectName('main_widget')  # 对象命名
        self.main_layout = QGridLayout()  # 创建网格布局的对象
        self.main_widget.setLayout(self.main_layout)  # 将主部件设置为网格布局

        self.init_left()  # 初始化左侧空间
        self.init_right()  # 初始化右侧空间

        # 将初始化完成的左侧、右侧空间加入整体空间的网格布局
        self.main_layout.addWidget(self.left_widget, 0, 0, 1, 1)
        self.main_layout.addWidget(self.right_widget1, 0, 1, 1, 6)
        #self.main_layout.addWidget(self.right_widget2, 0, 1, 1, 6)
        self.setCentralWidget(self.main_widget)  # 设置窗口主部件
    
    def init_left(self):
        '''
        初始化左侧布局
        '''
        self.left_widget = QWidget()  # 创建左侧部件
        self.left_widget.setObjectName('left_widget')  # 左侧部件对象命名
        self.left_layout = QGridLayout()  # 创建网格布局对象
        self.left_widget.setLayout(self.left_layout)  # 将左侧部件设置为网格布局
      	# 接下来添加按钮控件等...,细节略  
        
    def init_right(self):
        '''
        初始化右侧布局
        '''
        self.right_widget1 = QWidget()  # 创建右侧界面1
        self.right_layout1 = QGridLayout()  # 创建网格布局对象1
        self.right_widget1.setLayout(self.right_layout1)  # 设置右侧界面1的布局为网格布局
        self.Button1 = QPushButton() # 加一个用来界面跳转的button1
        self.Button1.setText("进入界面2")
        self.right_layout1.addWidget(self.Button1)
        
        self.right_widget2 = QWidget()  # 创建右侧界面2
        self.right_layout2 = QGridLayout()  # 创建网格布局对象2
        self.right_widget2.setLayout(self.right_layout2)  # 设置右侧界面2的布局为网格布局
        self.Button2 = QPushButton() # 加一个用来界面跳转的button2
        self.Button2.setText("进入界面1")
        self.right_layout2.addWidget(self.Button2)
        
        # 把切换界面的button和两个跳转函数绑定
        self.Button1.clicked.connect(self.clicked_1)
        self.Button2.clicked.connect(self.clicked_2)

现在的目标就是如何实现两个按钮的跳转函数去实现右侧两个界面的跳转,有两种思路:

解决方法
第一种思路:

首先随便选择一个widget(比如self.right_widget1)放到一开始的显示界面上,也就是上面的这句话

self.main_layout.addWidget(self.right_widget1, 0, 1, 1, 6)

然后当我点击该界面上的按钮Button1时,我从self.main_layout中删去这个self.right_widget1界面,再把self.right_widget2界面创建好并添加到self.main_layout布局里去,此时main布局的右侧就从界面1变成了界面2;想要从界面2跳转回界面1也是同样的道理,就先删去界面2的widget,再创建好界面1的widget并加入总布局里即可

# import sip
def clicked_1(self):
    # 删除界面1
    self.main_layout.removeWidget(self.right_widget1)
    sip.delete(self.right_widget1)
    # 创建界面2
    self.right_widget2 = QWidget()  # 创建右侧界面2
    self.right_layout2 = QGridLayout()  # 创建网格布局对象2
    self.right_widget2.setLayout(self.right_layout2)  # 设置右侧界面2的布局为网格布局
    self.Button2 = QPushButton() # 加一个用来界面跳转的button2
    self.Button2.setText("进入界面1")
    self.right_layout2.addWidget(self.Button2)
    # 添加界面2到总布局里
    self.main_layout.addWidget(self.right_widget2, 0, 1, 1, 6)
    
def clicked_2(self):
    # 删除界面2
    self.main_layout.removeWidget(self.right_widget2)
    sip.delete(self.right_widget2)
    # 创建界面1
    self.right_widget1 = QWidget()  # 创建右侧界面1
    self.right_layout1 = QGridLayout()  # 创建网格布局对象1
    self.right_widget1.setLayout(self.right_layout1)  # 设置右侧界面2的布局为网格布局
    self.Button1 = QPushButton() # 加一个用来界面跳转的button1
    self.Button1.setText("进入界面2")
    self.right_layout1.addWidget(self.Button1)
    # 添加界面1到总布局里
    self.main_layout.addWidget(self.right_widget1, 0, 1, 1, 6)

注意光使用self.main_layout.removeWidget(self.right_widget)好像并不能把widget删除,还需要加一句sip.delete(self.right_widget)才行(需要import sip),这种方法有一种缺点,想必你也发现了,就是每次切换页面都要删除原先的界面并新建想要跳转的界面,可是我们一般情况下并不希望每次跳转都删除、创建不变的东西,那会耗费更多的资源,导致更慢的速度,我们更希望用不到它的时候把它隐藏起来,当需要的时候再显示出来,这就是方法二的思路

第二种思路:

我们把所有的界面同时放在main的布局里的同一个位置,并且每次隐藏其他界面,只显示其中的一个,当我们想要切换界面的时候,其实就只要把原先显示的界面隐藏,想要显示的界面显示出来即可

当然此时一开始的代码要改一下,以便所有的界面都同时添加到main的右侧布局里:

self.main_layout.addWidget(self.right_widget1, 0, 1, 1, 6)
self.main_layout.addWidget(self.right_widget2, 0, 1, 1, 6)

然后只需要两个函数:Qwidget.hide()和Qwidget.show()

def clicked_1(self):
    self.right_widget1.hide() # 隐藏界面1
    self.right_widget2.show() # 显示界面2

def clicked_2(self):
    self.right_widget2.hide() # 隐藏界面2
    self.right_widget1.show() # 显示界面1

圆满解决!

这里随便选两个界面展示一下效果:

  • 第一个界面
  • 第二个界面