使用PyQt5实现自动化测试,太便利了-程序员宅基地

技术标签: python  java  PyQt开发与实战  qt 进阶  编程语言  人工智能  gui  

关注、星标公众号,直达精彩内容

公众号:技术让梦想更伟大

作者:Boudewijn Rempt 和 David Mertz

最近在使用pyqt写个自动化测试软件,对python和Qt都需要有一些了解,输出这篇文章主要是想分享一下Qt和PyQt用于Python的高级GUI库的知识。也有些感慨,当然这个pyqt用不上的可以直接不看了,先分享几点。

  1. 嵌入式开发学的东西真的很多很多,各种单片机、模电数电硬件基础、Linux驱动内核、C/C++编程、Qt、计算机等相关知识。

  2. 在编程过程中,其实语言都是相通的,会了C语言其余的语言学起来就很快,编程的思想很重要,当然要是想的深好还是要多家钻研。

  3. 不要拒绝任何学习的机会,工作中常说这个我不会,或者这个跟我做的不相关;这种想法还是要摒弃,给自己一个机会,多动手。

Qt 和 PyQt 用于 Python 的高级 GUI 库

一般来说,选择用于应用程序的 GUI 工具箱会是一件棘手的事。使用 Python(许多语言也一样)的程序员可以选择的 GUI 工具箱种类繁多,而每个工具箱都有各自的优缺点。有些速度比其它工具箱快,有些比较小;有些易于安装,有些更适合于跨平台使用(对于这一点,还要指出,有些支持您需要满足的特定特性)。当然,各种库都相应具有各种许可证。

对于 Python 程序员而言,缺省的 GUI 选择是 Tk(通过 Tkinter 绑定)— 其原因显而易见。Tkinter 和闲置的 IDE 是由 Python 创始人编写的,它们是作为大多数 Python 分发版的缺省选择而出现的。标准 Python 文档讨论了 Tkinter,但没有涉及任何其它 GUI 绑定。这是故意的!至少可以这么认为,如果 Tk 和 Tkinter 不是这么糟糕,程序员就没有理由去寻找替代品了。要诱导 Python 程序员放弃缺省选择,那么工具箱必须提供额外的东西。PyQt 就是这样一个工具箱。

PyQt 所具有的优点远远超过了 Tkinter(它也有几个缺点)。Qt 和 PyQt 速度都很快;Qt 和 PyQt 的设计完全是面向对象的;Qt 提供了一个设计良好的窗口构件集合,它比 Tk 所提供的要大得多。就其缺点而言,Qt 的许可证受到的限制比许多工具箱(至少在非 Linux 平台方面)都多;正确安装 Qt 和 PyQt 常常会很复杂;另外,Qt 是一个相当大的库。PyQt 应用程序的用户将需要设法完成安装 Qt 和 PyQt,这使分发变得很困难。

PyQt 严格遵循 Qt 的发放许可。特别是,它可用于 UNIX/X11 平台上的 GPL,并可用于 Zaurus 上的 Qt Palmtop Environment 环境,还存在用于较老的 Qt 版本的免费(free-as-in-free-beer)Windows 软件包。PyQt 的商业许可证可用于 Windows。

对于本文而言,PyQt 有一个方面优于许多其它工具箱,它值得我们特别关注。Qt 使用一种称为 信号/插槽(signals/slots)的机制在窗口构件(以及其它对象)之间传递事件和消息。这种机制完全不同于包括 Tkinter 在内的大多数工具箱所用的回调(callback)机制。使用信号/插槽以灵活且可维护的方式控制对象间通信要比使用脆弱的回调风格容易得多。应用程序越大,Qt 的这个优势就越重要。

样本应用程序

要显示信号/插槽和回调之间的反差,我们提供了一个写着玩玩的应用程序,它使用 Tkinter 和 PyQt。尽管实际上 PyQt 版本对于这个基本程序并不更简单,但是它已经演示了 PyQt 应用程序更好的模块性和可维护性。

应用程序包括四个窗口构件:

  1. “Quit”按钮(用来与整个应用程序通信)

  2. “Log Timestamp”按钮(用于窗口构件间的消息)

  3. 文本区域,显示可滚动的已记录日志的时间戳记列表

  4. 消息窗口构件,显示已记录日志的时间戳记数

在 Tkinter 中,我们可以这样实现应用程序:

清单 1. Logger.py Tkinter 应用程序

#!/usr/bin/python
import sys, time
from Tkinter import *
class Logger(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.pack(expand=YES, fill=BOTH)
        self.master.title("Timestamp logging application")
        self.tslist = []
        self.tsdisp = Text(height=6, width=25)
        self.count = StringVar()
        self.cntdisp = Message(font=('Sans',24),
                               textvariable=self.count)
        self.log = Button(text="Log Timestamp",
                          command=self.log_timestamp)
        self.quit = Button(text="Quit", command=sys.exit)
        self.tsdisp.pack(side=LEFT)
        self.cntdisp.pack()
        self.log.pack(side=TOP, expand=YES, fill=BOTH)
        self.quit.pack(side=BOTTOM, fill=BOTH)
    def log_timestamp(self):
        stamp = time.ctime()
        self.tsdisp.insert(END, stamp+"\n")
        self.tsdisp.see(END)
        self.tslist.append(stamp)
        self.count.set("% 3d" % len(self.tslist))
if __name__=='__main__':
    Logger().mainloop()

这个 Tk 版本使用了 log_timestamp() 方法作为按钮的 command= 参数。这个方法需要依次单独操作它要影响的所有窗口构件。如果我们想更改按钮按下的效果(例如还要记录时间戳记),那么这个风格就很脆弱。通过继承您可以实现这一点:

清单 2. StdOutLogger.py Tkinter 增强

    class StdOutLogger(Logger):
def log_timestamp(self):
    Logger.log_timestamp(self)
    print self.tslist[-1]

但是这个子类的作者需要相当精确地理解 Logger.log_timestamp() 已经做了什么;而且除非通过在子类中完全重写 .log_timestamp() 方法并且不调用父方法,否则没有办法 除去消息。

一个非常基本的 PyQt 应用程序总有一些样本代码,这些代码在哪里都相同,Tkinter 代码也是这样。但是,当我们进一步研究设置应用程序所需的代码,以及显示窗口构件的代码时,区别就显现出来了。

清单 3. logger-qt.py PyQt 应用程序

    #!/usr/bin/env python
import sys, time
from qt import * # Generally advertised as safe
class Logger(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)
        self.setCaption("Timestamp logging application")
        self.layout = QGridLayout(self, 3, 2, 5, 10)
        self.tsdisp = QTextEdit(self)
        self.tsdisp.setMinimumSize(250, 300)
        self.tsdisp.setTextFormat(Qt.PlainText)
        self.tscount = QLabel("", self)
        self.tscount.setFont(QFont("Sans", 24))
        self.log = QPushButton("&Log Timestamp", self)
        self.quit = QPushButton("&Quit", self)
        self.layout.addMultiCellWidget(self.tsdisp, 0, 2, 0, 0)
        self.layout.addWidget(self.tscount, 0, 1)
        self.layout.addWidget(self.log, 1, 1)
        self.layout.addWidget(self.quit, 2, 1)
        self.connect(self.log, SIGNAL("clicked()"),
                     self.log_timestamp)
        self.connect(self.quit, SIGNAL("clicked()"),
                     self.close)
    def log_timestamp(self):
        stamp = time.ctime()
        self.tsdisp.append(stamp)
        self.tscount.setText(str(self.tsdisp.lines()))
if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.connect(app, SIGNAL('lastWindowClosed()'), app,
                  SLOT('quit()'))
    logger = Logger()
    logger.show()
    app.setMainWidget(logger)
    app.exec_loop()

通过创建布局管理器, Logger 类开始工作了。布局管理器在任何 GUI 系统中都是一个很复杂的主题,但是 Qt 的实现使之变得简单。在大多数情况下,您会使用 Qt Designer 创建一般的 GUI 设计,随后可将它用于生成 Python 或 C++ 代码。然后您可以使生成的代码生成子类,以添加功能。

但是在这个示例中,我们选择手工创建布局管理器。窗口构件被置于网格的各个单元中,或者可以跨多个单元放置。在 Tkinter 需要命名参数的地方,PyQt 就不允许它们。这是一个很重要的差异,它经常会使在两种环境中工作的人们无所适从。

所有 Qt 窗口构件都可以和 QString 对象很自然地一起工作,而不能和 Python 字符串或 Unicode 对象一起工作。幸运的是,转换是自动的。如果您在 Qt 方法中使用了字符串或 Unicode 参数,那么它将自动转换成 QString。不能进行反向转换:如果您调用了一个返回 QString 的方法,那么您获得的是 QString。

应用程序中最有趣的部分是我们将 clicked 信号连接到功能的位置。一个按钮连接到了 log_timestamp 方法;另一个连接到了 QWidget 类的 close 方法。

图 1. logger-qt 的屏幕快照

现在我们想将日志记录添加到这个应用程序的标准输出。这十分容易。我们可以使 Logger 类生成子类,或者为了演示,创建简单的独立函数:

清单 4. logger-qt.py PyQt 增强

   def logwrite():
    print(time.ctime())
if __name__ == "__main__":
   app = QApplication(sys.argv)
   app.connect(app, SIGNAL('lastWindowClosed()'), app,
               SLOT('quit()'))
   logger = Logger()
   QObject.connect(logger.log, SIGNAL("clicked()"), logwrite)
   logger.show()
   app.setMainWidget(logger)
   app.exec_loop()

从上述代码我们可以看到,这就是将 log QPushButton 的 clicked() 信号连接到新函数的事情。注:信号也可以将任何数据传送到它们所连接的插槽,尽管在这里我们没有显示这样的示例。

如果您不想调用原始方法,那么可以从插槽 disconnect 信号,例如通过在 logger.show() 行之前添加以下行:

清单 5. logger-qt.py PyQt 增强

QObject.disconnect(logger.log, SIGNAL("clicked()"),
logger.log_timestamp)

现在将不再更新 GUI。

用于 Python 的其它 GUI 绑定

PyQt 在给定实例中可能不是很有用,可能是许可证状态问题,也可能是平台可用性问题(或者,可能因为再分发很困难,例如大小很大)。由于这个原因(也为了比较),我们想指出一些用于 Python 的其它流行 GUI 工具箱。

Anygui

Anygui 实际上不是 GUI 工具箱,而是一个作用于大量工具箱(甚至是令人惊奇的象 curses 和 Java/Jython Swing 那样的工具箱)的抽象包装器。在编程风格方面,使用 Anygui 类似于使用 Tkinter,但是要选中这个底层工具箱,要么自动进行,要么进行配置调用。Anygui 很好用,因为它允许应用程序未经更改就可以运行在差异很大的平台上(但因此它支持受支持工具箱的“最低级公共特性”)。

PyGTK

PyGTK 绑定包装了 GPL 下使用的 GTK 工具箱,它是流行的 Gnome 环境的基础。GTK 在根本上是 X Window 工具箱,但是它还有 Win32 的 beta 级支持和 BeOS 的 alpha 级支持。在常规范例中,PyGTK 对窗口构件使用回调。绑定存在于 GTK 和 大量编程语言之间,而不仅仅是 Qt,或甚至是 Tk。

FXPy

Python 绑定 FXPy 包装了 FOX 工具箱。FOX 工具箱已经被移植到大多数类 UNIX 平台上,以及 Win32 上。与大多数工具箱类似,FOX 和 FXPy 都使用回调范例。FOX 由 LGPL 特许。

wxPython

这个绑定包装了 wxWindows 工具箱。与 FOX 或 GTK 类似,wxWindows 被移植到 Win32 和类 UNIX 平台上(但是没有移植到 MacOS、OS/2、BeOS 或其它“次要”平台上 — 尽管它对 MacOSX 的支持是 alpha 级的)。在范例方面,wxPython 接近回调风格。wxPython 对继承结构的关注程度高于大多数其它工具箱,而且它使用“事件”,而不是回调。但是本质上,事件仍旧被连接到单个方法上,随后可能需要作用于各种窗口构件。

win32ui

win32ui 属于 win32all 软件包,它包装了 MFC 类。很显然,这个工具箱是特定于 Win32 的库。MFC 实际上不只是 GUI 工具箱,它还使用各种范例的混合。对于想创建 Windows 应用程序的读者而言,与其它工具箱相比,win32ui 会让您“更接近于实质”。

从其它语言使用 Qt

如同 Python,从大量其它编程语言使用 Qt 工具箱是可能的。如果可以自由选择,我们会首选 Python,而不是其它语言。诸如公司政策以及与其它代码库连接之类的外部约束可以决定编程语言的选择。Qt 的原始语言是 C++,但也有用于 C、Java、Perl 和 Ruby 的绑定。就与 Python 示例的比较而言,让我们讨论一下用 Ruby 和 Java 写着玩玩的应用程序。

Ruby/Qt 在用法上十分类似于 PyQt。这两种语言具有相似的动态性和简明性,所以除了拼写上的差别外,其代码很类似:

清单 6. HelloWorld.rb Qt2 应用程序

#!/usr/local/bin/ruby
require 'qt2'
include Qt2
a = QApplication.new([$0] + ARGV)
hello = QPushButton.new('Hello world!')
hello.resize(100, 30)
a.connect( hello, QSIGNAL('clicked()'), a, QSLOT('quit()'))
a.setMainWidget(hello)
hello.show
a.exec

Java 总是比脚本编制语言要冗长一点,但是基本部分都相同。一个同等功能的最小 qtjava 应用程序类似于:

清单 7. HelloWorld.java Qt2 应用程序

import org.kde.qt.*;
public class HelloWorld {
  public static void main(String[] args)
  {
    QApplication myapp = new QApplication(args);
    QPushButton hello = new QPushButton("Hello World", null);
    hello.resize(100,30);
    myapp.connect(hello, SIGNAL("clicked"),
                  this, SLOT("quit()"));
    myapp.setMainWidget(hello);
    hello.show();
    myapp.exec();
    return;
  }
  static {
    System.loadLibrary("qtjava");
    try {
        Class c = Class.forName("org.kde.qt.qtjava");
    } catch (Exception e) {
        System.out.println("Can't load qtjava class");
    }
  }
}

PyQt 是一个吸引人和快速的接口,它将 Qt 工具箱和 Python 编程语言集成在一起。除了该工具箱提供的种类繁多的窗口构件外,Qt 所用的信号/插槽编程风格在生产能力和可维护性方面都要优于大多数其它 GUI 工具箱所用的回调风格。

https://www.ibm.com/developerworks/cn/linux/l-qt/index.html

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

扫描下方微信,加作者微信进技术交流群,请先自我介绍喔。

推荐阅读:

嵌入式编程专辑Linux 学习专辑C/C++编程专辑
Qt进阶学习专辑关注微信公众号『技术让梦想更伟大』,后台回复“m”查看更多内容。
长按前往图中包含的公众号关注
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012846795/article/details/113287205

智能推荐

如何在Github上建立自己的个人博客网站详细教程_github个人网站-程序员宅基地

文章浏览阅读5.5k次,点赞5次,收藏56次。概述之前闲着没事,就利用Github建了一个个人博客网站,效果还不错,今天就来分享一下.建立自己个人博客网站的好处:1.面试装逼,这个不必多说…2.把平时积累的知识和项目记录下来,方便日后查看使用3.不受其他博客平台的限制准备工作开始之前,先大致介绍一下用到的技术和相关概念Github是什么:GitHub是一个利用Git进行版本控制、专门用于存放软件代码与内容的共享虚拟主机服务,很多人都把它称作程序员的同性交友网站,具体为啥这么叫我也不知道GitHub Pages是什么?_github个人网站

oneAPI GPU 优化指南 - 使用库进行 GPU 部署-程序员宅基地

文章浏览阅读49次。oneAPI 工具包提供了几个库, 可以通过提供专门的 API 简化编程过程, 用于优化应用程序。本节提供了使用库的步骤, 包括代码示例,用于应用程序加速。有关每个库的详细信息,包括可用的 API, 请参阅特定库的主要文档。

深度学习:transformer模型-程序员宅基地

文章浏览阅读5.6w次,点赞78次,收藏490次。Google于2017年6月发布在arxiv上的一篇文章《Attention is all you need》,提出解决sequence to sequence问题的transformer模型,用全attention的结构代替了lstm,抛弃了之前传统的encoder-decoder模型必须结合cnn或者rnn的固有模式,只用attention,可谓大道至简。文章的主要目的是在减少..._transformer模型

探索 iOS 面试之道:ChenYilong 的《iOS面试问题集锦》-程序员宅基地

文章浏览阅读355次,点赞4次,收藏9次。探索 iOS 面试之道:ChenYilong 的《iOS面试问题集锦》项目地址:https://gitcode.com/ChenYilong/iOSInterviewQuestions项目简介在软件开发领域,尤其是 iOS 开发,面试是一个至关重要的环节。ChenYilong/iOSInterviewQuestions 是一个由资深 iOS 开发者陈一龙(GitHub ID: ChenYil...

模电·PN结_pn结 电位差u ho下标ho什么意思-程序员宅基地

文章浏览阅读251次。在高掺杂的情况下,因耗尽层宽度很窄,不大的反向电压就可在耗尽层形成很强的电场,而直接破坏共价键,使价电子脱离共价键素服,产生电子-空穴对,致使电流急剧增大,这种击穿称为齐纳击穿,可见齐纳击穿电压较低。由于扩散到P区的自由电子与空穴复合,而扩散到N区的空穴与自由电子复合,所以在交界面附近多子的浓度下降,P区出现负离子区,N区出现正离子区,他们是不能移动的,称为空间电荷区,从而形成内电场。此时外电场使空间电荷区变宽,加强了内电场,阻止扩散运动的进行,而加剧漂移运动的进行,形成反向电流,也称为漂移电流。_pn结 电位差u ho下标ho什么意思

运算放大器_simulink运算放大器-程序员宅基地

文章浏览阅读8.1k次,点赞10次,收藏32次。集成电路运算放大器运算放大器的代表符号运算放大器的电路模型 电压传输特性:通常Avo都非常大,ab段几乎是一条垂直线,所跨越范围称为线性区;输出电压Vo不能超过正V+、负V-电压,这段被称为限幅区。理想运算放大器1.输出电压v0的饱和极限值等于运放的电源电压,即+Vom = V+和-Vom = V-。2.开环增益很高,若(Vp - Vn) > 0,则Vo趋于正饱和极限电压+Vom = V+;反之若(Vp - ..._simulink运算放大器

随便推点

Android中JNI与NDK_ndkj-程序员宅基地

文章浏览阅读879次。Android中JNI与NDK_ndkj

思维训练第三课 反意疑问句-程序员宅基地

文章浏览阅读1.1k次,点赞24次,收藏21次。提示:以下是本篇文章正文内容,下面案例可供参考英语中,反意疑问句是由陈述句和附在其后的附加疑问句组成。其中附加疑问句是对陈述句所说的事实或观点提出疑问,起证实作用,一般用于证实说话者所说的事实或观点。反意疑问句是英文中常见的一种句型,它提出情况或看法,询问对方同意与否,被广泛应用于英语口语。反意疑问句通常由两部分构成:前一部分用陈述句的形式(statement),后一部分是一个附着在前一部分上的简短问句(也叫tag question)。所附简短问句中的主语和谓语与陈述句的保持一致,而且两部分的时态要一致。

共阳极数码时钟c语言程序,基于51单片机C语言数字钟程序.doc-程序员宅基地

文章浏览阅读361次。基于51单片机C语言数字钟程序基于51单片机C语言数字钟程序数字电子钟的设计一、 绪论(一)引言20世纪末,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,有力地推动了社会生产力的发展和社会信息化程度的提高,同时也使现代电子产品性能进一步提高,产品更新换代的节奏也越来越快。时间对人们来说总是那么宝贵,工作的忙碌性和繁杂性容易使人忘记当前的时间。忘记了要做的事情,当事情不..._单片机 电子钟八段共阳极c语言

Wireshark使用(捕获过滤器、显示过滤器、TCP交互抓包示例、抓取本地回环数据包等)_通过操作实例说明wireshark捕获过滤器和显示过滤器的使用-程序员宅基地

文章浏览阅读3.5k次,点赞2次,收藏21次。这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar_通过操作实例说明wireshark捕获过滤器和显示过滤器的使用

快速搞定前端JS面试 -- 第六章 JS-Web-API-DOM-程序员宅基地

文章浏览阅读808次,点赞25次,收藏26次。整理面试题,不是让大家去只刷面试题,而是熟悉目前实际面试中常见的考察方式和知识点,做到心中有数,也可以用来自查及完善知识体系。《前端基础面试题》,《前端校招面试题精编解析大全》,《前端面试题宝典》,《前端面试题:常用算法》PDF完整版点击这里领取整理面试题,不是让大家去只刷面试题,而是熟悉目前实际面试中常见的考察方式和知识点,做到心中有数,也可以用来自查及完善知识体系。《前端基础面试题》,《前端校招面试题精编解析大全》,《前端面试题宝典》,《前端面试题:常用算法》PDF完整版点击这里领取。

Python打包exe和生成安装程序_python生产安装包-程序员宅基地

文章浏览阅读1.1k次。python打包成exe文件的一般步骤如下:除了上述基本步骤外,还有一些可选的参数和技巧可以用来优化打包过程和结果,例如:_python生产安装包

推荐文章

热门文章

相关标签