自学内容网 自学内容网

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的布局

        # 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(按钮)组成

        # 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设计

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

        # 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设计

        # 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

    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

    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

    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,如果处理,则会导致程序闪退。
  • “如果处于断网状态如何处理”,答案是,当判断出断网状态时,会抛出弹窗警告,弹窗警告的设计是笔者自做,后续系列更新会介绍。

原文地址:https://blog.csdn.net/whale_cat/article/details/143603493

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!