Qt Designer极速开发python桌面小工具详解

原创 测试小酋 51STE软件测试部落 昨天

今天来讲下如何使用Qt Designer设计UI,快速实现pyhon桌面小工具的开发,且UI与逻辑分离。

我的环境如下:

  • Windows 7

  • Python 3.7.1

  • PyCharm PROFESSIONAL 2019.3 (你可以用各种同类IDE替代或者安装它)

  • PyQt5

  • Qt Designer

本文并不讨论Python和PyCharm的安装,关于PyCharm具体安装可以参见文章《2020最新Pycharm四步破解教程(永久破解)》(再次提醒,PyCharm版本需要与文中版本一致,否则可能导致破解失败)

一、安装PyQt5

下面直接使用pip来安装PyQt5,此处可能是pip/pip3,或者两者皆可,后面不再重复

1、直接pip安装PyQt5

    pip install PyQt5

    2、由于Qt Designer已经在Python3.5版本从PyQt5转移到了tools,因此我们还需要安装pyqt5-tools

      pip install pyqt5-tools

      3、到这一步,PyQt5就安装完成了,你可以通过下面来检查是否已经安装成功:

      在cmd中输入pyuic5,如果返回“Error: one input ui-file must be specified”说明安装成功。

      二、初识Qt Designer

      根据参考文章:在win10中可以用Win+S呼出Cornata主面板(搜索框)来启动各种应用,那么这里就是在搜索框中输入designer并敲回车,就能够启动Qt Designer了。

      但我的系统为win7,并不能这样操作,最后只有在python安装路径下搜索“designer.exe”

      最终路径为 :

      [python安装目录]/Lib/site-packages/qt5_applications/Qt/bin

      双击启动。初次启动会弹出这个“新建窗体”窗口,一般来说默认选择“Main Window”然后点击“创建”就可以了。下方有个“启动时显示这个对话框”的勾选框,如果不想每次启动都看到这个“新建窗体”窗口,可以取消勾选。

      创建“Main Window”之后,我们会看到如下画面:

      下面就来简单介绍下整个画面的构成:

      • 左侧的“Widget Box”就是各种可以自由拖动的组件;

      • 中间的“MainWindow - untitled”窗体就是画布;

      • 右上方的"对象查看器"可以查看当前ui的结构;

      • 右侧中部的"属性编辑器"可以设置当前选中组件的属性;

      • 右下方的"资源浏览器"可以添加各种素材,比如图片,背景等等,目前可以不管;

      大致了解了每个板块之后,就可以正式开始编写第一个UI了。

      三、绘制一个简单的汇率转换器UI

      1、添加输入框

      在左侧的“Widget Box”栏目中找到“Input Widgets”分类,将“Line Edit”拖拽到屏幕中间的“MainWindow”画布上,你就获得了一个单行输入框,如下图所示。

      2、添加文本

      在左侧的“Widget Box”栏目中找到“Display Widgets”分类,将“Label”拖拽到“Line Edit”旁边,你就获得了一个仅用于显示文字的文本框,如下图所示。

      双击上图中的“TextLabel”,就可以对文本进行编辑,这里我们将其改成美元缩写“USD”,如下图所示。如果文字没有完全展示出来,可以自行拖拽空间改变尺寸。

      特别提醒:编辑完文本之后记得敲击回车令其生效!

      3、添加按钮

      使用同样的方法添加一个按钮(PushButton)并将其显示的文本改成“转换”,如下图所示。

      4、按照上面1、2步骤,完善汇率UI,如下图所示。

      5、修改窗口标题

      下面修改窗口标题。选中右上方的"Object Inspector"中的“MainWindow”,然后在右侧中部的"属性编辑器"中找到“windowTitle”这个属性,在Value这一栏进行修改(改为“汇率换算器”),修改完记得敲击回车。

      6、编辑菜单栏

      注意到画布的左上方有个“在这里输入”(Type Here),双击它即可开始编辑菜单栏。菜单栏支持创建多级菜单以及分割线(separator)。我随意创建了一些菜单项目,如下图所示。

      7、预览

      使用快捷键Ctrl+R预览当前编写的GUI(或者从菜单栏的Form > Preview / Preview in进入)

      此时你尝试去缩放窗口,会发现组件并不会自适应缩放,因此我们需要回到Qt Designer中进行一些额外的设置。

      8、组件自适应

      点击画布空白处,然后在上方工具栏找到 下图四种布局,在本例中我们使用栅格布局(grid layout),即第三种。

      我们再次使用Ctrl+R预览,这次组件可以自适应了!

      9、保存

      如果觉得完成了,那就可以保存成*.ui的文件(快捷键:Ctrl+S),这里我们保存为conversion.ui。为了方便演示,我将文件保存到D盘新建目录QT下。

      10、生成Python代码

      使用cmd将目录切到目录 D:/QT 并执行下面的命令。请自行将下面命令中的name替换成文件名,比如本例中的“conversion.ui”

      pyuic5 -o conversion.py conversion.ui

      生成的代码应该类似下图所示

      11、运行Python代码

      此时尝试运行刚刚生成的“conversion.py”是没用的,因为生成的文件并没有程序入口。因此我们在同一个目录下另外创建一个程序叫做“main.py”,并输入如下内容。在本例中,gui_file_name就是conversion,请自行替换。

        import sysfrom PyQt5.QtWidgets import QApplication, QMainWindowimport gui_file_nameif __name__ == '__main__':    app = QApplication(sys.argv)    MainWindow = QMainWindow()    ui = gui_file_name.Ui_MainWindow()    ui.setupUi(MainWindow)    MainWindow.show()    sys.exit(app.exec_())

        然后运行“main.py”,你就能看到刚刚编写的GUI了!

        四、实现汇率换算逻辑

        刚刚写的汇率换算器中,我们设置的按钮(PushButton)是没有实际作用的,因为我们并没有告诉这个按钮应该做什么。实际上,要让这个按钮做点什么只需要增加一行代码就可以了。

        1、获取按钮id

        打开conversion.ui,在designer中选中对应的按钮,从“属性编辑器”中可以得知这个按钮的“objectName”叫做“pushButton”,如下图所示。

        2、设置触发

        QT中有“信号和槽(signal and slot)”这个概念,不过目前无需深究,也无需在Designer中去设置对应按钮的“信号和槽”,直接在“main.py”中“MainWindow.show()”的后面加入下面这样的一行代码

          ui.pushButton.clicked.connect(click_success)

          下面简单解释下这行代码:

          • pushButton就是刚刚获取的按钮id;

          • clicked就是信号,因为是点击,所以我们这里用clicked;

          • click_success就是对应要调用的槽,注意这里函数并不写成click_success();

          3、设置函数

          既然刚刚设置了按钮的触发并绑定了一个函数click_success,我们就要在“main.py”中实现它。示例如下

            def click_success():    print("搞定了!")

            4、运行!

            UI跟逻辑分离的好处就在这里,我们这次不用去管“conversion.py”了,直接运行修改完的“main.py”。点击按钮,这次你会发现在控制台中有了我们预设的输出。

            5、回到正题,我们这里需要通过UI传参实现汇率的转换

            对于传参,有两种解决方案,一种是使用lambda,还有一种是使用functool.partial。在接下来的环节中我们会使用partial。

            partial的用法如下所示:

              partial(function, arg1, arg2, ......)

              既然使用partial传参,那么我们就要在程序(main.py)的头部加上下面这行。

                from functools import partial

                然后我们把步骤2的按钮触发那行代码修改成下面这样。

                  ui.pushButton.clicked.connect(partial(convert, ui))

                  6、编写convert函数

                  首先,我们要获取用户输入的数字。为了使得教程简洁易懂,我们这次只讲解单向的汇率转换。既然是单向的转换,那么我们只需要获取左侧的文本框id。在本例中,左侧的文本框id为lineEdit。如果你对此感到一头雾水,请停下并回头复习。

                  获取文本使用的是text()方法,因此读取用户输入的代码如下

                    input = ui.lineEdit.text()

                    接着我们进行汇率转换,注意这里要进行类型转换

                      result = float(input) * 6.5344

                      最后我们让右边的文本框显示结果

                        ui.lineEdit_2.setText(str(result))

                        下面是main.py的完整代码

                          import sysfrom PyQt5.QtWidgets import QApplication, QMainWindowfrom functools import partialimport conversiondef convert(ui):    input = ui.lineEdit.text()    result = float(input) * 6.5344    ui.lineEdit_2.setText(str(result))if __name__ == '__main__':    app = QApplication(sys.argv)    MainWindow = QMainWindow()    ui = conversion.Ui_MainWindow()    ui.setupUi(MainWindow)    MainWindow.show()    ui.pushButton.clicked.connect(partial(convert, ui))    sys.exit(app.exec_())

                          一个简单的汇率转换器就这样诞生了!

                          那么,如何知道一个组件都有什么方法呢?直接去Qt官方文档(https://doc.qt.io/archives/qt-5.13/qtgui-module.html)查看就可以了。本节使用到的lineEdit的相关方法在这里(https://doc.qt.io/archives/qt-5.13/qtextedit.html)

                          五、线程执行逻辑

                          当我们实现复杂的逻辑,处理时间较长时,此时界面就会出现“未响应”。如我实现一个对网站生成sitemap的工具,点击按钮运行后出现卡死,如下图所示。

                          1、问题原因

                          在GUI程序中,主线程也叫GUI线程,因为它是唯一被允许执行GUI相关操作的线程。对于一些耗时的操作,如果放在主线程中,就是出现界面无法响应的问题。

                          在编写QT的界面程序时,当我们调用QApplication.exec()时,我们就启动了QT的事件循环。在开始的时候,QT会发出一些事件来显示和绘制窗口部件。在这之后,事件循环就开始运行,不断地检查是不是有事件发生并且把这些事件发送给应用程序中的QObject。

                          当一个事件被处理时,其他事件也可能会产生并且追加到QT的事件队列中。如果我们在处理一个特定的事件上耗费过多的时间,用户界面就会变得不能够响应。

                          2、解决思路

                          解决该问题的方法有很多,如使用QTimer不断应答的,这里我还是喜欢以线程的方式来处理。

                          如把类似按钮触发代码:

                            ui.pushButton.clicked.connect(partial(sitemapgo, ui))

                            改为:

                              thread = RunThread(ui)  # 创建一个线程ui.pushButton.clicked.connect(lambda: thread.start())

                              3、实现处理线程

                              1)首先加入QtCore包的引用

                                from PyQt5 import QtCorefrom PyQt5.QtCore import *

                                2)把原来的sitemapgo函数处理逻辑填入run中进行简单的改造,具体怎么改造,相信有python基础的朋友来说都不难。如果没有python基础,建议学习下runoob.com中的基础教程。

                                具体线程类实现代码如下:

                                  class RunThread(QThread):    # python3,pyqt5与之前的版本有些不一样    # 通过类成员对象定义信号对象    # _signal = pyqtSignal(str)    trigger = pyqtSignal()    def __init__(self, ui):        super(RunThread, self).__init__()        self.ui = ui    def __del__(self):        self.wait()    def run(self):        #线程处理逻辑        try:            …… #填入网站生成sitemap的逻辑        except:            print("出现异常错误!")        finally:            self.trigger.emit()if __name__ == '__main__':    app = QApplication(sys.argv)    MainWindow = QMainWindow()    ui = sitedog.Ui_MainWindow()    ui.setupUi(MainWindow)    MainWindow.show()    thread = RunThread(ui)  # 创建一个线程    ui.pushButton.clicked.connect(lambda: thread.start())    sys.exit(app.exec_())

                                  4、最后再来运行工具,就再也不会出现“未响应”错误了。

                                  六、实现控制台显示

                                  我们发现程序的输出都是在控制台打印的,非常不方便,这是该怎么输出到前端textBrowser中呢?这里我们修改gui_file_name.py文件(gui_file_name是什么?一头雾水请再复习下前面)

                                  1、首先引入sys

                                    import sys

                                    2、定义发送信号槽

                                      class EmittingStr(QtCore.QObject):    textWritten = QtCore.pyqtSignal(str) #定义一个发送str的信号    def write(self, text):      self.textWritten.emit(str(text))

                                      3、在类Ui_MainWindow中开始处添加

                                        class Ui_MainWindow(object):    def __init__(self):        # 下面将输出重定向到textBrowser中        sys.stdout = EmittingStr(textWritten=self.outputWritten)        sys.stderr = EmittingStr(textWritten=self.outputWritten)    def outputWritten(self, text):        cursor = self.textBrowser.textCursor()        cursor.movePosition(QtGui.QTextCursor.End)        cursor.insertText(text)        self.textBrowser.setTextCursor(cursor)        self.textBrowser.ensureCursorVisible()

                                        4、再来运行上面的sitemap生成工具,控制台没有再打印输出,都在textBrowser中显示了。

                                        到了这一步,我们的PyQT5工具开发就基本告一段落了。怎么样,很简单吧?

                                        参考文章:

                                        https://blog.csdn.net/azuremouse/article/details/90338961

                                        https://www.cnblogs.com/hhh5460/p/5175322.html

                                        https://blog.csdn.net/weixin_38308549/article/details/105200032

                                        http://www.45fan.com/article.php?aid=19062535244902109151948616

                                        -- End --



                                        文末寄语  用自己的努力换取成功,然后成功就会像一个大巴掌,打在那些曾经看不起你的人脸上,要多响有多响,要多爽有多爽。

                                        不看的原因确定内容质量低不看此公众号
                                        (0)

                                        相关推荐