首页 > 编程语言 >基于pyqt5的番剧推荐小程序

基于pyqt5的番剧推荐小程序

时间:2023-05-17 12:23:28浏览次数:64  
标签:基于 font self pyqt5 textBrowser 设置 番剧 border setText

本文只为技术分享,无其他用途


前言:之前我完成了爬取番剧的爬虫实战,就想着基于爬取的数据,学习pyqt5做一个简易的窗口界面小程序,学的并不精深多有担待,以后技术精进了再优化优化。

主要实现: 分为主界面和另外3个副界面,main_window实现调用爬虫脚本初始化数据和跳转界面。random_window主要实现随机推送未看的番剧,包括番剧的图片、一些番剧信息和详情链接,用户可以标记已看和未看。recording_window主要实现记录用户已看的番剧,并显示用户的观看进度(即所看番剧数占比)。search_window主要实现支持用户的搜索服务,当然只是显示爬取的数据中的番剧信息。


准备

1.第三方库准备

 

sys、PyQt5.QtWidgets、PyQt.QtGui、PyQt.QtCore、pymysql、os

 

2. 数据库准备

我用的是Navicat 建立数据库

mysql建表:

 

CREATE TABLE Anime (
    Id VARCHAR (100 ) NOT NULL PRIMARY KEY,
    Link VARCHAR ( 100 ),
    Name_anime VARCHAR ( 100 ),
    Rank_anime CHAR ( 50 )  ,
    Episode VARCHAR ( 100 ) ,
    Date_time VARCHAR ( 300 ),
    Creator VARCHAR ( 200 ) ,
    Rating FLOAT ( 10 ) ,
    Person_num CHAR ( 40 ) ,
    Mark CHAR ( 10 ) 
);

 

 

 

 

Main_Window

成果:

 

 主要功能:

        调用爬虫脚本,进行数据准备,提供界面的跳转。

( 可以先使用Qt Deisinger构建出框架的大概模型,主要是设计好控件的位置,之后将ui文件用PyUic转化成py文件,开始详细设计,下文对Qt Deisinger不做详述。)

 

初始化

主要实现调用爬虫脚本初始化,考虑用messagebox来进行交互,点击初始化按钮会弹出对话框,因为初始化只能进行一次,所以会警告用户,然用户选择是否初始化,初始化成功会弹出显示成功的对话框。

 局部代码:

————设定自定义信号————

my_signal = pyqtSignal(str)   # 自定义信号

 

————设定子进程与对话框————

button1触发后,执行warning_box,设计用户交互是否执行脚本,监听进程的变化信号,选择Yes执行后,发出my_signal信号触发spider脚本,在脚本执行过程中,所有button暂时锁定不可用,鼠标样式改变

为wait样式,执行完成后,弹出提示框,初始化完成,所有button解锁可用,鼠标的样式恢复。

思路形成:

(1)开始想的是button1直接触发spider脚本,但想着初始化数据是只能进行一次的,所以就添加对话框来规避二次初始化,提醒用户的操作。

(2)对话框与用户交互,判断是否执行初始化,选择之后就要解决如何触发spider脚本,解决先对话框后脚本的事务执行,设计button1触发warning_box,判断对话框选择后,Yes则emit发出自定义信号my_signal,用my_signal触发脚本。数据初始化还没完成,所以执行脚本期间进行其他的界面操作没有数据也就没有意义,所以设置所用button暂时锁定不可用,设置鼠标演示为wait,来显示脚本执行中。

(3)接受信号后就想着如何监听脚本的过程,何时开始何时结束,建立子进程来执行spider脚本,用QPcess的readyRead和finished来监听进程的变化,readyRead来监听进程的输出变化,进程输出变化时发出信号触发槽函数process_output,finished来监听进程的结束,  进程结束时发出信号触发槽函数process_finished。在槽函数process_output里设计读取标准输出显示在终端,以便检验。在槽函数process_finished里设计提示框,提示初始化完成,重置鼠标样式,所有button解锁可用。

    def spider_clicked(self):
        # 暂时禁用按钮
        self.button1.setEnabled(False)
        self.button2.setEnabled(False)
        self.button3.setEnabled(False)
        self.button4.setEnabled(False)
        script_path = 'spider.py'  # 脚本路径
        process = QProcess(self)  # 创建QProcess对象
        process.setProcessChannelMode(QProcess.MergedChannels)   # 将子进程的标准输出和标准错误输出合并到主进程的标准输出中
        process.readyRead.connect(self.process_output)  # readyRead信号是QProcess类的一个信号在进程的输出发生变化时发出信号,将信号与函数process_output连接
        process.finished.connect(self.process_finished) # finished信号是QProcess类的一个信号,在进程执行完成时自动发出,将信号与函数process_finished连接
        process.start('python', [script_path])  # 运行进程

    def process_output(self):
        self.setCursor(Qt.WaitCursor)  # 设置鼠标为wait样式
        # 读取脚本的输出并显示在终端
        ob = self.sender()   # 获取信号的发送对象
        output = ob.readAllStandardOutput().data().decode()
        # readAllStandardOutput()方法读取脚本的标准输出,返回一个字节数组,使用data()方法获取字节数组中的数据,使用decode()方法将其解码成字符串
        print(output)


    def process_finished(self):
        msg_box = QMessageBox(self) # 创建对象
        msg_box.setWindowTitle('提示') # 设置标题
        msg_box.setText('初始化完成!')   # 设置文本
        msg_box.show()  # 展示提示框
        # 解封按钮,设置按钮可用
        self.button1.setEnabled(True)
        self.button2.setEnabled(True)
        self.button3.setEnabled(True)
        self.button4.setEnabled(True)
        self.unsetCursor()  # 重置鼠标样式

    def warning_box(self):
        msg = "初始化只可进行一次!确定要执行初始化吗?"
        reply = QMessageBox.question(self, "警告!", msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)  # 设置问答对话框
        if reply == QMessageBox.Yes:
            print("初始化开始")
            # 发送确定按钮被点击的信号
            self.my_signal.emit('Yes')
        else:
            print("初始化取消")

 

————设定初始化按钮样式————

button1触发warning_box,my_signal触发spider_clicked

        self.button1 = QPushButton(self)
        self.button1.setGeometry(90, 350, 100, 40)  # 设置位置和大小
        self.button1.setText("初始化")  # 设置文本
        self.button1.clicked.connect(self.warning_box) # 连接信号与槽
        self.my_signal.connect(self.spider_clicked)
        # 设置样式表,background用来设定背景颜色,border-radius用来设定边框的弧度,QPushButton:hover 鼠标悬停触发背景变化
        self.button1.setStyleSheet( '''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:orange;}''')

 

Tip:pyqt设计中为什么自定义信号要写在实例外?

在 PyQt 中,信号和槽(slot)是用于实现对象之间的通信的重要机制。信号是一种事件,当某个对象的状态发生变化时,它会发射一个信号,通知其他对象进行相应的处理。槽是一种连接到信号的函数,当接收到信号时,槽函数会被自动调用。

在PyQt中,自定义信号通常是通过继承QObject类并定义一个新的信号来实现的。当一个对象触发该信号时,它会向所有注册了该信号的对象发送信号。因此,如果自定义信号在类的实例内定义,那么每次创建一个新的类实例时,都会创建一个新的信号,这会导致信号的数量不断增加,而且会导致代码变得混乱。相反,将自定义信号定义在类的外部,可以确保每个类都有自己的信号,而不是每个实例都有自己的信号。这有助于提高代码的可读性和可维护性,并使代码更易于理解。

自定义信号通常需要在实例化对象之后才能使用。这是因为信号需要通过连接来传递,而连接只能在对象之间建立。如果信号定义在实例内部,那么只有该实例可以连接该信号,其他对象无法接收到该信号。因此,为了使信号可以在多个对象之间传递,我们需要将信号定义在实例外部。另外,自定义信号还可以使用 Q_SIGNALS 宏来声明信号,这样可以更好地管理信号的连接和删除。具体来说,Q_SIGNALS 宏会自动生成一个元类,用于管理信号的连接和删除。这样可以避免手动管理信号连接的问题,提高代码的可维护性和可扩展性。

(可以参考下这位博主的,(122条消息) Pyqt5系列(八)-自定义信号_pyqt 自定义信号_祝丰年的博客-CSDN博客))

 

QApplication(sys.argv) 是一个pyqt界面程序不可缺少的部分,QApplication是PyQt5中用于创建GUI应用程序的类,它提供了处理事件循环、窗口管理和用户交互等任务的方法和属性。sys.argv是一个包含命令行参数的列表,其中第一个元素是脚本文件名。在Python中,我们可以使用sys.argv来获取命令行参数并进行相应的处理。当我们使用QApplication(sys.argv)时,它会将sys.argv传递给它的构造函数,从而允许我们访问这些参数。 (可以参考这两位博主(124条消息) PyQt中主函数app=QApplication(sys.argv) sys.exit(app.exec_())的作用_app = qapplication(sys.argv)_cuicui_ruirui的博客-CSDN博客  和 为什么在创建QApplication实例时需要传递sys.argv - 掘金 (juejin.cn))  

全部代码:

import sys
from PyQt5.QtWidgets import *
from recording_window import recordingWindow
from search_window import searchWindow
from random_window import randomWindow
from  PyQt5.QtGui import QPixmap,QBrush,QPalette
from PyQt5.QtCore import *
import os


class MainWindow(QWidget):
    my_signal = pyqtSignal(str)   # 自定义信号
    def __init__(self):
        super().__init__()   # 继承父类
        self.main_ui()

    def spider_clicked(self):
        # 暂时禁用按钮
        self.button1.setEnabled(False)
        self.button2.setEnabled(False)
        self.button3.setEnabled(False)
        self.button4.setEnabled(False)
        script_path = 'spider.py'  # 脚本路径
        process = QProcess(self)  # 创建QProcess对象
        process.setProcessChannelMode(QProcess.MergedChannels)   # 将子进程的标准输出和标准错误输出合并到主进程的标准输出中
        process.readyRead.connect(self.process_output)  # readyRead信号是QProcess类的一个信号在进程的输出发生变化时发出信号,将信号与函数process_output连接
        process.finished.connect(self.process_finished) # finished信号是QProcess类的一个信号,在进程执行完成时自动发出,将信号与函数process_finished连接
        process.start('python', [script_path])  # 运行进程

    def process_output(self):
        self.setCursor(Qt.WaitCursor)  # 设置鼠标为wait样式
        # 读取脚本的输出并显示在终端
        ob = self.sender()   # 获取信号的发送对象
        output = ob.readAllStandardOutput().data().decode()
        # readAllStandardOutput()方法读取脚本的标准输出,返回一个字节数组,使用data()方法获取字节数组中的数据,使用decode()方法将其解码成字符串
        print(output)


    def process_finished(self):
        msg_box = QMessageBox(self) # 创建对象
        msg_box.setWindowTitle('提示') # 设置标题
        msg_box.setText('初始化完成!')   # 设置文本
        msg_box.show()  # 展示提示框
        # 解封按钮,设置按钮可用
        self.button1.setEnabled(True)
        self.button2.setEnabled(True)
        self.button3.setEnabled(True)
        self.button4.setEnabled(True)
        self.unsetCursor()  # 重置鼠标样式

    def warning_box(self):
        msg = "初始化只可进行一次!确定要执行初始化吗?"
        reply = QMessageBox.question(self, "警告!", msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)  # 设置问答对话框
        if reply == QMessageBox.Yes:
            print("初始化开始")
            # 发送确定按钮被点击的信号
            self.my_signal.emit('Yes')
        else:
            print("初始化取消")


    def main_ui(self):
        self.setWindowTitle("Anime Plan")  # 设置窗口边框栏字样
        self.setFixedSize(720, 405)  # 设置固定大小
        palette = QPalette()  # 调色板
        backImage = os.path.abspath('source/main.jpg')  # 背景的绝对路径
        # 设置背景图片,图片缩放并适应窗口大小,同时忽略图片宽高比
        palette.setBrush(self.backgroundRole(),QBrush(QPixmap(backImage).scaled(self.size(),Qt.IgnoreAspectRatio,Qt.SmoothTransformation)))
        self.setPalette(palette)
        # 初始化按钮
        self.button1 = QPushButton(self)
        self.button1.setGeometry(90, 350, 100, 40)  # 设置位置和大小
        self.button1.setText("初始化")  # 设置文本
        self.button1.clicked.connect(self.warning_box) # 连接信号与槽
        self.my_signal.connect(self.spider_clicked)
        # 设置样式表,background用来设定背景颜色,border-radius用来设定边框的弧度,QPushButton:hover 鼠标悬停触发背景变化
        self.button1.setStyleSheet( '''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:orange;}''')
        # ‘我的一番界’界面按钮
        self.button2 = QPushButton(self)
        self.button2.setGeometry(240, 350, 100, 40)
        self.button2.setText("我的一番")
        self.button2.setStyleSheet('''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:orange;}''')
        # ‘search’界面按钮
        self.button3 = QPushButton(self)
        self.button3.setGeometry(390, 350, 100, 40)
        self.button3.setText("Search")
        self.button3.setStyleSheet(  '''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:orange;}''')
        # ‘recording’界面按钮
        self.button4 = QPushButton(self)
        self.button4.setGeometry(540, 350, 100, 40)
        self.button4.setText("Recording")
        self.button4.setStyleSheet('''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:orange;}''')
        # 界面居中
        screen = QDesktopWidget().screenGeometry()   # 获取屏幕的几何信息,坐标和宽高
        size = self.geometry()  # 获取窗口的位置和大小
        newX = (screen.width() - size.width()) / 2
        newY = (screen.height() - size.height()) / 2
        self.move(int(newX), int(newY))  # 窗口居中



if __name__ =="__main__":
    # 实例化一个应用对象
    app =QApplication(sys.argv)
    # 实例化窗口
    m = MainWindow()
    Recording = recordingWindow()
    Random = randomWindow()
    Search = searchWindow()
    m.show()  # 展示界面
    # 将button与窗口连接,实现跳转
    m.button2.clicked.connect(Random.show)
    m.button3.clicked.connect(Search.show)
    m.button4.clicked.connect(Recording.show)
    app.exec_()   # 退出程序
代码在这里

 

 

 

 

 

Random_window

成果:

主要功能:

        实现随机抽取未看的番剧展示信息和图片,与用户交互,标记番剧已看或未看。

 

1.  界面设定

根据番剧的信息,如上图设计,设计了一个image Label来展示番剧的图片,设计各个番名、排名、信息、评分、评分人数、链接标签,并排设计LineEdit来输入查询的数据结果,番名、信息设置TextEdit输入多行文本,

但链接设置的是Qlabel,来设置超文本链接,设计了三个Button,为’click‘、’已看‘、’未看‘。

代码如下:

  def random_ui(self):
        self.setWindowTitle("我的一番")  # 设置窗口栏标题
        self.setFixedSize(755, 429)  # 设置窗口固定大小
        backImage = os.path.abspath('source/random.jpg')  # 获取背景图片的绝对路径
        palette = QPalette()  # 调色板
        # 设置背景图片,图片缩放并适应窗口大小,同时忽略图片宽高比
        palette.setBrush(self.backgroundRole(),
                         QBrush(QPixmap(backImage).scaled(self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)))
        self.setPalette(palette)
        font = QFont()
        font.setFamily('YouYuan')  # 字体样式
        font.setPointSize(12)  # 字体大小
        # 图片label
        self.imageLabel = QLabel(self)
        self.imageLabel.setGeometry(50,45,227,320)  # 设置位置和大小
        # 设置边框样式,宽度、颜色、实线
        self.imageLabel.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 图片button
        self.imageButton = QPushButton(self)
        self.imageButton.setGeometry(115,385,100,35)  # 设置位置和大小
        self.imageButton.setText("Click")
        # 设置文本的颜色和按钮背景颜色
        self.imageButton.setStyleSheet("color:red;background-color: orange;")
        # 设置字体样式
        self.imageButton.setFont(font)
        self.imageButton.clicked.connect(self.show_image)  # button触发show_image
        # 番名label和textedit
        self.nameLabel = QLabel(self)
        self.nameLabel.setGeometry(470,40,60,45)   # 设置位置和大小
        self.nameLabel.setText("番名:")
        # 设置字体样式
        self.nameLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.nameLabel.setStyleSheet("color:white;background-color: orange;")
        self.nameText = QTextEdit(self)
        self.nameText.setGeometry(530,40,220,45)   # 设置位置和大小
        # 设置字体样式
        self.nameText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.nameText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 排名label和textedit
        self.rankLabel = QLabel(self)
        self.rankLabel.setGeometry(470,95,60,45) # 设置位置和大小
        self.rankLabel.setText("排名:")
        # 设置字体样式
        self.rankLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.rankLabel.setStyleSheet("color:white;background-color: orange;")
        self.rankText = QLineEdit(self)
        self.rankText.setGeometry(530,95,60,45) # 设置位置和大小
        # 设置字体样式
        self.rankText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.rankText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 信息label和textedit
        self.inforLabel = QLabel(self)
        self.inforLabel.setGeometry(470, 150, 60, 45)  # 设置位置和大小
        self.inforLabel.setText("信息:")
        # 设置字体样式
        self.inforLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.inforLabel.setStyleSheet("color:white;background-color: orange;")
        self.inforText = QTextEdit(self)
        self.inforText.setGeometry(530, 150, 220, 45)  # 设置位置和大小
        # 设置字体样式
        self.inforText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.inforText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 评分label
        self.ratingLabel = QLabel(self)
        self.ratingLabel.setGeometry(470, 205, 60, 45) # 设置位置和大小
        self.ratingLabel.setText("评分:")
        # 设置字体样式
        self.ratingLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.ratingLabel.setStyleSheet("color:white;background-color: orange;")
        self.ratingText = QLineEdit(self)
        self.ratingText.setGeometry(530,205,60,45) # 设置位置和大小
        # 设置字体样式
        self.ratingText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.ratingText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 评分人数label
        self.personLabel = QLabel(self)
        self.personLabel.setGeometry(470, 260, 120, 45)
        self.personLabel.setText("评分人数:")
        self.personLabel.setFont(font)
        self.personLabel.setStyleSheet("color:white;background-color: orange;")
        self.personText = QLineEdit(self)
        self.personText.setGeometry(580,260,160,45)
        self.personText.setFont(font)
        self.personText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 链接label
        self.linkLabel = QLabel(self)
        self.linkLabel.setGeometry(470, 315, 60, 45)
        self.linkLabel.setText("链接:")
        self.linkLabel.setFont(font)
        self.linkLabel.setStyleSheet("color:white;background-color: orange;")
        self.linkText = QLabel(self)
        self.linkText.setGeometry(550, 315, 220,45)
        self.linkText.setFont(font)
        self.linkText.setOpenExternalLinks(True)  # 打开外部链接
        # 已看button
        self.ViewedButton = QPushButton(self)
        self.ViewedButton.setGeometry(470, 375, 100, 35)
        self.ViewedButton.setText("已看")
        self.ViewedButton.setFont(font)
        self.ViewedButton.setStyleSheet('background-color:orange')
        self.ViewedButton.clicked.connect(self.update_mark) # ViewedButton触发update_mark
        # 未看button
        self.UnwatchedButton = QPushButton(self)
        self.UnwatchedButton.setGeometry(600, 375, 100, 35)
        self.UnwatchedButton.setText("未看")
        self.UnwatchedButton.setFont(font)
        self.UnwatchedButton.setStyleSheet('background-color:orange')
        self.UnwatchedButton.clicked.connect(self.delete_mark) # UnwatchedButton触发delete_mark
        # 窗口居中
        screen = QDesktopWidget().screenGeometry()   # 获取屏幕的几何信息,坐标和宽高
        size = self.geometry()  # 获取窗口的位置和大小
        newX = (screen.width() - size.width()) / 2
        newY = (screen.height() - size.height()) / 2
        self.move(int(newX), int(newY))  # 居中
View Code

 

2. 查询数据库

随机抽取未看的番剧,并赋值给全局变量。

代码如下:

    def search_database(self):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        # 随机抽取未看的番剧
        sql = "SELECT * FROM anime WHERE Mark is NULL ORDER BY RAND() LIMIT 1 ;"
        cursor.execute(sql)
        # 获取数据并将元组转化为列表
        re = list(cursor.fetchone())
        # 取出各个元素赋值给各项
        self.item = re[0]
        self.link = re[1]
        self.name = re[2]
        self.rank = re[3]
        self.infor = re[4] + '/' + re[5] + '/' + re[6]
        self.rating = re[7]
        self.person = re[8]
        self.mark = re[9]
        # 关闭连接
        db.close()
        cursor.close()
View Code

 

3.槽函数设计

三个button触发了三个槽函数,’click‘按钮用来触发数据库查询和图片载入、文本输入,’已看‘按钮触发数据库跟新将当前的番剧标为已看,’未看‘按钮触发数据库跟新将当前的番剧标为未看。

 

思路形成:

(1)我设想是点击按钮就会进行数据库查询,随机抽取到数据,根据item来导入相应的图片,将查询到的数据按类取出输出文本到各个文本栏,设置链接为超文本可以跳转  

(2)将update_lable更新文本嵌入到show_image中,再调用图片的同时更新文本,让文本信息编辑和图片展示一起进行。

(3)展示图片这里QPixmap类,.setScaledContents(True) #让图片自适应QLabel大小(QPixmap可以参考这位博主的,链接:Qt 之 QPixmap - 简书 (jianshu.com)

  

<1>“click” 按钮触发show_image,而show_image里先调用查询数据库,来获取数据,根据数据获取对应的图片,之后再嵌套update_label() 调用方法编辑更新文本。

代码如下:

    def show_image(self):
        self.search_database()  # 调用函数查询数据库
        self.imageLabel.setPixmap(QPixmap(""))  # 清空label上的图片
        folder_name = 'Image'
        # 获取Image文件夹中的文件名
        file_name = os.listdir(folder_name)
        # 组合随机番剧的图片名
        image_name = self.item + '.jpg'
        # 获取文件夹绝对路径
        folder_path = os.path.abspath('Image')
        # 图片的绝对路径
        path = folder_path + '\{}'.format(image_name)
        # 判断该item图片是否存在对应的图片
        if image_name in file_name:
            # 若存在,则该item照片直接调用到界面
            img = QPixmap(path)
            self.imageLabel.setPixmap(img)
            self.imageLabel.setScaledContents(True)  # 图片自适应QLabel大小

        else:
            # 若不存在则调用None.png照片
            pt = folder_path + r'\None.png'
            img = QPixmap(pt)
            self.imageLabel.setPixmap(img)
            self.imageLabel.setScaledContents(True)
        self.update_label()  # 调用方法更新标签

    def update_label(self):
        # 清空内容
        self.nameText.clear()
        self.rankText.clear()
        self.inforText.clear()
        self.ratingText.clear()
        self.personText.clear()
        self.linkText.clear()
        # 写入文本
        self.nameText.setText(self.name)
        self.rankText.setText(self.rank)
        self.inforText.setText(self.infor)
        self.ratingText.setText(str(self.rating))  # 注意数据类型
        self.personText.setText(self.person)
        self.linkText.setText("<a href='{}' style='color: red;'>详情链接</a>".format(self.link)) # 超文本链接,并设置颜色
View Code

<2> '已看'按钮实现更新数据库将当前番剧标记为已看

代码如下:

    def update_mark(self):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        # 更新mark为已看
        sql = f"UPDATE anime SET Mark= '已看' WHERE   Id = '{self.item}';"
        cursor.execute(sql)
        db.commit()
        # 关闭连接
        db.close()
        cursor.close()

 

<3> ’未看‘按钮实现更新数据库将当前番剧标记为未看

代码如下:

    def delete_mark(self):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        # 清空mark
        sql = "UPDATE anime SET Mark= Null WHERE   Id = '{}';".format(self.item)
        cursor.execute(sql)
        db.commit()
        # 关闭连接
        db.close()
        cursor.close()

 

全部代码:

import sys
import pymysql
import os
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap, QBrush, QPalette, QFont
from PyQt5.QtCore import *


class randomWindow(QWidget):
    item = ""
    link = ""
    name = ""
    rank = ""
    infor = ""
    rating = ""
    person = ""
    mark = ""

    def __init__(self):
        super().__init__()  # 继承QWidget父类
        self.random_ui()
    def random_ui(self):
        self.setWindowTitle("我的一番")  # 设置窗口栏标题
        self.setFixedSize(755, 429)  # 设置窗口固定大小
        backImage = os.path.abspath('source/random.jpg')  # 获取背景图片的绝对路径
        palette = QPalette()  # 调色板
        # 设置背景图片,图片缩放并适应窗口大小,同时忽略图片宽高比
        palette.setBrush(self.backgroundRole(),
                         QBrush(QPixmap(backImage).scaled(self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)))
        self.setPalette(palette)
        font = QFont()
        font.setFamily('YouYuan')  # 字体样式
        font.setPointSize(12)  # 字体大小
        # 图片label
        self.imageLabel = QLabel(self)
        self.imageLabel.setGeometry(50,45,227,320)  # 设置位置和大小
        # 设置边框样式,宽度、颜色、实线
        self.imageLabel.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 图片button
        self.imageButton = QPushButton(self)
        self.imageButton.setGeometry(115,385,100,35)  # 设置位置和大小
        self.imageButton.setText("Click")
        # 设置文本的颜色和按钮背景颜色
        self.imageButton.setStyleSheet("color:red;background-color: orange;")
        # 设置字体样式
        self.imageButton.setFont(font)
        self.imageButton.clicked.connect(self.show_image)  # button触发show_image
        # 番名label和textedit
        self.nameLabel = QLabel(self)
        self.nameLabel.setGeometry(470,40,60,45)   # 设置位置和大小
        self.nameLabel.setText("番名:")
        # 设置字体样式
        self.nameLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.nameLabel.setStyleSheet("color:white;background-color: orange;")
        self.nameText = QTextEdit(self)
        self.nameText.setGeometry(530,40,220,45)   # 设置位置和大小
        # 设置字体样式
        self.nameText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.nameText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 排名label和textedit
        self.rankLabel = QLabel(self)
        self.rankLabel.setGeometry(470,95,60,45) # 设置位置和大小
        self.rankLabel.setText("排名:")
        # 设置字体样式
        self.rankLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.rankLabel.setStyleSheet("color:white;background-color: orange;")
        self.rankText = QLineEdit(self)
        self.rankText.setGeometry(530,95,60,45) # 设置位置和大小
        # 设置字体样式
        self.rankText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.rankText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 信息label和textedit
        self.inforLabel = QLabel(self)
        self.inforLabel.setGeometry(470, 150, 60, 45)  # 设置位置和大小
        self.inforLabel.setText("信息:")
        # 设置字体样式
        self.inforLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.inforLabel.setStyleSheet("color:white;background-color: orange;")
        self.inforText = QTextEdit(self)
        self.inforText.setGeometry(530, 150, 220, 45)  # 设置位置和大小
        # 设置字体样式
        self.inforText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.inforText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 评分label
        self.ratingLabel = QLabel(self)
        self.ratingLabel.setGeometry(470, 205, 60, 45) # 设置位置和大小
        self.ratingLabel.setText("评分:")
        # 设置字体样式
        self.ratingLabel.setFont(font)
        # 设置文本的颜色和按钮背景颜色
        self.ratingLabel.setStyleSheet("color:white;background-color: orange;")
        self.ratingText = QLineEdit(self)
        self.ratingText.setGeometry(530,205,60,45) # 设置位置和大小
        # 设置字体样式
        self.ratingText.setFont(font)
        # 设置边框样式,宽度、颜色、实线
        self.ratingText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 评分人数label
        self.personLabel = QLabel(self)
        self.personLabel.setGeometry(470, 260, 120, 45)
        self.personLabel.setText("评分人数:")
        self.personLabel.setFont(font)
        self.personLabel.setStyleSheet("color:white;background-color: orange;")
        self.personText = QLineEdit(self)
        self.personText.setGeometry(580,260,160,45)
        self.personText.setFont(font)
        self.personText.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(152,251,152);')
        # 链接label
        self.linkLabel = QLabel(self)
        self.linkLabel.setGeometry(470, 315, 60, 45)
        self.linkLabel.setText("链接:")
        self.linkLabel.setFont(font)
        self.linkLabel.setStyleSheet("color:white;background-color: orange;")
        self.linkText = QLabel(self)
        self.linkText.setGeometry(550, 315, 220,45)
        self.linkText.setFont(font)
        self.linkText.setOpenExternalLinks(True)  # 打开外部链接
        # 已看button
        self.ViewedButton = QPushButton(self)
        self.ViewedButton.setGeometry(470, 375, 100, 35)
        self.ViewedButton.setText("已看")
        self.ViewedButton.setFont(font)
        self.ViewedButton.setStyleSheet('background-color:orange')
        self.ViewedButton.clicked.connect(self.update_mark) # ViewedButton触发update_mark
        # 未看button
        self.UnwatchedButton = QPushButton(self)
        self.UnwatchedButton.setGeometry(600, 375, 100, 35)
        self.UnwatchedButton.setText("未看")
        self.UnwatchedButton.setFont(font)
        self.UnwatchedButton.setStyleSheet('background-color:orange')
        self.UnwatchedButton.clicked.connect(self.delete_mark) # UnwatchedButton触发delete_mark
        # 窗口居中
        screen = QDesktopWidget().screenGeometry()   # 获取屏幕的几何信息,坐标和宽高
        size = self.geometry()  # 获取窗口的位置和大小
        newX = (screen.width() - size.width()) / 2
        newY = (screen.height() - size.height()) / 2
        self.move(int(newX), int(newY))  # 居中

    def search_database(self):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        # 随机抽取未看的番剧
        sql = "SELECT * FROM anime WHERE Mark is NULL ORDER BY RAND() LIMIT 1 ;"
        cursor.execute(sql)
        # 获取数据并将元组转化为列表
        re = list(cursor.fetchone())
        # 取出各个元素赋值给各项
        self.item = re[0]
        self.link = re[1]
        self.name = re[2]
        self.rank = re[3]
        self.infor = re[4] + '/' + re[5] + '/' + re[6]
        self.rating = re[7]
        self.person = re[8]
        self.mark = re[9]
        # 关闭连接
        db.close()
        cursor.close()


    def show_image(self):
        self.search_database()  # 调用函数查询数据库
        self.imageLabel.setPixmap(QPixmap(""))  # 清空label上的图片
        folder_name = 'Image'
        # 获取Image文件夹中的文件名
        file_name = os.listdir(folder_name)
        # 组合随机番剧的图片名
        image_name = self.item + '.jpg'
        # 获取文件夹绝对路径
        folder_path = os.path.abspath('Image')
        # 图片的绝对路径
        path = folder_path + '\{}'.format(image_name)
        # 判断该item图片是否存在对应的图片
        if image_name in file_name:
            # 若存在,则该item照片直接调用到界面
            img = QPixmap(path)
            self.imageLabel.setPixmap(img)
            self.imageLabel.setScaledContents(True)  # 图片自适应QLabel大小

        else:
            # 若不存在则调用None.png照片
            pt = folder_path + r'\None.png'
            img = QPixmap(pt)
            self.imageLabel.setPixmap(img)
            self.imageLabel.setScaledContents(True)
        self.update_label()  # 调用方法更新标签

    def update_label(self):
        # 清空内容
        self.nameText.clear()
        self.rankText.clear()
        self.inforText.clear()
        self.ratingText.clear()
        self.personText.clear()
        self.linkText.clear()
        # 写入文本
        self.nameText.setText(self.name)
        self.rankText.setText(self.rank)
        self.inforText.setText(self.infor)
        self.ratingText.setText(str(self.rating))  # 注意数据类型
        self.personText.setText(self.person)
        self.linkText.setText("<a href='{}' style='color: red;'>详情链接</a>".format(self.link)) # 超文本链接,并设置颜色



    def update_mark(self):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        # 更新mark为已看
        sql = f"UPDATE anime SET Mark= '已看' WHERE   Id = '{self.item}';"
        cursor.execute(sql)
        db.commit()
        # 关闭连接
        db.close()
        cursor.close()

    def delete_mark(self):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        # 清空mark
        sql = "UPDATE anime SET Mark= Null WHERE   Id = '{}';".format(self.item)
        cursor.execute(sql)
        db.commit()
        # 关闭连接
        db.close()
        cursor.close()

if __name__ =="__main__":
    app = QApplication(sys.argv)
    ranWindow = randomWindow()  # 实列化
    ranWindow.show() # 显示界面
    app.exec_()  # 退出程序
View Code

 

 

 

 

 

 

 

Search_Window

成果:

 

主要功能:

       实现输入番剧名来查询数据库,展示查询结果。

 

1.界面设计

   主要由输入文本栏、按钮、文本浏览器组成。

 

    def search_ui(self):
        self.setWindowTitle('Search_window')  # 设置窗口标题
        self.setFixedSize(720, 405)  # 设置窗口固定大小
        palette = QPalette() # 调色板
        background_image = os.path.abspath('source\search.jpg')
        # 设置背景图片,图片缩放并适应窗口大小,同时忽略图片宽高比
        palette.setBrush(self.backgroundRole(),
                         QBrush(QPixmap(background_image).scaled(self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)))
        self.setPalette(palette)
        font = QFont()
        font.setFamily('YouYuan') # 字体样式
        font.setPointSize(12) # 字体大小
        # 输入栏
        self.lineEdit = QLineEdit(self)
        self.lineEdit.setGeometry(23,290,400,40)
        self.lineEdit.setPlaceholderText("搜索栏")  # 设置浮显文本
        self.lineEdit.setFont(font) # 设置字体样式
        # 设置输入文本字体加粗和大小,设置边框样式,宽度、颜色、实线
        self.lineEdit.setStyleSheet('font: bold 30px;border-width: 3px;border-style: solid;border-color: rgb(255,140,0);')
        # textEdited[str]当文本被编辑时会发出信号,当文本改变时触发onChange()
        self.lineEdit.textEdited[str].connect(  lambda: self.textChange())
        # 按钮
        self.pushButton = QPushButton(self)
        self.pushButton.setGeometry(435,290,80,40)
        self.pushButton.setText("search")
        self.pushButton.setFont(font) # 设置字体样式
        # 设置button样式表,鼠标滑过状态,鼠标单击后状态
        self.pushButton.setStyleSheet('''QPushButton{background:white;border-radius:5px;}QPushButton:hover{background:orange;}''')
        self.pushButton.clicked.connect(self.search_anime)  # 按钮触发search_anime
        # 文本浏览器
        self.textBrowser = QTextBrowser(self)
        self.textBrowser.setGeometry(23,20,450,200)
        self.textBrowser.setPlaceholderText("View the anime information ") # 设置浮显文本
        self.textBrowser.setFont(font) # 设置字体样式
        self.textBrowser.setOpenLinks(True)  # 打开链接 (是否应自动打开用户尝试通过鼠标或键盘激活的链接)
        self.textBrowser.setOpenExternalLinks(True)  # 打开外部链接 (是否自动打开指向外部源的链接)
        # 设置边框样式,宽度、颜色、实线
        self.textBrowser.setStyleSheet('border-width: 3px;border-style: solid;border-color: rgb(255,140,0);')
        # 图片标签
        self.img_label = QLabel(self)
        self.img_label.setGeometry(500,20,200,200)
        # 界面居中
        screen = QDesktopWidget().screenGeometry()   # 获取屏幕的几何信息,坐标和宽高
        size = self.geometry()  # 获取窗口的位置和大小
        newX = (screen.width() - size.width()) / 2
        newY = (screen.height() - size.height()) / 2
        self.move(int(newX), int(newY))  # 窗口居中

 

 2. 槽函数设计

(1) textEdited[str]当文本被编辑时会发出信号,当文本改变时触发onChange,实时获取输入的文本。

 代码如下:

    def textChange(self):
        self.search_name = self.lineEdit.text()    # 获取输入文本

 

(2) search按钮触发search_anime,查询数据库,输入数据更新文本浏览器

 

代码如下:

    def search_database(self,text:str):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        sql = f"SELECT * FROM anime WHERE Name_anime = '{text}' "
        cursor.execute(sql)
        result = cursor.fetchone()
        # 判断查询结果是否为空
        if result:
            # 若不为空
            data = list(result)     # 获取数据并将元组转化为列表
            # 取出各个元素赋值给各项
            self.item = data[0]
            self.link = data[1]
            self.name = data[2]
            self.rank = data[3]
            self.infor = data[4] + '/' + data[5] + '/' + data[6]
            self.rating = data[7]
            self.person = data[8]
            self.mark = data[9]
        else:
            # 若为空,查询结果为None
            pass

        # 关闭连接
        db.close()
        cursor.close()

    def search_anime(self):
        self.img_label.setPixmap(QPixmap(""))  # 清除图片
        self.textBrowser.clear() # 清空内容
        self.search_database(self.search_name) # 调用方法查询数据库
        self.char_format = QTextCharFormat() # 设置字符格式
        # 若查询到番剧
        if self.item:
            self.textBrowser.setCurrentCharFormat(self.char_format)  # 设置textBrowser的字符格式,
            # 连续输入文本(insertPlainText)
            self.textBrowser.insertPlainText('Item : {}\n'.format(self.item))
            self.textBrowser.insertPlainText('Name : {}\n'.format(self.name))
            self.textBrowser.insertPlainText('Information : {}\n'.format(self.infor))
            self.textBrowser.insertPlainText('Rank : {}\n'.format(self.rank))
            self.textBrowser.insertPlainText('Rating : {}\n'.format(self.rating))
            self.textBrowser.insertPlainText('Number of ratings : {}\n'.format(self.person))
            self.textBrowser.insertPlainText('View : {}\n'.format(self.mark))
            self.textBrowser.append("Link: <a href='{}'>点击这里</a>".format(self.link))
            # 清除赋值,再次初始化
            self.item = ""
            self.link = ""
            self.name = ""
            self.rank = ""
            self.infor = ""
            self.rating = ""
            self.person = ""
            self.mark = ""

 

 

 (3)  若查询不到,则展示相应的图片,创建线程播放语音。

 

 

 

代码如下:

 

        # 若动漫不存在
        else:
            self.textBrowser.setCurrentCharFormat(self.char_format)  # 设置为文本
            self.textBrowser.setText("ごめんなさい,没有这部动漫哦!")
            img_path = os.path.abspath('source\sorry.jpg')  # 图片的绝对路径
            img =QPixmap(img_path)
            self.img_label.setPixmap(img)  # 显示图片
            self.img_label.setScaledContents(True)  # 填充label,自适应大小
            mp3_thread = Thread() # 创建线程
            mp3_thread.run()  # 运行线程

# 设计线程
class Thread(QThread):
    def __init__(self):
        super().__init__()
    def run(self):
        mp3_file = QUrl.fromLocalFile(os.path.abspath('source/sorry.mp3'))  # 音频文件路径的接口(QUrl 类为处理 URL 提供了一个方便的接口)
        mp3 = QtMultimedia.QMediaContent(mp3_file)  # 构建媒体内容
        player = QtMultimedia.QMediaPlayer() # QMediaPlayer 类是一个高级媒体播放类
        player.setMedia(mp3) # 读取媒体数据
        player.setVolume(100)  # 设置音量
        player.play()  # 播放
        time.sleep(1.5) #设置延时等待音频播放结束

 

 

 

 Tips:

发现的问题
1.sql语句出错了,搜索的番剧名没有加‘’导致程序异常直接退出
2.我设置的item、name等都是全局变量,当我搜索存在于数据库的番剧再搜索不存在的番剧时textBrowser任然显示的前一个搜索的番剧信息
解决:再次初始化全局变量,clear文本内容
3.想给text browser直接加图片,
解决:利用css层叠样式表设置图片
4,实现超文本跳转时,必须有 self.textBrowser.setOpenLinks(True) # 打开链接 (是否应自动打开用户尝试通过鼠标或键盘激活的链接)
和self.textBrowser.setOpenExternalLinks(True) # 打开外部链接 (自动打开指向外部源的链接)
5. 查询番剧点击链接后,再次查询后后面的文本会连接到上一部番剧的超链接
解决:CurrentCharFormat:Returns the char format that is used when inserting new text(返回插入新文本时使用的字符格式)
setCharFormat(const QTextCharFormat &format)将光标的当前字符格式设置为给定格式。如果光标具有选定内容,则给定的格式将应用于当前选定内容。
setCurrentCharFormat(const QTextCharFormat &format)
通过在编辑器光标上调用 QTextCursor::setCharFormat() 来设置插入新文本时要使用的字符格式。如果编辑器有选择,则字符格式将直接应用于选择。

 

全部代码:

from PyQt5.QtWidgets import *
from  PyQt5.QtGui import QPixmap,QBrush,QPalette,QFont,QTextCharFormat
from PyQt5.QtCore import *
from PyQt5 import QtMultimedia
from PyQt5.QtCore import QUrl
import time
import sys,os
import pymysql


class searchWindow(QWidget):
    search_name = ""
    item = ""
    link = ""
    name = ""
    rank = ""
    infor = ""
    rating = ""
    person = ""
    mark = ""
    def __init__(self):
        super().__init__()
        self.search_ui()

    def search_ui(self):
        self.setWindowTitle('Search_window')  # 设置窗口标题
        self.setFixedSize(720, 405)  # 设置窗口固定大小
        palette = QPalette() # 调色板
        background_image = os.path.abspath('source\search.jpg')
        # 设置背景图片,图片缩放并适应窗口大小,同时忽略图片宽高比
        palette.setBrush(self.backgroundRole(),
                         QBrush(QPixmap(background_image).scaled(self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)))
        self.setPalette(palette)
        font = QFont()
        font.setFamily('YouYuan') # 字体样式
        font.setPointSize(12) # 字体大小
        # 输入栏
        self.lineEdit = QLineEdit(self)
        self.lineEdit.setGeometry(23,290,400,40)
        self.lineEdit.setPlaceholderText("搜索栏")  # 设置浮显文本
        self.lineEdit.setFont(font) # 设置字体样式
        # 设置输入文本字体加粗和大小,设置边框样式,宽度、颜色、实线
        self.lineEdit.setStyleSheet('font: bold 30px;border-width: 3px;border-style: solid;border-color: rgb(255,140,0);')
        # textEdited[str]是当文本被编辑时会发出信号,当文本改变时触发onChange()
        self.lineEdit.textEdited[str].connect(  lambda: self.textChange())
        # 按钮
        self.pushButton = QPushButton(self)
        self.pushButton.setGeometry(435,290,80,40)
        self.pushButton.setText("search")
        self.pushButton.setFont(font) # 设置字体样式
        # 设置button样式表,鼠标滑过状态,鼠标单击后状态
        self.pushButton.setStyleSheet('''QPushButton{background:white;border-radius:5px;}QPushButton:hover{background:orange;}''')
        self.pushButton.clicked.connect(self.search_anime)  # 按钮触发search_anime
        # 文本浏览器
        self.textBrowser = QTextBrowser(self)
        self.textBrowser.setGeometry(23,20,450,200)
        self.textBrowser.setPlaceholderText("View the anime information ") # 设置浮显文本
        self.textBrowser.setFont(font) # 设置字体样式
        self.textBrowser.setOpenLinks(True)  # 打开链接 (是否应自动打开用户尝试通过鼠标或键盘激活的链接)
        self.textBrowser.setOpenExternalLinks(True)  # 打开外部链接 (是否自动打开指向外部源的链接)
        # 设置边框样式,宽度、颜色、实线
        self.textBrowser.setStyleSheet('border-width: 3px;border-style: solid;border-color: rgb(255,140,0);')
        # 图片标签
        self.img_label = QLabel(self)
        self.img_label.setGeometry(500,20,200,200)
        # 界面居中
        screen = QDesktopWidget().screenGeometry()   # 获取屏幕的几何信息,坐标和宽高
        size = self.geometry()  # 获取窗口的位置和大小
        newX = (screen.width() - size.width()) / 2
        newY = (screen.height() - size.height()) / 2
        self.move(int(newX), int(newY))  # 窗口居中


    def textChange(self):
        self.search_name = self.lineEdit.text()    # 获取输入文本

    def search_database(self,text:str):
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        sql = f"SELECT * FROM anime WHERE Name_anime = '{text}' "
        cursor.execute(sql)
        result = cursor.fetchone()
        # 判断查询结果是否为空
        if result:
            # 若不为空
            data = list(result)     # 获取数据并将元组转化为列表
            # 取出各个元素赋值给各项
            self.item = data[0]
            self.link = data[1]
            self.name = data[2]
            self.rank = data[3]
            self.infor = data[4] + '/' + data[5] + '/' + data[6]
            self.rating = data[7]
            self.person = data[8]
            self.mark = data[9]
        else:
            # 若为空,查询结果为None
            pass

        # 关闭连接
        db.close()
        cursor.close()

    def search_anime(self):
        self.img_label.setPixmap(QPixmap(""))  # 清除图片
        self.textBrowser.clear() # 清空内容
        self.search_database(self.search_name) # 调用方法查询数据库
        self.char_format = QTextCharFormat() # 设置字符格式
        # 若查询到番剧
        if self.item:
            self.textBrowser.setCurrentCharFormat(self.char_format)  # 设置textBrowser的字符格式,
            # 连续输入文本(insertPlainText)
            self.textBrowser.insertPlainText('Item : {}\n'.format(self.item))
            self.textBrowser.insertPlainText('Name : {}\n'.format(self.name))
            self.textBrowser.insertPlainText('Information : {}\n'.format(self.infor))
            self.textBrowser.insertPlainText('Rank : {}\n'.format(self.rank))
            self.textBrowser.insertPlainText('Rating : {}\n'.format(self.rating))
            self.textBrowser.insertPlainText('Number of ratings : {}\n'.format(self.person))
            self.textBrowser.insertPlainText('View : {}\n'.format(self.mark))
            self.textBrowser.append("Link: <a href='{}'>点击这里</a>".format(self.link))
            # 清除赋值,再次初始化
            self.item = ""
            self.link = ""
            self.name = ""
            self.rank = ""
            self.infor = ""
            self.rating = ""
            self.person = ""
            self.mark = ""
        # 若动漫不存在
        else:
            self.textBrowser.setCurrentCharFormat(self.char_format)  # 设置为文本
            self.textBrowser.setText("ごめんなさい,没有这部动漫哦!")
            img_path = os.path.abspath('source\sorry.jpg')  # 图片的绝对路径
            img =QPixmap(img_path)
            self.img_label.setPixmap(img)  # 显示图片
            self.img_label.setScaledContents(True)  # 填充label,自适应大小
            mp3_thread = Thread() # 创建线程
            mp3_thread.run()  # 运行线程

# 设计线程
class Thread(QThread):
    def __init__(self):
        super().__init__()
    def run(self):
        mp3_file = QUrl.fromLocalFile(os.path.abspath('source/sorry.mp3'))  # 音频文件路径的接口(QUrl 类为处理 URL 提供了一个方便的接口)
        mp3 = QtMultimedia.QMediaContent(mp3_file)  # 构建媒体内容
        player = QtMultimedia.QMediaPlayer() # QMediaPlayer 类是一个高级媒体播放类
        player.setMedia(mp3) # 读取媒体数据
        player.setVolume(100)  # 设置音量
        player.play()  # 播放
        time.sleep(1.5) #设置延时等待音频播放结束




if __name__ =="__main__":
    app = QApplication(sys.argv)
    sWindow = searchWindow()
    sWindow.show()
    app.exec_()
View Code

 

 

 

 

 

 

 

 

Recording_Window

成果:

 

主要功能:

       实现展示已看的番剧名,动态展示已看进度,一键清空记录

 

 

1. 界面设计

     主要由文本浏览器、两个按钮、进度条组成。

代码如下:

 

    def recording_ui(self):
        self.resize(720,480)  # 设置窗口大小
        self.setWindowTitle("Recording")
        palette = QPalette()  # 调色板
        backImage = os.path.abspath('source/recording.jpg') # 背景的绝对路径
        # 设置背景图片,图片缩放并适应窗口大小,同时忽略图片宽高比
        palette.setBrush(self.backgroundRole(),
                         QBrush(QPixmap(backImage).scaled(self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)))
        self.setPalette(palette)
        # 设计进度条
        self.progressbar = QProgressBar(self)
        self.progressbar.setGeometry(30,435,470,30)
        # 设置最大最小值
        self.progressbar.setMinimum(0)
        self.progressbar.setMaximum(100)
        self.progressbar.setValue(0) # 设置进度条初始值为0
        # 设置进度标签
        self.label = QLabel(self)
        self.label.setGeometry(480,435,90,30)
        self.label.setText("进度")
        self.label.setFont(self.font)
        self.label.setStyleSheet("color: orange ") # 设置字体颜色
        # 设置文本浏览器
        self.textBrowser = QTextBrowser(self)
        self.textBrowser.setGeometry(30,110,451,301)
        self.textBrowser.setPlaceholderText('记录')
        self.textBrowser.setFont(self.font)
        # 设置边框颜色和宽度、实线
        self.textBrowser.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(255, 170, 0);')
        # 设置展示按钮
        self.showButton = QPushButton(self)
        self.showButton.setGeometry(495,350,75,40)
        self.showButton.setText("Show")
        self.showButton.setFont(self.font)
        self.showButton.clicked.connect(self.search_viewed)  # showButton触发search_viewed
        # 设置button样式表,鼠标滑过状态,鼠标单击后状态
        self.showButton.setStyleSheet('''QPushButton{background:white;border-radius:5px;}QPushButton:hover{background:orange;}''')
        # 设置清空按钮
        self.clearButton = QPushButton(self)
        self.clearButton.setGeometry(495,290,80,40)
        self.clearButton.setText("清空")
        self.clearButton.setFont(self.font)
        self.clearButton.clicked.connect(self.clear_mark)  # clearButton触发clear_mark
        # 设置button样式表,鼠标滑过状态,鼠标单击后状态
        self.clearButton.setStyleSheet('''QPushButton{background:white;border-radius:5px;}QPushButton:hover{background:red;}''')
        # 窗口居中
        screen = QDesktopWidget().screenGeometry()   # 获取屏幕的几何信息,坐标和宽高
        size = self.geometry()  # 获取窗口的位置和大小
        newX = (screen.width() - size.width()) / 2
        newY = (screen.height() - size.height()) / 2
        self.move(int(newX), int(newY))  # 居中

 

 

2. 槽函数设计

                           展示已看到番剧                                                                                          清空记录                                                                                                展示无记录情况

 

(1) 查询数据库统计已看的番剧数量

代码如下:

    def search_num(self):
        # 清空数据
        self.result2_num = 0
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor2 = db.cursor()
        # 查询已看的番剧信息
        sql2 = "SELECT COUNT(Mark) FROM anime where Mark = '已看';"
        cursor2.execute(sql2)
        mark_num = list(cursor2.fetchone())  # 获取查询结果
        self.result2_num = mark_num[0]  # 取出数值
        db.commit()
        db.close()
        cursor2.close()

 

(2)清空button触发clear_mark,更新数据库将番剧的mark归为Null,弹出提示框提醒记录已经清空。

 

 

代码如下:

    # 清空已看记录
    def clear_mark(self):
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor3 = db.cursor()
        # 更新mark,清空已看记录
        sql3 = "UPDATE anime SET Mark = NULL WHERE Mark = '已看';"
        cursor3.execute(sql3)
        db.commit()
        # 关闭连接
        db.close()
        cursor3.close()
        # 提示框
        self.message =QMessageBox()
        self.message.setWindowTitle("Clear") # 窗口标题
        self.message.setText('记录已经清空!')
        self.message.setFont(self.font) # 设置字体样式
        self.message.show()
        # 清空文本、初始化进度
        self.textBrowser.clear()
        self.progressbar.setValue(0)
        self.label.setText("进度")

 

(3)show按钮触发search_viewed,实现查询数据库,搜索标记为已看的番剧信息,在文本浏览器展示已看的番剧名,实现动态加载进度条(即已看的番剧占比),加载之后弹出提示框,显示已看的番剧数量,

若没有已看的番剧,则利用css来在文本浏览器加载图片,设置文本提醒无记录。

代码如下:

    # 搜索标记为已看的番剧信息
    def search_viewed(self):
        # 清空文本内容
        self.textBrowser.clear()
        self.result_infor = []
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor1 = db.cursor()
        # 查询已看的番剧信息
        sql1 = "SELECT * FROM anime WHERE Mark = '已看';"
        cursor1.execute(sql1)
        self.result_infor = list(cursor1.fetchall())  # 获取多条查询结果
        db.commit()
        # 关闭连接
        db.close()
        cursor1.close()

        if self.result_infor:
            self.search_num() # 获取已看番剧的数量
            self.progressbar.setValue(0) # 初始化进度条
            for x in list(self.result_infor):
                index =  str(list(self.result_infor).index(x) + 1)  # 获取序数(从1开始)
                self.textBrowser.append( '【{}】.{}'.format(index,x[2])) # 添加文本,以序数+番名的形式
                value = int(int(index)/24)  # 计算所看番剧的百分比,化为整型
                # 动态加载进度条
                self.progressbar.setValue(value)  # 设置进度值
                self.label.setText('%{}'.format(value)) # 进度标签展示进度值

            # 弹出提示框
            nm = QMessageBox(self)
            nm.setWindowTitle("Viewed")
            nm.setText('您已经观看了{}部动漫'.format(self.result2_num))
            nm.setFont(self.font)  # 字体样式
            nm.show()
        else:
            self.progressbar.setValue(0)  # 初始化进度条(否则在清空记录后仍保留当时的进度)
            self.label.setText('进度')
            # QTextBrowser中插入HTML代码来显示图片,并通过设置CSS样式来控制图片大小
            # css层叠样式
            html = """
            <html>
              <body>
                <img src="source/eva.png" width="380" height="380">
              </body>
            </html>
            """
            document = QTextDocument()
            document.setHtml(html)
            # 将QTextDocument设置为QTextBrowser的文本内容
            self.textBrowser.setDocument(document)
            self.textBrowser.append("无记录!请多多观看番剧哦!")

 

tip:进度条的动态展示

我是将进度条更新放入到写入番名的循环中,循环遍历查询结果,取出番名的同时,取出下标,再加一则可得出此时的已看番剧数量,再计算已看番剧的占比,设置为进度值,

这就实现了,显示当前番剧的同时,展示当前的看番进度,从而实现进度条的动态加载。

 

全部代码:

import sys
from PyQt5.QtWidgets import *
import os
from  PyQt5.QtGui import QPixmap,QBrush,QPalette,QFont
from PyQt5.QtCore import *
import pymysql
from PyQt5.QtGui import QTextDocument


class recordingWindow(QWidget):
    result_infor = [] # 存储已看的番剧信息
    result2_num = 0 # 已看的番剧数量
    font = QFont()
    font.setFamily('YouYuan')  # 字体样式
    font.setPointSize(12)  # 字体大小
    def __init__(self):
        super().__init__()   # 继承QWidget父类
        self.recording_ui()

    def recording_ui(self):
        self.resize(720,480)  # 设置窗口大小
        self.setWindowTitle("Recording")
        palette = QPalette()  # 调色板
        backImage = os.path.abspath('source/recording.jpg') # 背景的绝对路径
        # 设置背景图片,图片缩放并适应窗口大小,同时忽略图片宽高比
        palette.setBrush(self.backgroundRole(),
                         QBrush(QPixmap(backImage).scaled(self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)))
        self.setPalette(palette)
        # 设计进度条
        self.progressbar = QProgressBar(self)
        self.progressbar.setGeometry(30,435,470,30)
        # 设置最大最小值
        self.progressbar.setMinimum(0)
        self.progressbar.setMaximum(100)
        self.progressbar.setValue(0) # 设置进度条初始值为0
        # 设置进度标签
        self.label = QLabel(self)
        self.label.setGeometry(480,435,90,30)
        self.label.setText("进度")
        self.label.setFont(self.font)
        self.label.setStyleSheet("color: orange ") # 设置字体颜色
        # 设置文本浏览器
        self.textBrowser = QTextBrowser(self)
        self.textBrowser.setGeometry(30,110,451,301)
        self.textBrowser.setPlaceholderText('记录')
        self.textBrowser.setFont(self.font)
        # 设置边框颜色和宽度、实线
        self.textBrowser.setStyleSheet('border-width: 5px;border-style: solid;border-color: rgb(255, 170, 0);')
        # 设置展示按钮
        self.showButton = QPushButton(self)
        self.showButton.setGeometry(495,350,75,40)
        self.showButton.setText("Show")
        self.showButton.setFont(self.font)
        self.showButton.clicked.connect(self.search_viewed)  # showButton触发search_viewed
        # 设置button样式表,鼠标滑过状态,鼠标单击后状态
        self.showButton.setStyleSheet('''QPushButton{background:white;border-radius:5px;}QPushButton:hover{background:orange;}''')
        # 设置清空按钮
        self.clearButton = QPushButton(self)
        self.clearButton.setGeometry(495,290,80,40)
        self.clearButton.setText("清空")
        self.clearButton.setFont(self.font)
        self.clearButton.clicked.connect(self.clear_mark)  # clearButton触发clear_mark
        # 设置button样式表,鼠标滑过状态,鼠标单击后状态
        self.clearButton.setStyleSheet('''QPushButton{background:white;border-radius:5px;}QPushButton:hover{background:red;}''')
        # 窗口居中
        screen = QDesktopWidget().screenGeometry()   # 获取屏幕的几何信息,坐标和宽高
        size = self.geometry()  # 获取窗口的位置和大小
        newX = (screen.width() - size.width()) / 2
        newY = (screen.height() - size.height()) / 2
        self.move(int(newX), int(newY))  # 居中

    # 搜索标记为已看的番剧信息
    def search_viewed(self):
        # 清空文本内容
        self.textBrowser.clear()
        self.result_infor = []
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor1 = db.cursor()
        # 查询已看的番剧信息
        sql1 = "SELECT * FROM anime WHERE Mark = '已看';"
        cursor1.execute(sql1)
        self.result_infor = list(cursor1.fetchall())  # 获取多条查询结果
        db.commit()
        # 关闭连接
        db.close()
        cursor1.close()

        if self.result_infor:
            self.search_num() # 获取已看番剧的数量
            self.progressbar.setValue(0) # 初始化进度条
            for x in list(self.result_infor):
                index =  str(list(self.result_infor).index(x) + 1)  # 获取序数(从1开始)
                self.textBrowser.append( '【{}】.{}'.format(index,x[2])) # 添加文本,以序数+番名的形式
                value = int(int(index)/24)  # 计算所看番剧的百分比,化为整型
                # 动态加载进度条
                self.progressbar.setValue(value)  # 设置进度值
                self.label.setText('%{}'.format(value)) # 进度标签展示进度值

            # 弹出提示框
            nm = QMessageBox(self)
            nm.setWindowTitle("Viewed")
            nm.setText('您已经观看了{}部动漫'.format(self.result2_num))
            nm.setFont(self.font)  # 字体样式
            nm.show()
        else:
            self.progressbar.setValue(0)  # 初始化进度条(否则在清空记录后仍保留当时的进度)
            self.label.setText('进度')
            # QTextBrowser中插入HTML代码来显示图片,并通过设置CSS样式来控制图片大小
            # css层叠样式
            html = """
            <html>
              <body>
                <img src="source/eva.png" width="380" height="380">
              </body>
            </html>
            """
            document = QTextDocument()
            document.setHtml(html)
            # 将QTextDocument设置为QTextBrowser的文本内容
            self.textBrowser.setDocument(document)
            self.textBrowser.append("无记录!请多多观看番剧哦!")


    # 统计已看的番剧数量
    def search_num(self):
        # 清空数据
        self.result2_num = 0
        # 连接数据库
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor2 = db.cursor()
        # 查询已看的番剧信息
        sql2 = "SELECT COUNT(Mark) FROM anime where Mark = '已看';"
        cursor2.execute(sql2)
        mark_num = list(cursor2.fetchone())  # 获取查询结果并转为列表
        self.result2_num = mark_num[0]  # 取出数值
        db.commit()
        db.close()
        cursor2.close()

    # 清空已看记录
    def clear_mark(self):
        db = pymysql.connect(host='localhost',
                             user='root',
                             password='318427',
                             database='animeplan')

        # 使用cursor()方法获取操作游标
        cursor3 = db.cursor()
        # 更新mark,清空已看记录
        sql3 = "UPDATE anime SET Mark = NULL WHERE Mark = '已看';"
        cursor3.execute(sql3)
        db.commit()
        # 关闭连接
        db.close()
        cursor3.close()
        # 提示框
        self.message =QMessageBox()
        self.message.setWindowTitle("Clear") # 窗口标题
        self.message.setText('记录已经清空!')
        self.message.setFont(self.font) # 设置字体样式
        self.message.show()
        # 清空文本、初始化进度
        self.textBrowser.clear()
        self.progressbar.setValue(0)
        self.label.setText("进度")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    rWindow = recordingWindow()
    rWindow.show()
    app.exec_()
View Code

 

 

 

感言:

至此所有的模块已经展示完毕,历经半个月的零零散散敲代码,本程序的pyqt设计虽简陋,但对于初学来说我觉得已经很满意了,熟悉了基础控件,提高了我的查询能力,很多控件的功能、参数还是需要参考C++的说明文档,还有信号和槽实在太实用了,自己在设计中也苦想过槽函数的设计,还有QThread和QProcess还需要进一步学习,只是初步了解下,程序中用到了多线程和多进程,但实现的功能简易,望日后技术精进再来完善这个小程序,希望大家可以多多给我提建议^ - ^.

 

 

(本文独创,转载请标明出处)

标签:基于,font,self,pyqt5,textBrowser,设置,番剧,border,setText
From: https://www.cnblogs.com/Mokirito/p/17383174.html

相关文章

  • 提高数据的安全性和可控性,数栈基于 Ranger 实现的 Spark SQL 权限控制实践之路
    在企业级应用中,数据的安全性和隐私保护是极其重要的。Spark作为数栈底层计算引擎之一,必须确保数据只能被授权的人员访问,避免出现数据泄露和滥用的情况。为了实现SparkSQL对数据的精细化管理及提高数据的安全性和可控性,数栈基于ApacheRanger实现了SparkSQL对数据处理的权......
  • 基于云原生的物联大数据智能服务
    摘要:物联大数据已成为当前物联网系统建设的核心,基于物联大数据的涌现智能和应用以及借此对物理世界的反馈和控制是未来物联网系统的建设目标。本文分享自华为云社区《基于云原生的物联大数据智能服务》,作者:赵卓峰、丁维龙、于淇/北方工业大学数据工程研究院、大规模流数据集......
  • 基于云原生的物联大数据智能服务
    摘要:物联大数据已成为当前物联网系统建设的核心,基于物联大数据的涌现智能和应用以及借此对物理世界的反馈和控制是未来物联网系统的建设目标。本文分享自华为云社区《基于云原生的物联大数据智能服务》,作者:赵卓峰、丁维龙、于淇/北方工业大学数据工程研究院、大规模流数据集成......
  • 基于”python+requests模块“接口自动化的基本方法使用
    1,接口自动化测试1.1概念接口测试:是对系统或者组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。接口自动化测试:让程序代替人为对接口项目进行自动验证测试的过程1.2实现方式1,工具(jmeter,postman)2,代码(python-requests)1.3测试工具缺点......
  • 基于LSTM-RNN的深度学习网络的训练对比matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要        长短期记忆网络(LSTM,LongShort-TermMemory)是一种时间循环神经网络,是为了解决一般的RNN(循环神经网络)存在的长期依赖问题而专门设计出来的,所有的RNN都具有一种重复神经网络模块的链式形......
  • 基于CNN卷积神经网络的语音信号识别算法matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要       人工智能的应用中,语音识别在今年来取得显著进步,不管是英文、中文或者其他语种,机器的语音识别准确率在不断上升。其中,语音听写技术的发展最为迅速,目前已广泛在语音输入、语音搜索、语音......
  • 基于大模型的优质Prompt开发课--学习笔记ing
    大规模与训练语言模型(LLMs) Large-scaleandtrainedlanguagemodel 近十年深度学习模型主要更迭 当模型能够习得的知识量级越来越大,其生成的内容亦呈现出无线可能 为什么大模型能够如此强大的表现力大模型(LLMs)涌现出的三大能力:上下文学习(In-cotnextlearning)上下......
  • 基于C语言开发一个图书管理系统[2023-05-16]
    基于C语言开发一个图书管理系统[2023-05-16]2020级计算机应用专业毕业设计题目及要求一、设计内容及要求:基于C语言开发一个图书管理系统,完成系统分析、设计和开发。设计目的:设计一个可以实现增删改查、借书还书的图书借阅管理系统。功能要求:图书管理系统一般包括:借书还书、......
  • 基于FATE联邦学习的隐私计算实践
    FATE 是一个工业级联邦学习框架,所谓联邦学习指的就是可以联合多方的数据,共同构建一个模型;与传统数据使用方式相比,它不需要聚合各方数据搭建 数据仓库,联邦学习在联合计算建模的过程中,多方机构之间的数据是不会进行共享的,实现数据的 可用不可见。本文主要分享隐私计算平台 FATE......
  • 基于jenkins和jmeter实现接口自动化过程
    声明        本公众号所有内容,均属微信公众号:开源优测 所有,任何媒体、网站或个人未经授权不得转载、链接、转贴或以其他方式复制发布/发表。已经本公众号协议授权的媒体、网站,在使用时必须注明"稿件来源微信公众号:开源优测",违者本公众号将依法追究责任。前面几篇文章中......