PyQt5实战——翻译器的UI页面设计以及代码实现(七)

个人博客:苏三有春的博客

系类往期文章:
PyQt5实战------多脚本集合包,前言与环境配置(一)
PyQt5实战------多脚本集合包,UI以及工程布局(二)
PyQt5实战------多脚本集合包,程序入口QMainWindow(三)
PyQt5实战------操作台打印重定向,主界面以及stacklayout使用(四)
PyQt5实战------UTF-8编码器UI页面设计以及按钮连接(五)
PyQt5实战------UTF-8编码器功能的实现(六)

前言

上期文章我们讲了如何去实现一个UTF-8编码的转换器的构造以及代码实现。本期我们实现脚本集合包的第二个脚本(功能):翻译器。目前,该翻译一起支持中译英,英译中,或自动检测翻译。翻译功能的实现本质上是通过爬虫技术去爬取网页实现的翻译功能,因此翻译功能需要联网才可进行。因此,在设计之初需要注意的是(虽然笔者并不是在设计之初就意识到会有这么多问题):如何爬取一个网站,如何将需要翻译的内容上传给网站,是否需要判断当前状态是否联网,如何判断是否联网。如果处于断网状态如何处理...接下来两到三篇文章会详细讲述这些问题如何解决。

翻译器的UI布局

首先先看翻译器的UI布局

可以看到这个翻译器的主要框架分为上中下三个部分,垂直分布,因此,主布局是一个垂直布局,三个部分分别是:翻译语言选择,翻译文本框,快速翻译三个部分。

  • 翻译语言选择 :该部分由从左到右三个部分组成,水平布局,第一个下拉列表可选取待翻译语言的语种,包括:自动检测中文English三种,中间的组件是一个带有图标的按钮,可以转换左右下拉列表的语种,右边的下拉列表可选取翻译后的语种,包括:English中文
  • 翻译文本框:该部分由从左到右三个部分组成,水平布局,第一个文本框是可读写文本框,可输入待翻译的内容,中间是一个按钮,点击按钮则开始翻译,右边文本框是一个只读文本框,在点击翻译按钮后,若翻译成功则会在该文本框中显示翻译后的内容。
  • 快速翻译:快速翻译一个ListView,列表组件,其中存储了一个字典,显示对应的key,点击后会自动访问对应key的value,将value显示出来,无需联网,用于快速反应一些常用常翻译的内容。

代码解释

创建布局对象

根据上述UI的设计,我们可以创建对应的layout对象,并将子布局一次添加进主布局,主布局设置为widget的布局

python 复制代码
        # create a horizontal layout
        layout = QVBoxLayout() # 主布局
        langlayout = QHBoxLayout() # 翻译语言选择的布局
        hlayout = QHBoxLayout() # 翻译文本框的布局
        listlayout = QVBoxLayout() # 快速翻译列表的布局
        layout.addLayout(langlayout) # 将三个子布局添加进主布局
        layout.addLayout(hlayout) # 将三个子布局添加进主布局
        layout.addLayout(listlayout) # 将三个子布局添加进主布局
        self.setLayout(layout) # 将layout设置为该翻译器widget的布局

翻译语言的选择与切换UI设计

该部分由两个comboBox(下拉列表)和一个PushButton(按钮)组成

python 复制代码
        # lang layout
        self.langfromcb = QComboBox(self) # 创建输入语言的下拉列表
        self.langfromcb.addItem("自动检测") # 往下拉列表中添加元素
        self.langfromcb.addItem("中文")
        self.langfromcb.addItem("English")
        self.langfromcb.setCurrentIndex(1) # 将下拉列表中的第二个元素(0为第一个)设置为默认选项
        
        self.langtocb = QComboBox(self) # 创建输出语言的下拉列表
        self.langtocb.addItems(['中文','English']) # 往下拉列表中添加元素
        self.langtocb.setCurrentIndex(1) # 将下拉列表中的第二个元素设置为默认选项
        
        self.exchangebtn = QPushButton(self) # 创建交换语种的按钮
        pixmap = QPixmap("_internal/res/img/exchange.ico") # 将图标添加进变量
        self.exchangebtn.setIcon(QIcon(pixmap)) # 为按钮设置图标
        self.exchangebtn.setIconSize(self.exchangebtn.sizeHint()) # 设置图标为自适应按钮大小
        self.exchangebtn.setToolTip("交换语言") # 为按钮设置提示泡泡
        self.exchangebtn.clicked.connect(self.tranasexchange) # 给按钮点击状态连接事件方法,该方法将调转输入与输出语种
        
        langlayout.addWidget(self.langfromcb) # 将三个组件都加入到第一个子布局中
        langlayout.addWidget(self.exchangebtn)
        langlayout.addWidget(self.langtocb)

在这一段代码值得注意的是:

  • 这段代码展示了之前文章未出现的组件,即下拉列表(ComboBox)。

  • 下拉列表有两种添加元素的方法,addItem()addItems(),一个参数为单个元素,一个参数为list,可同时输入多个元素。

  • setCurrentIndex()方法可设置下拉列表的首选项,比如:下拉列表的顺序为:自动检测,中文,English,我想让中文成为默认选项,则可使用setCurrentIndex(1)来使得中文成为默认选项,因为python是从0开始算起的。

  • 按钮可以添加图标,这个图标的地址开头是__internal,为什么使用这个作为最高级目录,请看往期内容PyQt5实战------多脚本集合包,程序入口QMainWindow(三)第三节初始化应用程序部分,在窗口标签部分讲过相关内容

  • 按键的提示泡泡长这样,当鼠标放在按钮上,会弹出一个小框描述该按键的功能。

翻译文本框的UI设计

该部分是由两个文本框与一个按键组成

python 复制代码
        # input editor
        self.editor = QTextEdit(self) # 创建输入文本框
        self.editor.setPlaceholderText("翻译内容") # 设置文本框的背景内容
        hlayout.addWidget(self.editor) # 将输入文本框添加到子布局中
        TextEditStyle(self.editor) # 修改文本框的样式,作者创建的方法,非第三方库调用
        # translation button
        self.button = QPushButton("翻译",self) # 创建翻译按钮
        btnReleaseStyleA(self.button) # 修改按钮的样式,作者创建的方法,非第三方库调用
        self.button.clicked.connect(self.translating) # 按钮点击状态连接到translating事件方法
        hlayout.addWidget(self.button) # 将按钮添加到子布局中
        
        # output edit
        self.textedit = QTextEdit(self) # 创建输出文本框
        self.textedit.setPlaceholderText("翻译结果") # 设置文本框的背景内容
        self.textedit.setReadOnly(True) # 设置文本框为只读
        hlayout.addWidget(self.textedit) # 将文本框添加到子布局中
        TextEditStyle(self.textedit) # 修改文本框的样式,作者创建的方法,非第三方库调用

这段代码并没有什么需要特殊注意的地方,在之前的文章中我们已经用过多次了

快速翻译列表UI设计

python 复制代码
        # list layout
        self.workdist = {'快进':'forward','后退':'backward','暂停':'pause','停止':'stop',
                         '播放':'play'}
        self.model = QStandardItemModel(0, 1) # 创建一个模型类,0行1列,即没有元素
        self.view = QListView(self) # 设置一个ListView对象
        self.view.setModel(self.model) # 设置ListView对象的模型为上面创建的模型
        for i in self.workdist.keys(): # 做一个for循环,循环从workdist中读取key
            item = QStandardItem(i) # 按顺序,将key设置为模型元素对象
            self.model.appendRow(item) # 将对象添加到模型中
        ListViewStyle(self.view) # 修改ListView的样式,作者创建的方法,非第三方库调用
        listlayout.addWidget(self.view) # 将ListView对象添加到子布局中
        self.view.clicked.connect(self.modelselected) # 将listview的点击状态连接到事件方法modelselected

这里新知识比较多,尤其是出现了一个陌生的控件QListView与一个模型类QStandardItemModel

  • QStandardItemModel的定义

    在 PyQt 中,QStandardItemModel 是一个常用的模型类,它提供了一种标准的方式来存储和管理数据,尤其是用于与视图类(如 QListViewQTreeViewQTableView)配合使用。QStandardItemModel 是一种基于项(Item)模型的数据结构,它通过 QStandardItem 类来表示每个数据项。

    QStandardItemModel 主要特点:

    1. 基于项的模型 :它使用 QStandardItem 来表示数据的每一项,QStandardItem 是存储数据和管理项状态的对象。
    2. 支持树形和表格数据 :通过 QStandardItemModel 可以管理数据,支持表格和树形结构。它可以通过层次结构来组织数据。
    3. 与视图(View)绑定QStandardItemModel 与 PyQt 中的视图类(如 QListViewQTreeViewQTableView)一起使用,模型控制数据,而视图负责数据的显示和交互。
  • QListView控件与QComboBox功能相似,但是用途,行为和样式差别较大,直接问大模型会给你长长的一条差别,但在这里,使用QListView的原因是它好看,可自定义样式,且不会收束成一个单个元素,而是完整地展示所有元素。

布局代码解释完了,接下来我们看一下实现交互功能的代码:

tranasexchange

python 复制代码
    def tranasexchange(self):
        cba = self.langfromcb.currentText()
        cbb = self.langtocb.currentText()
        if cba == "自动检测":
            cba = "English"
        self.langfromcb.setCurrentText(cbb)
        self.langtocb.setCurrentText(cba)

这个代码逻辑很简单实际上就是一个获取两个QComboBox的当前选择内容,然后交换它,因为langto并没有自动检测这一选项,所以当langfrom选择的是自动检测,则切换成English

translating

python 复制代码
    def translating(self):
        print(self.langfromcb.currentText()," to ",self.langtocb.currentText())
        text = self.editor.toPlainText()
        tran = Translation.translating(text,self.langfromcb.currentText(),self.langtocb.currentText())
        if tran == "website is not reachable":
            MsgClass().show_HTTP_error("Website is not reachable")
        else:
            self.textedit.setText(tran)
  • 首先将从什么语种翻译到什么语种打印到log面板上
  • text变量获取当前输入文本框中的文本内容
  • text中的文本内容,当前选择的两个语种,一共3个参数传入Translation对象的translating方法中,该方法才是真正实现翻译功能的方法,该方法会返回一个字符串,tran获取这个字符串
  • if的其实就是回应我们开头提出的问题:"需不需要判断网络问题"以及"如果网络异常该怎么办",在一开始,笔者并没有处理这个异常,直到有一次笔者挂了clash访问GitHub时,无法访问翻译网站,结果导致程序闪退,所以,必须要判断网络问题,才做了这个if判断来抛出异常,使脚本在遇到网络问题时依然能够正常运行。
  • MsgClass是笔者写的一个消息处理类,主要功能是获取文本,制作一个弹窗,弹窗内容就是获取到的文本,在这里是Website is not reachable
  • 如果网络没有问题,则不会将获取的文本输出到输出文本框中
  • 当然这个网络异常逻辑设计并不完美,因为有可能翻译的内容恰恰是website is not reachable,这样也会导致UI这一部分误以为是网络异常,从而弹窗警告。更优解时返回两个变量,一个变量是翻译内容,一个变量是网站访问情况。if检测网站访问情况,如果非200,如404,则抛出弹窗警告。

modelselected

python 复制代码
    def modelselected(self):
        print(self.view.currentIndex().data(),'to',self.workdist[self.view.currentIndex().data()])
        self.editor.setText(self.view.currentIndex().data())
        self.textedit.setText(self.workdist[self.view.currentIndex().data()])

如果是点击快速翻译中的某一项,则无需点击翻译按钮,直接完成翻译

  • 在log面板上打印当前选择的元素以及元素所对应的value(元素为字典中的key)
  • 将元素设置为输入文本框的内容
  • 将元素对应的value设置为输出文本框的内容

本文要点

  • 翻译器的主要UI布局其实是模仿目前市面上大多数的翻译器设计的,主要是模仿微软翻译 ,即:搜索 Microsoft Translator - 从英语翻译到中文 (简体)。其实,该翻译器的实现,主要也是爬取了微软翻译,翻译器模仿成用户,向微软翻译发送翻译文本,并获取返回的response,拿到翻译后的结果。之所以不爬取有道翻译,是因为有道翻译对爬虫限制很高,现在甚至无法打开开发者工具(如果在有道翻译页面强行打开开发者工具,会导致闪退该页面)。
  • 在这个页面的UI设计中,我们加入了许多新玩意儿,比如ListView,模型类QStandardItemModelQComboBox,等等有趣的东西,想使用但却没有实际例子模仿的小伙伴可以借鉴参考。
  • 在本文中我们回答了开头的五个问题中的两个,"是否需要判断当前状态是否联网"答案是:需要判断当前状态是否联网,如果不加以判断,当处于断网时,爬虫无法正常爬取网页,会抛出Error或Exception,如果处理,则会导致程序闪退。
  • "如果处于断网状态如何处理",答案是,当判断出断网状态时,会抛出弹窗警告,弹窗警告的设计是笔者自做,后续系列更新会介绍。
相关推荐
毕设源码-郭学长6 分钟前
【开题答辩全过程】以 基于python电商商城系统为例,包含答辩的问题和答案
开发语言·python
black0moonlight7 分钟前
win11 isaacsim 5.1.0 和lab配置
python
知乎的哥廷根数学学派11 分钟前
基于多尺度注意力机制融合连续小波变换与原型网络的滚动轴承小样本故障诊断方法(Pytorch)
网络·人工智能·pytorch·python·深度学习·算法·机器学习
网安CILLE12 分钟前
PHP四大输出语句
linux·开发语言·python·web安全·网络安全·系统安全·php
jjjddfvv13 分钟前
超级简单启动llamafactory!
windows·python·深度学习·神经网络·微调·audiolm·llamafactory
A先生的AI之旅16 分钟前
2025顶会TimeDRT快速解读
人工智能·pytorch·python·深度学习·机器学习
江公望18 分钟前
QT/QML qmlRegisterType()函数浅谈
开发语言·qt
程序员小远23 分钟前
完整的项目测试方案流程
自动化测试·软件测试·python·功能测试·测试工具·职场和发展·测试用例
程序猿阿伟25 分钟前
《量子算法开发实战手册:Python全栈能力的落地指南》
python·算法·量子计算
雪风飞舞38 分钟前
python根据音频生成柱状图
开发语言·python·音视频