【PyQt5 实战项目1】武汉大学建筑知识系统--思路分享4(软件版本1.1.2介绍之新界面搭建与界面跳转)

1. 简述

接上篇文章,我们讲解了软件第一个主版本的开发思路以及给了一些相关代码供大家学习,对于第一个主版本,我们的思路是不是开发了主要的几个功能:用户上传图片并保存、显示建筑的相关信息(文字简介以及建筑图片)、导航(将在后续讲解,这里留个坑)。那么对于这些基础功能开发完毕后,我们是不是可以开始美化我们的界面了,通过几个小时去浏览别人开发的软件界面,我也对我们这个软件的大致界面有了一个思路,同学们也可以现在去看几个别人开发的软件或者网页,再回来看我的思路,看看距离我的思路相差多少,又或者会比我的思路好多少!

2. 新界面构建思路

面对首次开发软件,不知道大家有没有一种想法是和我一样的,就是想把所有内容都放进去,比如放一些自我感觉很牛的东西进去给大家展示,从而产生一种优越感。要是有这种想法的同学,恭喜你进入了老师的扣分或者加分范围的边缘了。为什么说是边缘呢?因为这要看你加入的东西是否有价值了,那么什么东西有价值,什么东西没价值呢?之后会一一叙述我的个人观点。(注意是我自己的个人观点,不一定正确!

现在就给大家看看我的新界面搭建思路吧~

  1. 首页
    对于自己制作的一款软件,当然是想打开软件的第一眼就是给用户看到我们的团队以及我们软件有哪些优势吧!于是制作的第一个界面首当其冲就是我们的主页,主页要显示的内容有哪些呢?(1)我们的软件名字肯定要吧,而且必须加粗加大字体,让它变的很显眼;(2)我们的软件有哪些功能很突出,有哪些很牛的地方是不是也要放上来装一下 ^ _ ^;(3)我们的团队成员辛苦了这么久,那不得把大伙的名字放在中间最显眼的位置,让大家记住我们;(4)一些提示信息以及我们的软件版本号也要放上来吧。于是我们的首页如下图:

    首页
    嘿嘿,这时点头的同学,恭喜你进入老师的扣分范围内啦~

    有的同学就会问为什么扣分咧?我觉得也没什么吧,“唔通装一下都唔畀”?因为软件开发秉持的是用户至上的观念,用户是上帝,我们应该从用户的角度出发去设计软件,能在这之前想到这点的同学(厉害!!),试想一个用户打开你的软件,就这样一个画面在眼前,然后也不消失,还要用户通过点击识别才能跳转他要的功能(拜托,我只是想来看看武汉大学的建筑和你识别的准确度而已…)

    所以,这也是在展示时被老师提出的一个问题!那么有什么办法解决呢?(1)直接把首页删除,这也是我后期优化的一部分;(2)如果你真的想保留这部分,那请把这部分的内容设置为定时显示,即用户打开界面之后显示 2 秒就自动进入识别界面(相当于很多软件的初始化界面)。

    那么为什么当时没选第二种方法呢?原因是展示介绍后只剩下 10 来天的时间去优化,而且恰好进入提前考试周(大多数课程都在 16 周结束那天随堂考试),没啥时间再去了解以及优化(而且之后也会讲到要优化的地方不止这一个,所以要选择性价比最高的功能去优化),因此直接删除首页是最快的方法!

    如果有的同学对第二种方法感兴趣的话可以自行搜索,这里也给出一种解决方法,即用到 PyQt5.QtCore 下的 QTimer

    from PyQt5.QtCore import QTimer
    
    QTimer.singleShot(1000, 类方法)
    # 示例:QTimer.singleShot(1000, self.login)
    # 1000 指的是时间 1 秒(毫秒为单位)
    # 类方法是你要显示内容的函数(比如我自定义的叫做 self.login)
    # 注意:上面的类方法调用时(不加!不加!不加!)括号,即写成 self.login,而不是 self.login()
    

    那么具体要实现的内容就让同学们自己实现啦~

  2. 识别
    接下来是不是就是我们的识别界面啦!

    识别
    这个界面是不是和我们的版本 1.0.0 很像!没错,这页的设计其实就是基于我们第一版的设计稍微加了几个 Label 控件用来显示文字,同时由于用户没有上传图片,所以两个显示图片的内容就是“用户未上传图片”,而对于按钮格式是不是也做出了一些修改,再加上图标的加持,比之前的按钮好看很多吧~

  3. 浏览
    设计了识别界面,当时我就在想,用户也许还想看看武汉大学有哪些建筑呀(新增功能),所以我们的软件不能局限于老师提到的那几个功能,就像我们的微信,从一开始的聊天到现在能网购、导航一样。而且浏览界面的代码是不是应该和我们的识别界面差不多啊,也是显示建筑图片、建筑信息以及导航嘛,那么不同点就是我们要把我们数据库中有的建筑弄一个按钮出来给用户选择吧,所以代码量其实就是多了提取所有建筑制作成按钮吧(别看这感觉很难,在 PyQt5 中就是几句话的事情,因为已经有现成的控件给你使用了)。于是浏览界面就设计成下面这样:

    浏览
    下面讲讲和识别界面的不同点:
    (1) 把上传图片按钮改成了下拉框按钮,即 designerInput Widgets 下的 comboBox

    在这里插入图片描述
    但是这点也被老师指出可优化的地方,就是既然因为下拉框要每次点击才能选择,同时为了让用户知道我们有什么建筑,又在左下角写出我们支持的建筑,那为什么不直接用滑动框来实现呢?说实话,当时我也想过,但是因为没仔细了解过 designer 里面的所有控件,所以一直没找到实现的方法。重点来啦:第一篇文章就提到要熟悉 designer 里面提供的所有控件,把每个控件拖出来看一遍,你们做到了吗?如果做到了就会知道这个优化的控件了!在最后一个版本将会讲解。

    (2)只显示一张图片,那就是建筑的图片。本来是想做自动滑动图片显示的,就是那种一张张图片从左到右依次滑动显示,但是基于时间限制就没开发,同学们可以自己尝试!

    (3)右侧是输出建筑文字内容的,那为什么截图中是一堆看不懂的东西啊。因为这还是调试阶段,这时候我们的模型还没出来,所以为了测试软件的正确性,我一般会把用到的信息输出到前端来 debug,同时这里面的内容是来自于我们构建的数据库的(下一篇文章将介绍关于数据库相关的内容)。

  4. 关于
    最后就是我们的关于界面啦,你在不同的软件是不是都看见过“关于”之类的界面,所以我也开发了这个界面。

    关于
    这里主要是进行一些声明、更新日志以及介绍,那么看到这个,是不是发现首页是完全多余的!首页的内容可以放到这里来。

  5. 退出
    这里的退出不再是一个界面了,而是我们整个软件的结束出口之一(我们也可以通过左上角双击两下或者右上角关闭)。

    退出代码如下:

    @pyqtSlot()
    def on_btn_quit_clicked(self):
        self.btn_style_init()
        self.ui.btn_quit.setStyleSheet(
            "QPushButton { font:14pt \"Agency FB\";background-color: rgba(69, 139, 116, 255); color: rgb(255, 255, 255);}\n"
            "QPushButton:hover { background-color: rgba(69, 139, 116, 255); color: rgb(255, 255, 255);}\n"
            "QPushButton:pressed { font:14pt \"Agency FB\";background-color: rgba(69, 139, 116, 255); color: rgb(255, 255, 255);}")
        filePath = '.\\images\\background\\predict.png'
        image = QImage(filePath)
        image.save('.\\images\\predict\\predict.jpg', "JPG", 100)
        self.close()
    

    可以看见这里提供的代码主要实现了几个功能:
    (1)重新初始化其他按钮格式以及自身按钮格式,其实现在看来根本没必要!
    (2)我们重置了用户上传的图片,因为用户上传图片后会被我们保存在指定地方,然后在这个指定地方提取图片来进行预测。所以在退出后,为了用户隐私性,我们会把这里的图片恢复为“用户暂未上传图片”的那张图片(即删除用户上传的图片),就是我们进入识别界面时显示的图片!

    当然大家也可以用之前提到的 connect 方法来实现!至于 setStyleSheet 后面的内容其实就是 QSS 样式,用于美化我们的按钮、界面,在这里不会专门讲解(在最后一篇文章“收官之作”中会有些许介绍),感兴趣的同学自行搜索相关内容进行学习!

3. 界面跳转

看到这里,是不是有个问题,就是我们的每个界面显示的内容都讲了,但是怎么实现跳转呢?因为上篇文章说了我们 不采用 新增窗口这种方法,那么我用的就是 designer 中的 stackedWidget 实现的。

在这里插入图片描述

下面给出在 designer 的设计步骤之一,拖出 stackedWidget 后右上角有箭头是控制翻页的。因为它默认只给你两页,所以想要增加页可以在右箭头上面右键就有插入页了。

在这里插入图片描述
那么怎么在代码中实现翻页呢?基础代码是:

self.ui.stackedWidget.setCurrentIndex(0)

# self.ui 是我的 UI 对象
# stackedWidget 是我的 objectName(见下图)
# setCurrentIndex(0) 是指翻到第几页,第一页是从 0 开始计算的,和数组下标一样

属性编辑器
那么页面怎么和按钮进行交互(连接)呢?

那么下面给出一个简单的示例,如果要查看本软件的界面跳转代码请看第一篇文章给出的源代码链接地址(GiteeCSDN 中都有)。
先创建一个 py 文件叫 ui3.py,然后输入以下代码:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(522, 222)
        self.gridLayout = QtWidgets.QGridLayout(Form)
        self.gridLayout.setObjectName("gridLayout")
        self.frame = QtWidgets.QFrame(Form)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth())
        self.frame.setSizePolicy(sizePolicy)
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
        self.verticalLayout.setObjectName("verticalLayout")
        self.pushButton = QtWidgets.QPushButton(self.frame)
        self.pushButton.setObjectName("pushButton")
        self.verticalLayout.addWidget(self.pushButton)
        self.pushButton_2 = QtWidgets.QPushButton(self.frame)
        self.pushButton_2.setObjectName("pushButton_2")
        self.verticalLayout.addWidget(self.pushButton_2)
        self.pushButton_3 = QtWidgets.QPushButton(self.frame)
        self.pushButton_3.setObjectName("pushButton_3")
        self.verticalLayout.addWidget(self.pushButton_3)
        spacerItem = QtWidgets.QSpacerItem(20, 68, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)
        self.btn_quit = QtWidgets.QPushButton(self.frame)
        self.btn_quit.setObjectName("btn_quit")
        self.verticalLayout.addWidget(self.btn_quit)
        self.gridLayout.addWidget(self.frame, 0, 0, 1, 1)
        self.frame_2 = QtWidgets.QFrame(Form)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(5)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth())
        self.frame_2.setSizePolicy(sizePolicy)
        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_2.setObjectName("frame_2")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.frame_2)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.stackedWidget = QtWidgets.QStackedWidget(self.frame_2)
        self.stackedWidget.setObjectName("stackedWidget")
        self.page = QtWidgets.QWidget()
        self.page.setObjectName("page")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label = QtWidgets.QLabel(self.page)
        self.label.setObjectName("label")
        self.verticalLayout_2.addWidget(self.label)
        self.stackedWidget.addWidget(self.page)
        self.page_2 = QtWidgets.QWidget()
        self.page_2.setObjectName("page_2")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.page_2)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.label_2 = QtWidgets.QLabel(self.page_2)
        self.label_2.setObjectName("label_2")
        self.gridLayout_3.addWidget(self.label_2, 0, 0, 1, 1)
        self.stackedWidget.addWidget(self.page_2)
        self.page_3 = QtWidgets.QWidget()
        self.page_3.setObjectName("page_3")
        self.gridLayout_4 = QtWidgets.QGridLayout(self.page_3)
        self.gridLayout_4.setObjectName("gridLayout_4")
        self.label_3 = QtWidgets.QLabel(self.page_3)
        self.label_3.setObjectName("label_3")
        self.gridLayout_4.addWidget(self.label_3, 0, 0, 1, 1)
        self.stackedWidget.addWidget(self.page_3)
        self.gridLayout_2.addWidget(self.stackedWidget, 0, 0, 1, 1)
        self.gridLayout.addWidget(self.frame_2, 0, 1, 1, 1)

        self.retranslateUi(Form)
        self.stackedWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.pushButton.setText(_translate("Form", "1"))
        self.pushButton_2.setText(_translate("Form", "2"))
        self.pushButton_3.setText(_translate("Form", "3"))
        self.btn_quit.setText(_translate("Form", "退出"))
        self.label.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt;\">我是第一页</span></p></body></html>"))
        self.label_2.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt;\">我是第二页</span></p></body></html>"))
        self.label_3.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt;\">我是第三页</span></p></body></html>"))

再创建一个 py 文件叫 main3.py,输入以下代码:

import sys

from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import pyqtSlot

from ui3 import Ui_Form


class QmyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数,创建窗体
        self.ui = Ui_Form()  # 创建UI对象
        self.ui.setupUi(self)  # 构造UI界面
        self.setWindowTitle("武汉大学建筑知识系统")  # 设置程序窗口名称

    @pyqtSlot()
    def on_pushButton_clicked(self):
        self.ui.stackedWidget.setCurrentIndex(0)

    @pyqtSlot()
    def on_pushButton_2_clicked(self):
        self.ui.stackedWidget.setCurrentIndex(1)

    @pyqtSlot()
    def on_pushButton_3_clicked(self):
        self.ui.stackedWidget.setCurrentIndex(2)

    @pyqtSlot()
    def on_btn_quit_clicked(self):
        """退出按钮"""
        self.close()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = QmyWidget()
    w.show()
    sys.exit(app.exec())

同学们可以根据示例代码自行修改,同时本示例代码用的是 @pyqtSlot() 方法,同学们可自行修改为 connect 方法尝试一下!同时可以给按钮增加 QSS 样式进行美化哦~

拓展:不知道你有没有注意到上面最后一行代码是 sys.exit(app.exec()),发现是不是和前几篇文章不一样啦,前几张文章都是 sys.exit(app.exec_()),那么这里为什么进行了修改呢?因为 PyQt 在不断更新后,开始不支持 exec_ 这种写法了,所以这里提一下,但是我们的源代码还是采用 exec_ 这种写法的(PyQt5 还是支持的,但处于弃用状态,而 PyQt6 好像就完全不支持了)。

4. 预告

好啦,本篇文章到此结束,今天主要讲了新界面的构造思路以及如何切换不同界面来显示不同的内容,下篇文章将会讲解我们的一个主要内容(重点)——数据库的搭建以及数据库的内容设定!

那么要看下一篇的同学,我希望你掌握 SQL 语句的相关知识点,因为本软件的数据库将会用到系统自带的 sqlite3sqlite3 用的就是 SQL 语句进行数据库的增删改查,相信大家应该都修了 MySQL 这门课了,没修的可以自己上网了解(比如:菜鸟教程),那我们下一篇文章见~

上一篇文章传送门:【PyQt5 实战项目1】武汉大学建筑知识系统–思路分享3(软件版本1.0.0介绍之显示预测的建筑信息、图片)

下一篇文章传送门:【PyQt5 实战项目1】武汉大学建筑知识系统–思路分享5(如何用代码修改图片与文字以及数据库的使用)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值