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

1. 简述

上一篇文章讲述了新界面的搭建思路以及如何进行不同界面的切换。本来关于如何使用代码来进行修改图片和文字是想在最后一篇文章进行介绍,但基于可能同学们对这方面有兴趣,下面会给出简单的示例,而具体的操作还是会放在最后一篇文章里面讲解。本篇文章还会讲一下“武汉大学建筑知识系统”的数据库构造。

2. 用代码修改图片和文字

  1. 修改图片
    I. 修改普通图片(如后缀为 .png.jpg 等类型的图片)
    用到 setPixmap 方法,而图片对象用 QPixmap 获取:

    # 修改静态图片(图片地址最好采用相对路径,绝对路径很大可能不可用于其他电脑,因为别人的用户名不会和你是一样的)
    self.ui.label_pre.setPixmap(QPixmap(f"./images/buildings/{content[1]}.jpg"))
    self.ui.label_pre.setMaximumSize(QSize(711, 400))	# 设置一下图片显示大小
    

    II. 修改动图(如后缀为 .gif 类型的图片)
    用到 setMovie 方法,而动图对象用 QMovie 获取:

    self.movie = QMovie("./images/background/loading.gif")	# 获取动图
    self.ui.label_pre.setMaximumSize(QSize(124, 124))	# 设置一下图片显示大小
    # 修改动态图片(图片地址最好采用相对路径,绝对路径很大可能不可用于其他电脑,因为别人的用户名不会和你是一样的)
    self.ui.label_pre.setMovie(self.movie)
    self.movie.start()	# 启动动图播放(不加这句话将不显示动图)
    
  2. 修改文字
    I. 方法一(不推荐,用的是 pyuic5 转换后的提供代码进行改写)
    用到 setHtml 方法,感觉有些麻烦,当时第一次接触所以用了这个方法:

    _translate = QCoreApplication.translate
    self.ui.textBrowser.setHtml(_translate("Form",
                                           "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
                                           "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
                                           "p, li { white-space: pre-wrap; }\n"
                                           "</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
                                           f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">建筑名</span><span style=\" font-size:12pt;\">:{content[2]}</span></p>\n"
                                           f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">类  别:</span><span style=\" font-size:12pt;\">{content[3]}</span></p>\n"
                                           "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">简  介:</span></p>\n"
                                           f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt;\">    {content[4]}</span></p>\n"
                                           f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">地  址:</span><span style=\" font-size:12pt;\">{content[5]}</span></p></body></html>"))
    

    II. 方法二(推荐)
    用到 setText 方法,少写了一些代码,而实现的功能是完全一样的,除了 textBrowserLabel 以及 Button 的文字修改也是用 setText 方法,大家要熟练掌握

    self.ui.textBrowser.setText("<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
                                "p, li { white-space: pre-wrap; }\n"
                                "</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
                                f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">建筑名</span><span style=\" font-size:12pt;\">:{content[2]}</span></p>\n"
                                f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">类  别:</span><span style=\" font-size:12pt;\">{content[3]}</span></p>\n"
                                "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">简  介:</span></p>\n"
                                f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt;\">    {content[4]}</span></p>\n"
                                f"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:12pt; font-weight:600;\">地  址:</span><span style=\" font-size:12pt;\">{content[5]}</span></p></body></html>")
    

    :上述文字用的是 HTML 的样式,因为默认的字体大小以及样式不好,大家可以自学 HTML 等网页语言来美化文字,当然也可以直接在 designer 里面修改文字获取 HTML 样式!下面给出如何在 designer 里面获取 HTML 样式:

    先在拖出的 textBrowser 控件上面“右键”,选择“改变 HTML ”(或者改变多信息文本),修改好格式:

    在这里插入图片描述
    然后点击,就有相应的 HTML 代码了,但是不建议在这里进行复制,建议通过 pyuic5 命令把 ui 文件转为 py 文件后,在 py 文件里面进行复制,因为 py 文件会把格式给你转换好(比如字符串里面有单引号、双引号时会帮你加上转义字符,不用手动增加)。

    源
    但是这种是不是感觉有点麻烦,如果有很多文本框都需要修改,那么就要加入很多这种很长的语句,其实还有一种方法,就是自定义控件。只要在 designer 中提升控件,这样就不用一个个设置了,包括控件的 QSS 样式也不用一个一个在 designer 里面设计,同时自定义控件还可以在以后的软件中重复使用。但是自定义控件对于小白来说不好掌握(难点),所以这里就不再介绍,感兴趣的同学可以自行学习!

3. 数据库 sqlite3

数据库 sqlite3 是大家电脑自带的一个数据库,无须下载安装,当然其有一定的缺点:任何人拿到你的数据库文件都可以修改,没有安全性可言,不过对于我们的这种不涉及用户隐私的软件就不用用到太高级的数据库了。如果大家是做签到系统那个项目的话,我建议不要用这个数据库,可以MySQL 这样安全性高的数据库,在听展示的时候,做这个项目的小组没介绍他们使用的数据库,所以我也不清楚他们用的是什么数据库。

那么有同学会问为什么要用数据库呢?我用 Excel 或者 txt 不行吗?答案当然是可以的!但是一旦数据量太大,Excel 的打开速度将会很慢(我实测过,在打开大小为 8 MB 的“森林背词”词汇表时,用时大概是5秒)。不过对于我们这种数据信息不多的时候用什么进行存储数据都可以。

下面只对我们项目用到的数据库增查操作来介绍,删改操作部分感兴趣的同学可自行了解(其实就是 SQL 语句的变化,主要的 python 代码操作是差不多的)。

  1. 创建数据库
    我们用 sqlite3.connect(数据库名称【包括后缀】)连接一个指定数据库如果没有检测到这个数据库,它会帮你创建一个空的数据库。用 cursor() 方法对数据库进行操作(相当于实例化一个对象吧)。

    execute() 方法是指对数据库要做哪些操作命令,里面一般输入的是 SQL 语句。为节省篇幅,这里不再介绍 SQL 语句怎么写。

    commit() 方法是指提交事务sqlite3Python 中的操作都是以事务进行的。

    close() 方法是关闭数据库,这句话不能少,要养成习惯,每次用完数据库要关闭

    确定要显示的建筑信息后,我确定了要存储的内容为:id(主键),name_pre(建筑简称——模型预测时的输出),name_cn(建筑全名),category(所属类别——食堂、图书馆、教学楼、院楼、体育馆等建筑类别),introduction(建筑简介),location(地址),location_url(地址链接——用于导航)。

    下面给出我们的数据库创建的代码:

    def buildDatabase():
        """
        创建数据库:buildings.db
        :return: NULL
        """
        conn = sqlite3.connect('buildings.db')  # 如果没有这个数据库,则创建这个数据库,然后连接数据库
        cur = conn.cursor()  # 对数据库操作就是对cur操作
    
        # 数据库定义各属性(创建一个表)
        cur.execute('''
            CREATE TABLE IF NOT EXISTS buildings(
            id              INT     not null,
            name_pre        TEXT    not null,
            name_cn         TEXT    not null,
            category        TEXT    not null,
            introduction    TEXT    not null,
            location        TEXT    not null,
            location_url    TEXT    not null,
            PRIMARY KEY (id));''')
    
        conn.commit()   # 保存数据库(因为新建了一个表)
        conn.close()    # 关闭数据库
    
  2. 增加数据
    增加数据大部分代码和创建数据库差不多,不同的地方是插入之前需要判断数据库里面是否已经有要插入的内容(防止重复插入数据)。那么有很多方法来检测是否有重复插入的数据,我采用的是一种比较简单,但是不合规范的策略!就是按照插入数据的 id 与数据库的行数进行比较,如果要插入的数据 id 小于行数,则说明数据库里面已经有这个数据,那么停止插入;否则就插入新数据。

    但是有个 bug,这个 bug 主要是由人为原因引起。因为我是先把数据存在 Excel 里面,再存储到数据库里面,那么如果我在 Excel 开头新增了一个数据,那么到数据库这边认为 id0 的数据存在,反而最后一条旧数据因为前面新增了一条数据,它的 id 加一,此时数据库会将这条旧数据误以为新数据插入到数据库中。即新数据没插入,旧数据重复插入,但是因为数据库是我自己创建更新的,所以我可以手动删除数据库,重新运行程序就会生成正确的数据库。下面给出几种解决此问题的方法供大家参考与实践:
    (1)将上面我的手动操作改为自动操作;
    (2)新增数据库操作,结合操作修改内容,但是这种方法时间复杂度高,不建议用于大型项目;
    (3)那就是从我们自己出发,在新增 Excel 内容时,必须从末尾添加数据。

    到这里不知道有没有同学有疑惑呢?就是我既然用了 Excel 存储数据,为什么又用数据库存储一遍呢,这样不是相当于有 2 份数据了吗?有这个疑问的同学很好,因为你学会了思考,其实在我上传的源代码里面确实有 2 份一模一样的的数据。因为这是课程项目,所以我会把所有操作都尽量保存下来,但是在真正开发的过程中,我是不会把 Excel 的内容发给你的,我只会把生成好的数据库文件(buildings.db)发给你。

    下面是插入数据的相关代码:

    def insertValue(content):
        """
        向数据库中插入内容
        :param content: 是一个列表,为要插入的数据内容
        :return: NULL
        """
        conn = sqlite3.connect('buildings.db')  # 连接数据库
        cur = conn.cursor()  # 对数据库进行操作
    
        cur.execute('''SELECT COUNT(*) FROM buildings;''')  # 计算当前数据库已有数据行数
        row_count = int(cur.fetchone()[0])  # 返回当前数据库已有数据行数
    
        if content[0] >= row_count:   # 如果插入的数据不在数据库中(大于数据库行的数据),则允许插入
            # 此处存在bug,即若数据在原数据excel中间插入,无法在新数据库中插入此条信息,而是插入最后一条信息(重复插入)
            # 不过由于此数据库由我们自行创建,所以可以人为避免此情况发生(不清楚是否重复插入时,可以将.db文件删除,再运行此脚本,将产生新的正确的数据库)
            # 插入 id, name_pre, name_cn, category, introduction, location, location_url
            cur.execute('''INSERT INTO buildings(
                        id, name_pre, name_cn, category, introduction, location, location_url)
                        VALUES (?, ?, ?, ?, ?, ?, ?);''', content)
    
            conn.commit()  # 保存数据库
    
        conn.close()  # 关闭数据库
    

    拓展fetchone() 指只取出一条符合条件的数据;要取出全部符合条件的数据可以用 fetchall();要取出不多于指定数目且符合条件的数据可以用 fetchmany(size)size 是指定不多于此数的数据数目。

  3. 查看数据
    接下来到查看数据步骤。在查看数据前,我们必须确保数据库是存在的,所以我会先运行数据库插入数据的操作(即 run())。但是在真正的项目开发里面,验证过程不是输入数据,而是判断这个叫 buildings.db 的数据库是否存在。那么这个判断操作怎么实现呢?给你们一个思路:通过 os 模块获取指定目录的文件名,看文件名是否在指定的路径里面,如果不存在,那一定用户删除了(因为软件开发好后,所有的内容都是打包好的,那么数据库文件是一定存在的)。

    比如我在开发“森林背词”的时候,数据一般是放在文件夹 db 里面,那么这时候只要检测文件夹 db 里面有没有我要运行的数据库文件就可以了。
    在这里插入图片描述
    下面给出“武汉大学建筑知识系统”的查看数据代码(以根据建筑预测名进行查找为示例):

    def run():
        """
        每次查询前都要确保数据库存在
        :return: NULL
        """
        buildDatabase()
        df = pd.read_excel('buildings.xlsx', engine="openpyxl")  # 读取建筑信息
        for i in range(len(df)):
            value = [int(df.at[i, 'id']), df.at[i, 'name_pre'], df.at[i, 'name_cn'],
                     df.at[i, 'category'], df.at[i, 'introduction'], df.at[i, 'location'], df.at[i, 'location_url']]
            insertValue(value)
    
    
    def gainContent_name_pre(name_pre):
        """
        获取数据库内容
        :param name_pre: 要查询的建筑预测名
        :return: contents,一个列表(要查询的建筑在数据库中的所有信息)
        """
        run()	# 插入数据
        conn = sqlite3.connect('buildings.db')
        cur = conn.cursor()
    
        cur.execute(f'''
            SELECT * FROM buildings
            WHERE name_pre = '{name_pre}';''')
    
        contents = cur.fetchone()
        conn.close()
        return contents
    

4. 预告

好的,那么本篇文章就结束啦!今天主要讲解了如何用代码修改图片与文字以及数据库的使用,下一篇文章将会讲解浏览界面的优化(将下拉框和显示全部建筑名修改为滑动栏),要是有时间的话还会讲讲怎么对控件进行 QSS 美化。而“导航”操作应该会在下下篇文章进行介绍。

那我们下一篇文章见啦~

上一篇文章传送门:【PyQt5 实战项目1】武汉大学建筑知识系统–思路分享4(软件版本1.1.2介绍之新界面搭建与界面跳转)

下一篇文章传送门:【PyQt5 实战项目1】武汉大学建筑知识系统–思路分享6(优化浏览界面以及为我们的控件添加QSS样式)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值