鱼C论坛

 找回密码
 立即注册
查看: 103151|回复: 129

[技术交流] PyQt5学习与交流

  [复制链接]
发表于 2015-4-1 23:45:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 lightninng 于 2021-11-20 14:39 编辑

平时时间不多,主要是跑数据程序,不过总是对有界面的程序有种憧憬,于是抽时间学一学pyqt5,本贴的平台是python3.3+pyqt5.2.1,搜索之后发现网上pyqt5的教程比较少,仅根据一个PyQt4入门指南开始学习,主要的内容都是从PyQt4入门指南中粘贴的,但是代码都是我自己用python3.3_pyqt5.2.1实现过的,还有一些感悟和疑问

当然,我还参考了http://hi.baidu.com/lovebabycase/item/c29f74c205e4e0d9ee183bde这个好贴以及百度的一些内容
PS:有鱼油说这篇失效了,有人已经把它转到百度文库了在这里
http://wenku.baidu.com/link?url=wOH8dLQjqWg4PZ-3arT7fyEpEalgIcnyHy39HkVbY5kM4z6-cLD-KjXN--ZQP4CqVQ7HfU3CUrYibOT_SYVaMqOqDNCGgou6CdkGDMl-hsi

自己很多东西弄不明白,会在贴中用红字标出来,希望有知道的朋友可以回复指


至26楼为止原PyQt4入门指南(The PyQt4 tutorial)中的相关内容已经更新完毕,所有内容均已加入贴中,代码也在用python3.3+pyqt5.2正确的跑通了,后面会针对最后一章的俄罗斯方块代码再做一些解释和改进~由于自己很懒,这部分缓慢施工中,同样的会慢,但是不会坑

_____________________________________________________________________________________________________
因为各种各样的原因坑了两年,些贴不一定会再次更新~~~等我提起劲头来的~~

_____________________________________________________________________________________________________
2021.11.20
我回来了,时隔多年,回到论坛感觉冷清了不少,有些感慨,当初在坛子里认识的朋友,最近的也有一两年没在坛子里活跃了,不过这些年每次打开鱼C都会看到几个帖子里面鱼油的回帖。为了完成当年的承诺,也给这个帖子一个完结,我决定把当初的PyQt4入门指南的翻译的最后一部分,俄罗斯方块完成。
不过毕竟这么多年过去了,不论是我自己的关注的方向,还是各种库的发展,都和当初有所不同,所以这次针对俄罗斯方块的更新也会有所变化。
首先,图形库的选择——PySide2

当初选择pyqt5,而不是4最简单的想法就是学新不学旧,就像当初选择python3而不是python2一样,但是时过境迁,我们又有了新的选择那就是PySide2,最近学期PySide2的原因也很简单,因为正好有比较好的学习资料(其实有时候选择的理由不需要太多),感兴趣的朋友去B站搜索pyside2就好了,纯分享,非引流。坛子里也有版主很早就分享了PySide2和PyQt5的对比(详情移步https://fishc.com.cn/forum.php?mod=viewthread&tid=146046

关于迁移成本,其实现阶段学习的简单代码你把代码里面的PyQt5替换为PySide2几乎都能直接运行起来,深入的学习过PyQt5的鱼油应该也不会来看这个入门级的帖子。少数运行不起来的一般是因为两个库下,有个别模块的位置有调整,这个只需要百度一下就能解决。


其次,更新的形式,尽量详尽,同时在原作品的基础上增添一些新的东西

既然,选择来填坑,那自然是希望这个坑可以填平,所以更新方式还和以前一样,尽量详细的解释各种细节,虽然可能让某些技术好的鱼油觉得啰嗦,但这毕竟是一个初级的帖子,个人水平也有限。


最后,让我们开始吧,让我们从烂尾的地方开始。。。


点评

我很赞同!: 5.0
我很赞同!: 5
o(≧v≦)o~~好棒  发表于 2015-6-4 00:50

评分

参与人数 9荣誉 +42 鱼币 +47 贡献 +34 收起 理由
continent + 5 + 5 + 3 感谢楼主无私奉献!
nforev + 5 + 5 + 3
轩辕匡华 + 5 + 5 + 3
vincent207 + 2 + 2 + 2
收敛函数 + 5 + 5 + 3 qt5的资料太少 感谢楼主无私分享
康小泡 + 10 + 10 + 10 支持楼主,(づ ̄ 3 ̄)づ
戴宇轩 + 5 + 5 + 5 感谢楼主无私奉献!
qq351317878 + 5 热爱鱼C^_^
~风介~ + 5 + 5 + 5 感谢楼主无私奉献!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-4-1 23:55:53 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-19 02:24 编辑

1.PyQt5工具包简介
1.1 关于本指南
这是一个入门级的PyQt指南。其目的在于引导读者快速上手PyQt5工具包。
PS:本指南英文名叫入The_PyQt4_tutorialPyQt4入门教程,网上有pdf版的中文版但是只到第7章,而且翻译作者觉得没有必要的部分他没有加入,后来我找到了这个贴子http://wiki.woodpecker.org.cn/moin/The_PyQt4_tutorial,它是对The_PyQt4_tutorial的完整翻译版本,但是里面的代码有一些小的错误,另外是针对PyQt4的,现在PyQt5已经出来了,而且和PyQt4最大的不同是在信号槽部分(其实是在PyQt4.5版本的改动),所以我根据The_PyQt4_tutorial写了这个贴子,主要是跟着The_PyQt4_tutorial这篇教程学习PyQt5。以下教程中的所有代码均在pyqt5.2.1+python3.3.2+windows7_64位环境下创建并通过测试。
1.2 关于PyQt
PyQt是用来创建GUI应用程序的工具包。它是Python编程语言与已获得成功的Qt库的混合体。其中Qt库是这个星球上最强大的GUI库之一。PyQt的官方网站是http://www.riverbankcomputing.com/software/pyqt/intro它由PhilThompson创建。
PyQt的实现被视作Python的一个模块。它由300多个类和接近6000个函数与方法构成。作为一个跨平台的工具包,PyQt可以在所有主流的操作系统上运行(Unix、Windows、Mac)。PyQt有两种许可,开发者可以在GPL和商业许可证之间做出选择。之前,PyQt的GPL许可证只在Unix系统上可用,但在PyQt4之后,其GPL许可证适用于所有支持它的系统。
因为PyQt5中有大量的类,为便于管理,它们被划分到如下的几个模块中。
注:下面这个图和模块介绍不一定对,这是pyqt4的结构和介绍。

其中QtCore模块包含了核心的非GUI功能函数,用于以下方面:日期、文件和目录、数据结构、数据流、URL、MIME、线程和进程。QtGui模块则包含了绘图组件以及与绘图相关的类,比如按钮、窗口、状态栏、工具栏、滑块、位图、颜色、字体等。QtNetWork模块包含用于网络编程的类,用户可以用这些类实现TCP/IP和UDP的客户端或服务器。并且使用这些类会使网络编程更加容易、轻便。QtXml包含用于处理XML文件的类,该模块提供了SAX和DOMAPI两种XML文件处理方式的实现。QtSvg模块包含了用于显示SVG(可缩放矢量图形,参考http://zh.wikipedia.org/wiki/SVG)文件内容的类。QtOpenGL模块用于渲染使用OpenGL库创建的3D或2D图形。并且它支持QtGUI库和OpenGL库的无缝结合。QtSql则库提供了用于操作数据库的类。
在pyqt5中,模块的结构有所改变, PyQt4的QtGui模块在PyQt5中分为了QtGui,QtPrintSupport和QtWidgets三个模块。PyQt4的QtOpenGL模块中,只有QGLContext,QGLFormat和QGLWidget这三个类还可以在PyQt5中使用。
1.3 关于python
Python是一门很成功的脚本语言。最初由Guido van Rossum提出。第一版于1991年发布。Python从ABC和Haskell编程语言获得灵感,Python是一种高阶的、常规用途的、多平台的解释语言。有些人更愿意称之为动态语言。它很容易入门。Python是一种简单的语言,它的最显著的特性之一就是不用使用分号或括号,而是使用回车和空格分隔语句和函数。 Python 2.5版,于2006年9月发布。今天,Python由遍布全世界的一大群志愿者维护。
TIOBE编程社区索引显示了各种不同编程语言理论上的使用情况。java是冠军,C++语言在下降,但是C++在将来的十年会一直被应用,并且看起来它的地位没有真正的受到威胁。我们可以清楚的看到编程语言中特殊性。Java主要用在企业项目和移动设备项目。C是系统编程之王(OS,设备驱动,小的应用),PHP在中小型网站的应用中处于统治地位,Javascript应用在网络应用的客户端。
  
Position
  
Language
Ratings
1
Java
21.7%
2
C
14.9%
3
Visual Basic
10.7%
4
PHP
10.2%
5
C++
9.9%
6
Perl
5.4%
7
C#
3.4%
8
Python
3.0%
9
JavaScript
2.7%
10
Ruby
2.0%
Python目前位于第8位。Ruby语言刚进入前十。Python最接近的竞争者是Ruby和Perl。
1.4 python的图形界面工具集
为了创建图形用户界面,python工程师可以有三种选择,PyGTK, wxPython和PyQt。选择那种工具依赖于细节。
1.5 PyQt5怎么学
偶然看到了知乎了一篇帖子,转过来大家参考
http://www.zhihu.com/question/26492283
1.      看官方文档
2.      看 Qt 教程,然后对应到 PyQt
3.      看 PyQt4 的教程
4.      看 PyQt4 对应 PyQt5 的改动说明,边看边写
因为我不会 python,而 python 3 的资料还比较少(至少当时没找到多少),所以我还看了:
1.      python 2.7 的教程和参考手册
2.      python 3 对应 python 2 的改动说明,边看边写
然后自己做学习笔记,大概像这样:


1.jpg

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +5 收起 理由
戴宇轩 + 5 + 5 + 5 感谢楼主无私奉献!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-1 23:59:53 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-18 20:31 编辑

2初次使用PyQt5工具包编程
         这一部分我们将学习一些基本的功能。这里的讲解很详细,就像我们和孩子对话一样。孩子迈出第一步总是笨拙的,初学者的第一次尝试也是如此。记住,没有笨人,只有懒惰的和固执的人。
2.1 一个简单的例子
这段代码非常简单,它的作用只是显示一个小的窗口,然而你可以对这个窗口作很多事情。我们可以改变窗口尺寸,最大化、最小化窗口。为了实现这些功能,我们需要编写大量的代码。但是,已经有人将这些实现这些功能的代码写好了,因为这些操作在很多的程序中都是重复出现的,没有必要一次一次的重新写这些代码,所以这些代码向PyQt的使用者隐藏了。PyQt 是一种高层的工具集,如果我们用更底层的工具,以下的示例代码将会超过几十行。
  1. # -*- coding: utf-8 -*-
  2. """第一个程序"""
  3. from PyQt5 import QtWidgets
  4. import sys
  5. app = QtWidgets.QApplication(sys.argv)
  6. first_window = QtWidgets.QWidget()
  7. first_window.resize(400, 300)
  8. first_window.setWindowTitle("我的第一个程序")
  9. first_window.show()
  10. sys.exit(app.exec_())
复制代码
  1. from PyQt5 import QtWidgets
  2. import sys
复制代码
这两句用来载入必须的模块。基本的GUI窗口部件在QtWidgets模块中。
  1. app = QtGui.QApplication(sys.argv)
复制代码
每一个PyQt5程序都需要有一个application对象,application类包含在QtGui模块中。sys.argv参数是一个命令行参数列表。Python脚本可以从shell中执行,参数可以让我们选择启动脚本的方式。
PS:这里作者说的很简单,关于sys.argv这个东西并未进行介绍,有兴趣的同学请看这个贴子8楼最下面的那几行对它有解释
http://bbs.fishc.com/forum.php?mod=viewthread&tid=59410&page=1&extra=#pid2308195
  1. first_window = QtWidgets.QWidget()
复制代码
QWidget部件是PyQt5中所有用户界面类的父类。这里我们使用没有参数的默认构造函数,它没有继承其它类。我们称没有父类的first_window为一个window。
  1. first_window.resize(250,150)
复制代码
resize()方法可以改变窗口部件的大小,在这里我们将其设置为250像素宽,150像素高。
  1. first_window.setWindowTitle("我的第一个程序")
复制代码
这句用来设置窗口部件的标题,该标题将在标题栏中显示。
  1. first_window.show()
复制代码
show()方法将窗口部件显示在屏幕上。
  1. sys.exit(app.exec_())
复制代码
最后我们进入该程序的主循环。事件处理从本行语句开始。主循环接受事件消息并将其分发给程序的各个部件。如果调用exit()或主部件被销毁,主循环就会结束。使用sys.exit()方法退出可以确保程序可以完整的结束,这种情况下系统的环境变量会记录程序是如何退出的。
也许你会疑惑,为什么exec_()方法会有一个下划线。这是因为exec是Python的关键字,
为避免冲突,PyQt使用exec_()替代。

                               
登录/注册后可看大图

截图:第一个程序


2.2设置程序图标
程序图标就是一个小图片,通常显示在程序标题栏的左上角。在以下的示例中,我们将学习如何在PyQt中使用程序图标,另外我们还将学习一些新的方法。
  1. # -*- coding: utf-8 -*-
  2. """图标"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtGui


  5. class Icon(QtWidgets.QWidget):
  6.     def __init__(self, parent = None):
  7.         QtWidgets.QWidget.__init__(self, parent)

  8.         self.setGeometry(300, 300, 250, 150)
  9.         self.setWindowTitle("图标")
  10.         self.setWindowIcon(QtGui.QIcon(r'sample.ico'))


  11. app = QtWidgets.QApplication(sys.argv)
  12. icon = Icon()
  13. icon.show()
  14. sys.exit(app.exec_())
复制代码
上一个示例采用了面向过程的方法编写。Python语言同时支持面向过程和面向对象两种编程方法。PyQt编程是面向对象的。

  1. class Icon(QtWidgets.QWidget):
  2.     def __init__(self, parent = None):
  3.         QtWidgets.QWidget.__init__(self, parent)
复制代码
面向对象编程中最重要的是类、属性和方法。以上代码中,我们创建了一个名为Icon的新类,该类继承QtWidgets.QWidget类。因此我们必须调用两个构造函数——Icon的构造函数和继承类QtGui.QWidget类的构造函数。
  1.         self.setGeometry(300, 300, 250, 150)
  2.         self.setWindowTitle("图标")
  3.         self.setWindowIcon(QtGui.QIcon(r'sample.ico'))
复制代码
setGeometry()方法完成两个功能——设置窗口在屏幕上的位置和设置窗口本身的大小。它的前两个参数是窗口在屏幕上的x和y坐标。后两个参数是窗口本身的宽和高。setWindowIcon()方法用来设置程序图标,它需要一个QIcon类型的对象作为参数。调用QIcon构造函数时,我们需要提供要显示的图标的路径(相对或绝对路径)。

                               
登录/注册后可看大图

截图:图标程序

PS:之前设置图标总是不成功,现在找到原因是用了相对路径,这里如果图标显示不出,请使用绝对路径。如果还是显示不出,放在系统变量path里所在的某个文件夹中,然后直接用文件名调用;亦或使用os.path.append()命令将图标文件所在文件夹暂时加入path中,然后直接用文件名调用。

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
戴宇轩 + 5 + 5 感谢楼主无私奉献!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 4 反对 0

使用道具 举报

 楼主| 发表于 2015-4-2 09:05:14 | 显示全部楼层
本帖最后由 lightninng 于 2015-7-4 23:44 编辑

2.3显示提示信息

我们可以为任何窗口部件设置一个悬停提示。
  1. # -*- coding: utf-8 -*-
  2. """悬停提示信息"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore, QtGui


  5. class Tooltip(QtWidgets.QWidget):
  6.     def __init__(self, parent=None):
  7.         QtWidgets.QWidget.__init__(self, parent)

  8.         self.setGeometry(835, 465, 250, 150)
  9.         self.setWindowTitle("提示信息")

  10.         self.setToolTip("This is a <b>QWidget<b> widget")
  11.         # QtWidgets.QToolTip.setFont(QtGui.QFont("Times", 10))


  12. app = QtWidgets.QApplication(sys.argv)
  13. tooltip = Tooltip()
  14. tooltip.show()
  15. sys.exit(app.exec_())
复制代码
         在本示例中,我们为一个QWidget类型的窗口部件设置工具提示。
  1. self.setToolTip('Thisis a<b>QWidget</b>widget')
复制代码
要创建工具提示,则需要调用setToolTip()方法。该方法接受丰富的文本格式参数。
  1. QtWidgets.QToolTip.setFont(QtGui.QFont("Times", 10))
复制代码
因为默认的QToolTip字体看起来比较糟糕,我们可以通过上面的语句设置想要的字体和字体大小。另外,有鱼油提到直接在setToolTip方法传入的字符串中可以通过应用html语言设置字体和字体大小 (详见68#)
1.jpg

截图:提示信息程序
2.4 关闭窗口
一个显而易见的关闭窗口的方式是单击标题栏右上角的X标记。在接下来的示例中,我们将展示如何用代码来关闭程序,并简要介绍Qt的信号和槽机制。
下面是QPushButton的构造函数,我们将会在下面的示例中使用它。
  1. QPushButton(string text, QWidget parent = None)
复制代码
text 表示将显示在按钮上的文本。parent是其对象,用于指定按钮显示在哪个部件中。在我们的示例中,parent为是一个QWidget对象。
  1. # -*- coding: utf-8 -*-
  2. """用按钮关闭程序"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore, QtGui


  5. class QuitButton(QtWidgets.QWidget):
  6.     def __init__(self, parent=None):
  7.         QtWidgets.QWidget.__init__(self, parent)

  8.         self.setGeometry(300, 300, 250, 150)
  9.         self.setWindowTitle("我的关闭程序")
  10.         quit_button = QtWidgets.QPushButton("关闭", self)
  11.         quit_button.setGeometry(10, 10, 60, 35)
  12.         
  13.         quit_button.clicked.connect(QtWidgets.qApp.quit)
  14.         
  15. app = QtWidgets.QApplication(sys.argv)
  16. quitbutton = QuitButton()
  17. quitbutton.show()
  18. sys.exit(app.exec_())
复制代码
  1. quit_button = QtWidgets.QPushButton("关闭", self)
  2. quit_button.setGeometry(10, 10, 60, 35)
复制代码
以上两句用来创建一个按钮并将其放在QWidget部件上,就像我们将QWidget部件放在屏幕上一样。
  1. quit_button.clicked.connect(QtWidgets.qApp.quit)
复制代码
PyQt5的事件处理系统建立在信号-槽机制之上。如果我们单击quit按钮,那么信号clicked就会被触发,槽函数可以是PyQt自带的槽函数,也可以是任何Python可以调用的函数等。QtCore.QObject.connect()方法可以将信号和槽函数连接起来。在我们的示例中槽函数是PyQt中已定义的quit()函数。通过connect方法就可以建立发送者(quit按钮)和接受者(应用程序对象)之间的通信。
Pyqt4pyqt5在信号槽这里是有一些不同的,以下是两pyqt4和pyqt5中将quit_button按下的信号和程序退出的槽函数连接起来的语句对比
  1. quit_button.clicked.connect(QtWidgets.qApp.quit)  # pyqt5中的做法
  2. self.connect(quit,QtCore.SIGNAL('clicked()'),QtGui.qApp,QtCore.SLOT('quit()'))  # pyqt4中的做法
复制代码
具体的不同请参看pyqt5的参考文档
6.jpg



7.jpg

截图:我的关闭程序







想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-4-2 10:02:11 | 显示全部楼层
谢谢,pyqt的资料太少了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-2 12:08:16 | 显示全部楼层
大水牛 发表于 2015-4-2 10:02
谢谢,pyqt的资料太少了。

欢迎交流~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-2 23:07:29 | 显示全部楼层
本帖最后由 lightninng 于 2015-4-25 23:35 编辑

2.5 消息窗口
默认情况下,如果我们单击了窗口标题栏上的X标记,窗口就会被关闭。但是有些时候我们想要改变这一默认行为。比如,我们正在编辑的文件内容发生了变化,这时若单击X标记关闭窗口,编辑器就应当弹出确认窗口。
  1. # -*- coding: utf-8 -*-
  2. """消息窗口示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtGui, QtCore


  5. class MessageBox(QtWidgets.QWidget):
  6.     def __init__(self, parent=None):
  7.         QtWidgets.QWidget.__init__(self, parent)
  8.         self.setGeometry(300, 300, 250, 150)
  9.         self.setWindowTitle("消息窗口演示程序")

  10.     def closeEvent(self, event):
  11.         reply = QtWidgets.QMessageBox.question(self,'确认退出','你确定要退出么?',
  12.                                                QtWidgets.QMessageBox.Yes,
  13.                                                QtWidgets.QMessageBox.No)
  14.         if reply == QtWidgets.QMessageBox.Yes:
  15.             event.accept()
  16.         else:
  17.             event.ignore()

  18. app = QtWidgets.QApplication(sys.argv)
  19. qb = MessageBox()
  20. qb.show()
  21. sys.exit(app.exec_())
复制代码
如果我们关闭QWidget窗口,QCloseEvent事件就会被触发。要改变原有的wdiget行为阻止查窗口的关闭,我们就需要重新实现closeEvent()方法。
  1. reply = QtWidgets.QMessageBox.question(self,'确认退出','你确定要退出么?',
  2.                                                QtWidgets.QMessageBox.Yes,
  3.                                                QtWidgets.QMessageBox.No)
复制代码
通过上面的语句我们可以显示一个带有两个按钮(Yes/No)的消息窗口。第一个字符串参数'确认退出'在消息窗口的标题栏显示。第二个字符串参数'你确定要退出么?'以对话的形式显示在消息窗口中。返回的结果被保存在reply变量中。
  1. if reply == QtWidgets.QMessageBox.Yes:
  2.             event.accept()
  3.         else:
  4.             event.ignore()
复制代码
我们使用上面的if语句来判断用户选择的结果。如果用户选择了Yes按钮,那么关闭widget窗口并终止应用程序的动作会被允许执行。否则,关闭窗口的动作会被忽略

                               
登录/注册后可看大图

截图:消息窗口示例

2.6 将窗口放在屏幕中心
以下的脚本显示了将窗口放在屏幕的中间位置的方法。

  1. # -*- coding: utf-8 -*-
  2. """窗口置中"""
  3. import sys
  4. from PyQt5 import QtWidgets

  5. class Center(QtWidgets.QWidget):
  6.     def __init__(self, parent=None):
  7.         QtWidgets.QWidget.__init__(self,parent)
  8.         self.setWindowTitle("窗口置中程序")
  9.         self.resize(250, 150)
  10.         self.center()

  11.     def center(self):
  12.         screen = QtWidgets.QDesktopWidget().screenGeometry()
  13.         size = self.geometry()
  14.         self.move((screen.width() - size.width())/2, (screen.height() - size.height())/2)

  15. app = QtWidgets.QApplication(sys.argv)
  16. center = Center()
  17. center.show()
  18. sys.exit(app.exec_())
复制代码

  1. self.resize(250,150)
复制代码
该语句用来设置 QWidget 窗口的大小为 250 像素宽,150 像素高。
  1. screen =QtWidgets.QDesktopWidget().screenGeometry()
复制代码
该语句用来计算出显示器的分辨率(screen.width, screen.height)。
  1. size =self.geometry()
复制代码
该语句用来获取 QWidget 窗口的大小(size.width,size.height)。
  1. self.move((screen.width()- size.width())/2, (screen.height() - size.height())/2)
复制代码
该语句将窗口移动到屏幕的中间位置。这里move语句是将窗口的左上角移动到((screen.width()- size.width())/2, (screen.height() - size.height())/2)这个位置,效果如下图
1.jpg
截图:窗口置中程序
3.PyQt5中的菜单和工具栏
3.1主窗口
QMainWindow 类用来创建应用程序的主窗口。通过该类,我们可以创建一个包含状态栏、工具栏和菜单栏的经典应用程序框架。
3.2状态栏
状态栏是用来显示状态信息的串口部件。

  1. # -*- coding: utf-8 -*-
  2. """状态栏程序"""
  3. import sys
  4. from PyQt5 import QtWidgets


  5. class MainWindow(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(MainWindow, self).__init__()

  8.         self.resize(250, 150)
  9.         self.setWindowTitle("状态栏程序示例")
  10.         self.statusBar().showMessage("就绪")

  11. app = QtWidgets.QApplication(sys.argv)
  12. main_window = MainWindow()
  13. main_window.show()
  14. sys.exit(app.exec_())
复制代码
  1. super(MainWindow, self).__init__()
复制代码
       所有的类在创建时都会先调用构造函数(python中就是__init__())将实例按照构造函数的操作先进行初始化,继承了其它类的类,在构造函数中,先要构造他的父类,在之前的程序中,我们都是直接调用父类的__init__()方法来完成父类的构造,但是有一种更安全的方法就是用关键字super来完成。super(MainWindow, self).__init__()我们可以这样理解:super(MainWindow, self)首先找到MainWindow的父类(就是QtWidgets.QMainWindow),然后把类MainWindow的对象self转换为类QtWidgets.QMainWindow的对象,然后被转换的类A对象调用自己的__init__函数。考虑到super中只有指明子类的机制,因此,在多继承的类定义中,通常我们保留使用之前代码中的方法。对于之前用的方法为什么不安全,请参考网页http://www.cnblogs.com/lovemo1314/archive/2011/05/03/2035005.html
1.jpg
截图:状态栏程序实例

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-2 23:15:01 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-13 00:35 编辑

3.3菜单栏
菜单栏是 GUI 程序最明显的组成部分。它由一组位于不同菜单中的命令组成。在控制台程序中,我们必须记住那些晦涩难懂的命令。但在 GUI 程序中,通过菜单栏我们将命令合理的放置在不同的菜单中来降低学习新应用程序的时间开销。
  1. # -*- coding: utf-8 -*-
  2. """菜单栏"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtGui


  5. class MainWindow(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(MainWindow, self).__init__()

  8.         self.resize(250, 150)
  9.         self.setWindowTitle("菜单栏示例")

  10.         exit_menu = QtWidgets.QAction(QtGui.QIcon(r"1.ico"), "退出", self)
  11.         exit_menu.setShortcut("Ctrl+Q")
  12.         exit_menu.setStatusTip("退出程序")
  13.         exit_menu.triggered.connect(QtWidgets.qApp.quit)

  14.         self.statusBar()

  15.         menubar = self.menuBar()
  16.         file = menubar.addMenu("文件")
  17.         file.addAction(exit_menu)

  18. app = QtWidgets.QApplication(sys.argv)
  19. mainwindow = MainWindow()
  20. mainwindow.show()
  21. sys.exit(app.exec_())
复制代码
  1. menubar = self.menuBar()
  2. file = menubar.addMenu("文件")
  3. file.addAction(exit_menu)
复制代码
首先我们使用 QMainWindow 类的 menuBar()方法创建一个菜单栏。然后使用 addMenu()方法添加一个菜单。最后我们把动作对象(这里是exit_menu)添加到 file 菜单中。
1.jpg
截图:菜单栏示例
3.4工具栏
菜单对程序中的所有命令进行分组放置,而工具栏则提供了快速执行最常用命令的方法。
  1. # -*- coding: utf-8 -*-
  2. """工具栏"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtGui


  5. class MainWindow(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(MainWindow, self).__init__()

  8.         self.resize(250, 150)
  9.         self.setWindowTitle("工具栏示例")

  10.         self.exit_menu = QtWidgets.QAction(QtGui.QIcon(r"sample.png"), "退出", self)
  11.         self.exit_menu.setStatusTip("退出程序")
  12.         self.exit_menu.setShortcut("Ctrl+Q")
  13.         self.exit_menu.triggered.connect(QtWidgets.qApp.quit)

  14.         self.toolbar = self.addToolBar("退出")
  15.         self.toolbar.addAction(self.exit_menu)

  16. app = QtWidgets.QApplication(sys.argv)
  17. main_window = MainWindow()
  18. main_window.show()
  19. sys.exit(app.exec_())
复制代码
  1. self.exit_menu = QtWidgets.QAction(QtGui.QIcon(r"sample.png"), "退出", self)
  2. self.exit_menu.setStatusTip("退出程序")
复制代码
GUI 应用程序的行为是由命令来控制的,这些命令可以来自菜单、上下文菜单、工具栏或它们的快捷方式。PyQt 通过引入 actions 来简化编程难度,一个 action 对象可以拥有菜单、文本、图标、快捷方式、状态信息、“这是什么?”文本或工具提示等。在我们的示例程序中,我们定义了一个拥有图标、工具提示和快捷键的 action 对象。
  1. self.exit_menu.triggered.connect(QtWidgets.qApp.quit)
复制代码
该语句将 action 对象的triggered()信号连接到预定义的quit()槽函数。
  1. self.toolbar = self.addToolBar("退出")
复制代码
该语句创建一个工具栏,然后使用语句 self.toolbar.addAction(self.exit)将 action 对象(这里是 exit)添加到该工具栏。


                               
登录/注册后可看大图

截图:工具栏示例

3.5一个综合的例子
在本章的最后一个示例中,我们将创建一个菜单栏、一个工具栏和一个状态栏。我们还会创建一个中心部件。
  1. # -*- coding: utf-8 -*-
  2. """我的程序"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtGui


  5. class MainWindow(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(MainWindow, self).__init__()

  8.         self.resize(350, 250)
  9.         self.setWindowTitle("我的程序")
  10.         text_edit = QtWidgets.QTextEdit()
  11.         self.setCentralWidget(text_edit)

  12.         exit_action = QtWidgets.QAction(QtGui.QIcon(r"sample.png"), "退出", self)
  13.         exit_action.setStatusTip("退出程序")
  14.         exit_action.setShortcut("Ctrl+Q")
  15.         exit_action.triggered.connect(QtWidgets.qApp.quit)

  16.         self.statusBar()

  17.         self.menu_bar = self.menuBar()
  18.         file = self.menu_bar.addMenu("文件")
  19.         file.addAction(exit_action)

  20.         self.toolbar = self.addToolBar("退出")
  21.         self.toolbar.addAction(exit_action)

  22. app = QtWidgets.QApplication(sys.argv)
  23. main_window = MainWindow()
  24. main_window.show()
  25. sys.exit(app.exec_())
复制代码
在该示例中,我们创建了一个文本编辑部件,并将它设置为 QMainWindow 的中心部件。中心部件将占据所有的窗口剩余空间。

                               
登录/注册后可看大图

截图:一个综合示例


1.jpg
1.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2015-4-3 23:20:00 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-13 00:38 编辑

4.PyQt5中的布局管理器
布局管理器是编程中重要的一部分。所谓布局管理是指我们在窗口中安排部件位置的方法。布局管理有两种工作方式:绝对定位方式(absolute positioning)和布局类别方式(layout classes)。
4.1绝对定位方式
该方式下,程序员编程指定每一个部件的位置和尺寸像素。当使用绝对定位方式时,需要注意以下几点:
·改变窗口大小时,窗口中部件的大小和位置不会随之改变。
·在不同的平台上,应用程序可能会看起来不尽相同。
·在应用程序中改变字体可能会导致布局混乱。

·如果你打算改变窗口布局,你就必须得重新书写所有部件的布局,这一工作会非常乏味且耗时较多。
  1. # -*- coding: utf-8 -*-
  2. """绝对定位演示"""

  3. import sys
  4. from PyQt5 import QtWidgets, QtGui

  5. class MainWindow(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(MainWindow, self).__init__()

  8.         self.setWindowTitle("绝对定位演示程序")
  9.         self.resize(250, 150)
  10.         QtWidgets.QLabel('Couldn\'t', self).move(15, 10)
  11.         QtWidgets.QLabel('care', self).move(35, 40)
  12.         QtWidgets.QLabel('less', self).move(55, 65)
  13.         QtWidgets.QLabel('and', self).move(115, 65)
  14.         QtWidgets.QLabel('then', self).move(135, 45)
  15.         QtWidgets.QLabel('you', self).move(115, 25)
  16.         QtWidgets.QLabel('kiss', self).move(145, 10)
  17.         QtWidgets.QLabel('me', self).move(215, 10)

  18. app = QtWidgets.QApplication(sys.argv)
  19. main_window = MainWindow()
  20. main_window.show()
  21. sys.exit(app.exec_())
复制代码
在该示例中,我们简单是使用 move()方法来设置部件的位置。我们通过 x 和 y 坐标来指定 QLabel 部件的位置,坐标起点为左上角的顶点。x 坐标从左向右增长,y 坐标从上向下增长。
1.jpg
截图:绝对定位演示
4.2Box布局
使用布局类别方式的布局管理器比绝对定位方式的布局管理器更加灵活实用。它是窗口部件的首先布局管理方式。最基本的布局类别是 QHBoxLayout 和 QVBoxLayout布局管理方式,分别将窗口部件水平和垂直排列。
假设我们要将两个按钮放在窗口的右下角。为创建该布局,我们需要使用一个水平Box 和一个垂直 Box,另外为了创建必须的空白空间,我们还需要添加一个伸缩间隔元素(stretch factor
  1. # -*- coding: utf-8 -*-
  2. """Box定位演示"""

  3. import sys
  4. from PyQt5 import QtWidgets


  5. class BoxLayout(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(BoxLayout, self).__init__()

  8.         self.setWindowTitle("Box定位演示程序")

  9.         self.ok_button = QtWidgets.QPushButton("确定")
  10.         self.cancel_button = QtWidgets.QPushButton("取消")

  11.         self.h_box = QtWidgets.QHBoxLayout()
  12.         self.h_box.addStretch(1)
  13.         self.h_box.addWidget(self.ok_button)
  14.         self.h_box.addWidget(self.cancel_button)

  15.         self.v_box = QtWidgets.QVBoxLayout()
  16.         self.v_box.addStretch(1)
  17.         self.v_box.addLayout(self.h_box)

  18.         self.setLayout(self.v_box)

  19.         self.resize(300, 150)

  20. app = QtWidgets.QApplication(sys.argv)
  21. box_layout = BoxLayout()
  22. box_layout.show()
  23. sys.exit(app.exec_())
复制代码
  1. self.ok_button = QtWidgets.QPushButton("确定")
  2. self.cancel_button = QtWidgets.QPushButton("取消")
复制代码
以上两句用来创建两个按钮(确定和取消按钮)。
  1. self.h_box = QtWidgets.QHBoxLayout()
  2. self.h_box.addStretch(1)
  3. self.h_box.addWidget(self.ok_button)
  4. self.h_box.addWidget(self.cancel_button)
复制代码
以上四句用来创建一个水平 box 布局,然后加入一个伸缩间隔元素与两个按钮。
  1. self.v_box = QtWidgets.QVBoxLayout()
  2. self.v_box.addStretch(1)
  3. self.v_box.addLayout(self.h_box)
复制代码
为创建需要的布局,我们使用以上语句创建了一个垂直 box 布局并将水平 box 布局放入水平 box 布局中。
self.setLayout(v_box)
最后我们设置窗口的主布局。
1.jpg
截图:Box定位演示程序

关于Box定位的更多用法(即VBoxLayout和HBoxLayout),请看此贴http://bbs.fishc.com/thread-61103-1-1.html

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2015-4-3 23:30:51 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-13 00:39 编辑

4.3网格布局
最通用的布局类别是网格布局(QGridLayout)。该布局方式将窗口空间划分为许多行和列。要创建该布局方式,我们需要使用 QGridLayout 类。
  1. # -*- coding: utf-8 -*-
  2. """网格布局示例"""

  3. import sys
  4. from PyQt5 import QtWidgets


  5. class GridLayout(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(GridLayout, self).__init__()

  8.         self.setWindowTitle("网格布局演示程序")
  9.         buttton_names = ['Cls', 'Bck', '', 'Close',
  10.                          '7', '8', '9', '/',
  11.                          '4', '5', '6', '*',
  12.                          '1', '2', '3', '-',
  13.                          '0', '.', '=', '+']
  14.         main_ground = QtWidgets.QWidget()
  15.         self.setCentralWidget(main_ground)
  16.         grid = QtWidgets.QGridLayout()

  17.         for [n, (x, y)] in enumerate([(i, j) for i in range(5) for j in range(4)]):
  18.             if (x, y) == (0, 2):
  19.                 grid.addWidget(QtWidgets.QLabel(buttton_names[n]), x, y)
  20.             else:
  21.                 grid.addWidget(QtWidgets.QPushButton(buttton_names[n]), x, y)
  22.         main_ground.setLayout(grid)

  23. app = QtWidgets.QApplication(sys.argv)
  24. grid_layout = GridLayout()
  25. grid_layout.show()
  26. sys.exit(app.exec_())
复制代码

在这个示例中,我们创建一组按网格布局的按钮。为了填补 Bck 和 Close 按钮之间的空白,我们使用 QLabel 部件。
  1. main_ground = QtWidgets.QWidget()
  2. self.setCentralWidget(main_ground)
复制代码
上面这两条语句中,我们先创建了一个QtWidgets.QWidget类的实例main_ground,然后setCentralWidget方法将它置为中心部件
  1. grid = QtWidgets.QGridLayout()
复制代码
该语句创建了一个网格布局。
  1. for [n, (x, y)] in enumerate([(i, j) for i in range(5) for j in range(4)]):
  2.             if (x, y) == (0, 2):
  3.                 grid.addWidget(QtWidgets.QLabel(buttton_names[n]), x, y)
  4.             else:
  5.                 grid.addWidget(QtWidgets.QPushButton(buttton_names[n]), x, y)
复制代码
使用 addWidget()方法,我们将部件加入到网格布局中。addWidget()方法的参数依次为要加入到局部的部件,行号和列号。
  1. main_ground.setLayout(grid)
复制代码
最后将创建好的网格布局用setLayout方法置于之前创建的main_ground实例上,如果不创建main_ground而是直接在最后用self.setLayout(grid),程序可以正常跑起来,但是你看不到你布置好的网格布局,同时会被警告QWidget::setLayout: Attempting to set QLayout "" onGridLayout "", which already has a layout。在4.2中我们直接应用self.setLayout(grid)方法将布局安放在了程序界面,这是因为我们的主程序界面继承的是QtWidgets.QWidget类而不是这节中的QtWidgets.QMainWindow类。
1.jpg
截图:网格布局示例1
部件在网格布局中可以跨越多行或多列。我们将下面的示例中演示该情况。
  1. # -*- coding: utf-8 -*-
  2. """网格布局跨行示例"""
  3. import sys
  4. from PyQt5 import QtWidgets


  5. class GridLayout(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(GridLayout, self).__init__()

  8.         self.setWindowTitle("网格布局跨行演示程序")

  9.         main_ground = QtWidgets.QWidget()
  10.         self.setCentralWidget(main_ground)

  11.         grid = QtWidgets.QGridLayout()
  12.         grid.setSpacing(20)
  13.         grid.addWidget(QtWidgets.QLabel("标题:"), 1, 0)
  14.         grid.addWidget(QtWidgets.QLineEdit(), 1, 1)
  15.         grid.addWidget(QtWidgets.QLabel("作者:"), 2, 0)
  16.         grid.addWidget(QtWidgets.QLineEdit(), 2, 1)
  17.         grid.addWidget(QtWidgets.QLabel("评论:"), 3, 0)
  18.         grid.addWidget(QtWidgets.QTextEdit(), 3, 1, 5, 1)

  19.         main_ground.setLayout(grid)
  20.         self.resize(350, 300)

  21. app = QtWidgets.QApplication(sys.argv)
  22. grid_layout = GridLayout()
  23. grid_layout.show()
  24. sys.exit(app.exec_())
复制代码
  1. grid = QtGui.QGridLayout()
  2. grid.setSpacing(20)
复制代码
通过以上两句,我们创建了一个网格布局,并将该布局中的部件间隔(同行的横向间隔)设为 20 个字距。
  1. grid.addWidget(QtWidgets.QLineEdit(), 3, 1, 5, 1)
复制代码
我们可以为加入网格布局的部件设置行列跨度,在上面的语句中,我们将 reviewEdit部件的行跨度设置为 5,列跨度设置为 1。

                               
登录/注册后可看大图

截图:网格布局跨行示例



有些同学可能会出现下图所示的情况,那么请看看这一句你是否写的正确grid.addWidget(QtWidgets.QTextEdit(), 3, 1, 5, 1)



1.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2015-4-3 23:33:56 | 显示全部楼层
本帖最后由 lightninng 于 2015-4-25 23:39 编辑

5.PyQt5的事件与信号
在本章的学习中,我们将介绍发生在应用程序中的事件和信号。
5.1事件
事件(Events)是 GUI 程序中很重要的一部分。它由用户或系统产生。当我们调用程序的 exec_()方法时,程序就会进入主循环中。主循环捕获事件并将它们发送给相应的对象进行处理。为此,奇趣公司(Trolltech)引入了一种独一无二的处理模式:信号与槽机制。
5.2信号槽
当用户单击一个按钮,拖动一个滑块或进行其它动作时,相应的信号就会被发射。除此之外,信号还可以因为环境的变化而被发射。比如一个运行的时钟将会发射时间信号等。而所谓的槽则是一个方法,该方法将会响应它所连接的信号。在 Python 中,槽可以是任何可以被调用的对象。
  1. # -*- coding: utf-8 -*-
  2. """信号槽示例"""

  3. import sys
  4. from PyQt5 import QtWidgets, QtCore


  5. class SignalSlot(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(SignalSlot, self).__init__()

  8.         self.setWindowTitle("信号槽演示程序")
  9.         lcd = QtWidgets.QLCDNumber(self)
  10.         slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)

  11.         v_box = QtWidgets.QVBoxLayout()
  12.         v_box.addWidget(lcd)
  13.         v_box.addWidget(slider)

  14.         self.setLayout(v_box)
  15.         slider.valueChanged.connect(lcd.display)
  16.         self.resize(250, 150)

  17. app = QtWidgets.QApplication(sys.argv)
  18. qb = SignalSlot()
  19. qb.show()
  20. sys.exit(app.exec_())
复制代码
在这个示例中,我们创建了一个LCD显示器和一个滑块。通过拖动滑块我们可改变LCD显示器的数字。
  1. slider.valueChanged.connect(lcd.display)
复制代码
这里我们将滑块的 valueChanged信号连接到 LCD 显示器的 display槽函数上。下面介绍connect 的用法,如果信号发送者对象为emit(这里是 slider 对象),要发射的信号是signal(这里是valueChanged 信号),信号的接收者对象accept(这里是 lcd 对象),对信号做出响应的槽函数slot(这里是 display 方法),那么连接信号和槽的方法为:
  1. emit.signal.connect(accept.slot)
复制代码
1.jpg
截图:信号槽示例

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2015-4-9 00:25:34 | 显示全部楼层
本帖最后由 lightninng 于 2015-4-25 23:46 编辑

5.3重写事件处理方法
PyQt 中的事件处理主要依赖重写事件处理函数来实现。
  1. # -*- coding: utf-8 -*-
  2. """用Esc键推出示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore

  5. class Escape(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(Escape, self).__init__()

  8.         self.setWindowTitle("Esc退出演示程序")
  9.         self.resize(250, 150)

  10.     def keyPressEvent(self, event):
  11.         if event.key() == QtCore.Qt.Key_Escape:
  12.             self.close()

  13. app = QtWidgets.QApplication(sys.argv)
  14. escape = Escape()
  15. escape.show()
  16. sys.exit(app.exec_())
复制代码
在上面的示例中,我们重新实现了 keyPressEvent()事件处理方法。
  1.     def keyPressEvent(self, event):
  2.         if event.key() == QtCore.Qt.Key_Escape:
  3.             self.close()
复制代码
通过上面的方法,当我们按下 ESC 键时程序就会结束。
5.4发射信号
通过QtCore.QObject创建的对象可以发射信号。如果我们点击按钮,就会生成一个clicked()信号。在以下的例子里我们会看到如何发射一个信号。
  1. # -*- coding: utf-8 -*-
  2. """发射信号示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore


  5. class EmitSignal(QtWidgets.QWidget):
  6.     closeEmitApp = QtCore.pyqtSignal()

  7.     def __init__(self):
  8.         super(EmitSignal, self).__init__()

  9.         self.setWindowTitle("发射信号演示程序")
  10.         self.resize(250, 150)
  11.         
  12.         self.closeEmitApp.connect(self.close)

  13.     def mousePressEvent(self, QMouseEvent):
  14.         self.closeEmitApp.emit()

  15. app = QtWidgets.QApplication(sys.argv)
  16. es = EmitSignal()
  17. es.show()
  18. sys.exit(app.exec_())
复制代码
closeEmitApp =QtCore.pyqtSignal()
我们创建一个叫做closeEmitApp()的新的信号。这个信号在鼠标按下时产生。
PS:这里楼主曾经尝试将信号的定义放到__init__()函数中,即在__init__()函数中加入这样的语句
  1. self.closeEmitApp = QtCore.pyqtSignal()
复制代码
但是,程序报错:AttributeError: 'PyQt5.QtCore.pyqtSignal'object has no attribute 'connect',这里涉及到在类中直接定义变量和在__init__()函数中定义变量的问题:前者作为类的属性,在类外部可以直接用(类名.属性名)这样的方式调用;后者,可以在类内部的方法中调用,但是它不属于类的一个属性。一个可信号必须在类中进行定义,否则它将不能使用connect()方法连接槽函数。具体的可以看这个贴子,在贴中我提了问题,4楼的回答也提供了遇到这类问题时怎么弄清楚的思路http://bbs.fishc.com/forum.php?mod=viewthread&tid=60309&page=1#pid2326532
  1. def mousePressEvent(self, QMouseEvent):
  2.         self.closeEmitApp.emit()
复制代码
通过信号变量的emit()方法来发射一个信号。
  1. self.closeEmitApp.connect(self.close)
复制代码
当然,我们我们还得把自定义的closeEmitApp()信号与槽函数close()连接起来。

程序的效果是出现程序窗体后,点击左键或者右键程序会关闭。
6 PyQt5中的对话框
对话窗口和对话框是现代 GUI 应用程序必不可少的一部分。生活中“对话”被定义为
发生在两人或更多人之间的会话。而在计算机世界,“对话”则是人与应用程序之间的“会
话”。人机对话的形式有在输入框内键如内容,修改已有的数据,改变应用程序的设置等。
对话框在人机交互中扮演着非常重要的角色。
从本质上说,只存在两种形式的对话框:预定义对话框和定制对话框。
6.1 QInputDialog输入对话框
QInputDialog 提供了一种获取用户单值数据的简洁形式。它接受的数据有字符串,数字和列表中的一项数据等。
  1. # -*- coding: utf-8 -*-
  2. """输入对话框示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore

  5. class InputDialog(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(InputDialog, self).__init__()

  8.         self.setWindowTitle("输入对话框演示程序")
  9.         self.setGeometry(300, 300, 350, 80)
  10.         self.button = QtWidgets.QPushButton("对话框", self)
  11.         self.button.setFocusPolicy(QtCore.Qt.NoFocus)
  12.         self.button.move(20, 20)
  13.         self.button.clicked.connect(self.show_dialog)
  14.         self.setFocus()

  15.         self.label = QtWidgets.QLineEdit(self)
  16.         self.label.move(130, 22)

  17.     def show_dialog(self):
  18.         text, ok = QtWidgets.QInputDialog.getText(self, "输入对话框", "请输入你的名字:")
  19.         if ok:
  20.             self.label.setText(text)

  21. app = QtWidgets.QApplication(sys.argv)
  22. input_dialog = InputDialog()
  23. input_dialog.show()
  24. sys.exit(app.exec_())
复制代码
本示例包含一个按钮和一个行编辑部件。单机按钮会弹出输入对话框,以获取用户输入的文本数据。该文本数据将会显示在行编辑部件中。
  1. text, ok = QtWidgets.QInputDialog.getText(self, "输入对话框", "请输入你的名字:")
复制代码
该语句用来显示一个输入对话框。第一个参数"输入对话框"是对话框的标题。第二个参数"请输入你的名字:"将作为提示信息显示在对话框内。该对话框将返回用户输入的内容和一个布尔值,如果用户单击OK按钮确认输入,则返回的布尔值为true,否则返回的布尔值为false。

                               
登录/注册后可看大图

截图:输入对话框示例





想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-9 23:11:17 | 显示全部楼层
本帖最后由 lightninng 于 2015-4-25 23:47 编辑

6 PyQt5中的对话框
对话窗口和对话框是现代 GUI 应用程序必不可少的一部分。生活中“对话”被定义为
发生在两人或更多人之间的会话。而在计算机世界,“对话”则是人与应用程序之间的“会
话”。人机对话的形式有在输入框内键如内容,修改已有的数据,改变应用程序的设置等。
对话框在人机交互中扮演着非常重要的角色。
从本质上说,只存在两种形式的对话框:预定义对话框和定制对话框。
6.1 QInputDialog输入对话框
QInputDialog 提供了一种获取用户单值数据的简洁形式。它接受的数据有字符串,数字和列表中的一项数据等。
  1. # -*- coding: utf-8 -*-
  2. """输入对话框示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore

  5. class InputDialog(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(InputDialog, self).__init__()

  8.         self.setWindowTitle("输入对话框演示程序")
  9.         self.setGeometry(300, 300, 350, 80)
  10.         self.button = QtWidgets.QPushButton("对话框", self)
  11.         self.button.setFocusPolicy(QtCore.Qt.NoFocus)
  12.         self.button.move(20, 20)
  13.         self.button.clicked.connect(self.show_dialog)
  14.         self.setFocus()

  15.         self.label = QtWidgets.QLineEdit(self)
  16.         self.label.move(130, 22)

  17.     def show_dialog(self):
  18.         text, ok = QtWidgets.QInputDialog.getText(self, "输入对话框", "请输入你的名字:")
  19.         if ok:
  20.             self.label.setText(text)

  21. app = QtWidgets.QApplication(sys.argv)
  22. input_dialog = InputDialog()
  23. input_dialog.show()
  24. sys.exit(app.exec_())
复制代码
本示例包含一个按钮和一个行编辑部件。单机按钮会弹出输入对话框,以获取用户输入的文本数据。该文本数据将会显示在行编辑部件中。
  1. text, ok = QtWidgets.QInputDialog.getText(self, "输入对话框", "请输入你的名字:")
复制代码
该语句用来显示一个输入对话框。第一个参数"输入对话框"是对话框的标题。第二个参数"请输入你的名字:"将作为提示信息显示在对话框内。该对话框将返回用户输入的内容和一个布尔值,如果用户单击OK按钮确认输入,则返回的布尔值为true,否则返回的布尔值为false。

                               
登录/注册后可看大图

截图:输入对话框示例


6.2 QColorDialog颜色对话框
QcolorDialog 提供了用于选择颜色的对话框。
  1. # -*- coding: utf-8 -*-
  2. """颜色对话框示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtGui, QtCore


  5. class ColorDialog(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(ColorDialog, self).__init__()

  8.         self.setWindowTitle("颜色对话框演示程序")
  9.         self.setGeometry(300, 300, 250, 180)

  10.         self.button = QtWidgets.QPushButton("更改颜色", self)
  11.         self.button.setFocusPolicy(QtCore.Qt.NoFocus)
  12.         self.button.move(20, 20)

  13.         self.button.clicked.connect(self.show_dialog)
  14.         self.setFocus()

  15.         color = QtGui.QColor(0, 0, 0)
  16.         self.widget = QtWidgets.QWidget(self)
  17.         self.widget.setStyleSheet("QWidget{background-color:%s}"% color.name())
  18.         self.widget.setGeometry(130, 22, 100, 100)

  19.     def show_dialog(self):
  20.         col = QtWidgets.QColorDialog.getColor()
  21.         if col.isValid():
  22.             self.widget.setStyleSheet("QWidget{background-color:%s}" % col.name())

  23. app = QtWidgets.QApplication(sys.argv)
  24. colordialog = ColorDialog()
  25. colordialog.show()
  26. sys.exit(app.exec_())
复制代码
以上示例程序显示了一个按钮和一个QWidget 部件,该 widget 部件的初始背景颜色为黑色。使用颜色对话框 QcolorDialog,我们可以改变 widget 部件的背景色。
  1. col = QtWidgets.QColorDialog.getColor()
复制代码
这一行语句用来弹出颜色对话框。
  1. if col.isValid():
  2.        self.widget.setStyleSheet("QWidget{background-color:%s}" % col.name())
复制代码
以上的语句首先检测颜色时候可用。如果用户单击了颜色对话框的取消按钮,则对话框将不返回任何可用的颜色。如果颜色可用,我们就使用 stylesheets 设置 widget 部件的背景色。

                               
登录/注册后可看大图

截图:颜色对话框示例
文中对于下面几条语句并没有过多的解释,查了一番资料解释如下
  1. self.button.setFocusPolicy(QtCore.Qt.NoFocus)
复制代码
将按钮的焦点策略设定为NoFocus,关于焦点,简单介绍一下,在应用程序中,都会有一个当前窗口,即当前获得焦点事件的窗口,这个窗口可以接受键盘的输入。关于焦点的更多内容请看http://blog.csdn.net/kangroger/article/details/7744077,虽然是C++的例子,但是有一点C基础的同学,学过这么多python应该能看的懂。
  1. self.setFocus()
复制代码
将当前窗口设为焦点窗口,即设为选中状态
  1. color = QtGui.QColor(0, 0, 0)
复制代码
用一个color变量存储一种颜色,这里用的是rgb颜色,(0, 0, 0)代表的是黑色
  1. self.widget.setStyleSheet("QWidget{background-color:%s}" % color.name())
复制代码
setStyleSheet方法用来设置图形界面的外观,比如按钮颜色,这里是将刚刚创建的widget部件的颜色设为color存储的颜色,下文中当颜色值有效时,用样的方法重新设置了widget部件的背景颜色。
这里说一下我理解的setStyleSheet的语法,它接受一个字符串,字符串的开始是调用这个方法的实例的类,应该只能是PyQt中的类(个人理解),然后花括号扩起来的是设置,这里background-color是指背景颜色,然后用了一个占位符,对应的是后面的color.name(),我尝试将color的赋值语句删掉,然后把这句改成这样:
  1. self.widget.setStyleSheet("QWidget{background-color:black}")
复制代码
效果不变,每种颜色都有名字,但是只能记得常见的名字,所以先调用QtGui.QColorrgb值给颜色赋值,然后再调用它的.name方法便能方便的得到各种颜色的名字便于我们进行颜色的设置。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-11 17:08:36 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-18 22:26 编辑

6.3 QFontDialog字体对话框
字体对话框用来一个用来这是字体的对话框部件。
  1. # -*- coding: utf-8 -*-
  2. """字体对话框示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore


  5. class FontDialog(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(FontDialog, self).__init__()

  8.         self.setWindowTitle("字体对话框示例程序")
  9.         self.setGeometry(300, 300, 250, 110)

  10.         self.button = QtWidgets.QPushButton("对话框", self)
  11.         self.button.setFocusPolicy(QtCore.Qt.NoFocus)
  12.         self.button.move(20, 20)
  13.         self.button.clicked.connect(self.show_dialog)

  14.         self.label = QtWidgets.QLabel("普通的disco我们普通的摇", self)
  15.         self.label.move(130, 30)

  16.         self.h_box = QtWidgets.QHBoxLayout()
  17.         self.h_box.addWidget(self.button)
  18.         self.h_box.addWidget(self.label, 1)
  19.         self.setLayout(self.h_box)

  20.     def show_dialog(self):
  21.         font, ok = QtWidgets.QFontDialog.getFont(self)
  22.         if ok:
  23.             self.label.setFont(font)

  24. app = QtWidgets.QApplication(sys.argv)
  25. fd = FontDialog()
  26. fd.show()
  27. sys.exit(app.exec_())
复制代码
在本示例中,我们在主界面中显示了一个按钮和一个标签。单机按钮后,用户可在弹出字体对话框中选择字体来修改标签中的字体样式。
  1. self.h_box.addWidget(self.label, 1)
复制代码
该语句将 labe 标签加入到 hbox 布局中,并通过第二个参数1 设置 label 的大小是可变的。该设置是必须的,因为在用户选择不同的字体时,label 标签中的字体可能会变大,若不进行该设置,标签中的内容就可能不会被全部显示。
  1. font, ok = QtWidgets.QFontDialog.getFont(self)
复制代码
该语句将弹出字体对话框。
  1. if ok:
  2.             self.label.setFont(font)
复制代码
在用户选择了字体并单击 OK 按钮后,使用标签对象的setFont 方法设置标签内容的字体。

                               
登录/注册后可看大图

截图:字体对话框示例

6.4 QFileDialog文件对话框
文件对话框允许用户选择文件或文件夹,被选择的文件可进行读或写操作。
  1. # -*- coding: utf-8 -*-
  2. """文件对话框示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore, QtGui


  5. class OpenFileDialog(QtWidgets.QMainWindow):
  6.     def __init__(self):
  7.         super(OpenFileDialog, self).__init__()

  8.         self.setWindowTitle("文件对话框演示程序")
  9.         self.setGeometry(300, 300, 400, 300)

  10.         self.text_edit = QtWidgets.QTextEdit()
  11.         self.setCentralWidget(self.text_edit)
  12.         self.statusBar()
  13.         self.setFocus()

  14.         self.file_item = QtWidgets.QAction(QtGui.QIcon(r"gear_08.png"), "打开", self)
  15.         self.file_item.setShortcut("Ctrl+O")
  16.         self.file_item.setStatusTip("打开新文件")
  17.         self.file_item.triggered.connect(self.show_dialog)

  18.         self.file = self.menuBar().addMenu("文件")
  19.         self.file.addAction(self.file_item)

  20.     def show_dialog(self):
  21.         file_name = QtWidgets.QFileDialog.getOpenFileName(self, '打开文件', r"C:\Users\Administrator\Desktop\test/")
  22.         try:
  23.             file = open(file_name[0], "r")
  24.             data = file.read()
  25.         except UnicodeDecodeError:
  26.             data = "不是合法的txt文件"
  27.         except FileNotFoundError:
  28.             data = ""
  29.         self.text_edit.setText(data)

  30. app = QtWidgets.QApplication(sys.argv)
  31. file_d = OpenFileDialog()
  32. file_d.show()
  33. sys.exit(app.exec_())
复制代码
我们在本示例程序中显示了一个菜单栏,一个状态栏和一个被设置为中心部件的文本编辑器。其中状态栏的状态信息只有在用户想要打开文件时才会显示。单击菜单栏中的 Open选项将弹出文件对话框供用户选择文件。被选择的文件内容将被显示在文本编辑器部件中。
  1. class OpenFileDialog(QtWidgets.QMainWindow):
  2.         …
  3.         self.text_edit = QtWidgets.QTextEdit()
  4.         self.setCentralWidget(self.text_edit)
复制代码
本示例程序是基于 QMainWindow 窗口部件的,因为我们需要将文本编辑器设置为中心部件(QWidget 部件类没有提供 setCentralWidget 方法)。无须依赖布局管理器,QMainWindow即可轻松完成设置中心部件的工作(使用 setCentralWidget 方法)。
PS:关于这段说的这点,我自己由于马虎,在手动输入代码时,自定义的OpenFileDialog类继承的是QtWidget.QWidegt类,在setCentralWidget处报错,经过百度得知错误来源。然后说句题外话,这次图标的设置成功了,没有像上次一样显示一片白。
  1. file_name = QtWidgets.QFileDialog.getOpenFileName(self, '打开文件', r"C:\Users\Administrator\Desktop\test/")
复制代码
该语句将弹出文件对话框。getOpenFileName()方法的第一个字符串参数'OpenFile'将显示在弹出对话框的标题栏。第二个字符串参数用来指定对话框的工作目录,也就是下图中2所示位置的目录(这里我将默认工作目录设为桌面上的test文件夹)。默认情况下文件过滤器被设置为不过滤任何文件(所有工作目录中的文件/文件夹都会被显示)。另外一个小技巧,在表示路径的字符串的最后一个字符如果输入"\"会报错,可以用"/"来代替,具体原理不明(我懒~~)。
  1.         try:
  2.             file = open(file_name[0], "r")
  3.             data = file.read()
  4.         except UnicodeDecodeError:
  5.             data = "不是合法的txt文件"
  6.         except FileNotFoundError:
  7.             data = ""
  8.         self.text_edit.setText(data)
复制代码
以上面的语句将读取被选择的文件并将其内容显示在文本编辑器中,原教程中的语句是这样的:
  1.         file = open(file_name[0], "r")
  2.         data = file.read()
  3.         self.text_edit.setText(data)
复制代码
遇到几个问题:
1、file_name打印出来发现QtWidgets.QFileDialog.getOpenFileName的返回值file_name中存储的是一个元组,第一个元素是我们选择的文件的路径,第二个元素是一个空的字符串(意义不明),加上索引[0]后,正确运行。
2、在选择的文件不是txt里报错UnicodeDecodeError,在不选择文件取消时报错FileNotFoundError,用try语句将它们捕获,并在文本框内给出相应的提示


                               
登录/注册后可看大图

截图:文件对话框示例

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-4-11 23:45:52 | 显示全部楼层
楼主好棒,加油
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-12 00:16:07 | 显示全部楼层

谢谢,欢迎交流,中间我也有很多不懂的,如果知道的话还请告诉我啊~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-4-15 22:32:31 | 显示全部楼层
lightninng 发表于 2015-4-12 00:16
谢谢,欢迎交流,中间我也有很多不懂的,如果知道的话还请告诉我啊~

一定一定,
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-16 23:53:45 | 显示全部楼层
本帖最后由 lightninng 于 2015-4-18 12:26 编辑

之前的内容不太完整,不过主要的东西都在了,以后可能序号会变,也会加一些内容(无关紧要的)
7 PyQt5中的部件
部件是构建应用程序的基础元素。PyQt5 工具包拥有大量的种类繁多的部件。比如:按钮,单选框,滑块,列表框等任何程序员在完成其工作时需要的部件。本本章的学习中,我们将介绍一些有用的部件。
7.1 QCheckBox单选框
单选框具有两个状态:被选中或未被选中。它看起来像一个附件了标签的方框。当用户选择或取消选择时,单选框就会发射一个 stateChanged()信号。
  1. # -*- coding: utf-8 -*-
  2. """单选框示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore


  5. class CheckBox(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(CheckBox, self).__init__()

  8.         self.setWindowTitle("单选框演示程序")
  9.         self.setGeometry(300, 300, 250, 150)

  10.         self.check_box = QtWidgets.QCheckBox("显示标题", self)
  11.         self.check_box.move(10, 10)
  12.         self.check_box.setFocusPolicy(QtCore.Qt.NoFocus)
  13.         self.check_box.toggle()
  14.         self.check_box.stateChanged.connect(self.change_title)

  15.     def change_title(self):
  16.         if self.check_box.isChecked():
  17.             self.setWindowTitle("单选框演示程序")
  18.         else:
  19.             self.setWindowTitle("单选框未选中")

  20. app = QtWidgets.QApplication(sys.argv)
  21. cb = CheckBox()
  22. cb.show()
  23. sys.exit(app.exec_())
复制代码
在本示例中,我们创建了一个用来改变窗口标题的单选框。
  1. self.check_box = QtWidgets.QCheckBox("显示标题", self)
复制代码
该语句用来创建一个标签信息为"显示标题"的单选框。
  1. self.check_box.stateChanged.connect(self.change_title)
复制代码
这里我们将用户定义的 change_title()函数与单选框的stateChanged()信号连接起来。自定义的change_title()函数将重置窗口的标题。
  1. self.check_box.setFocusPolicy(QtCore.Qt.NoFocus)
复制代码
默认情况下单选框接受聚焦,被聚焦的表现形式为单选框的标签被一个薄薄的矩形所覆盖。这个矩形看起来回有些太过严肃,所以我们使用以上代码行将单选框的聚焦样式修改为Qt.NoFocus 的无聚焦样式。这里我把这句注释掉的话,显示效果没变,原因不明,但是我知道作者想说的大概是这样的。

                               
登录/注册后可看大图

  1. self.check_box.toggle()
复制代码
初始状态下我们设置了窗口的标题,因此我们需要使用以上代码行将单选框选上。在默认情况下,单选框是未被选中的。

                               
登录/注册后可看大图

截图:单选框示例
7.2 ToggleButton开关按钮
PyQt5 没有开关按钮部件。但是我们可以使用在特殊状态下的 QPushButton 部件来创建开关按钮。而所谓的开关按钮就是一个具有按下和未按下两种状态的普通按钮。用户可以通过单击按钮来切换其开或关的状态。在一些情形下,这个特性会非常好用。
  1. # -*- coding: utf-8 -*-
  2. """开关按钮示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore, QtGui


  5. class ToggleButton(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(ToggleButton, self).__init__()

  8.         self.setWindowTitle("开关按钮演示程序")
  9.         self.setGeometry(300, 300, 280, 170)

  10.         self.red = QtWidgets.QPushButton("红", self)
  11.         self.red.setCheckable(True)
  12.         self.red.move(10, 10)
  13.         self.red.clicked.connect(self.set_red)

  14.         self.green = QtWidgets.QPushButton("绿", self)
  15.         self.green.setCheckable(True)
  16.         self.green.move(10, 60)
  17.         self.green.clicked.connect(self.set_green)

  18.         self.blue = QtWidgets.QPushButton("蓝", self)
  19.         self.blue.setCheckable(True)
  20.         self.blue.move(10, 110)
  21.         self.blue.clicked.connect(self.set_blue)

  22.         self.square = QtWidgets.QWidget(self)
  23.         self.square.setGeometry(150, 20, 100, 100)
  24.         self.color = QtGui.QColor(0, 0, 0)
  25.         self.square.setStyleSheet("QWidget{background-color:%s}" % self.color.name())

  26.         QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create("cleanlooks"))

  27.     def set_red(self):
  28.         if self.red.isChecked():
  29.             self.color.setRed(255)
  30.         else:
  31.             self.color.setRed(0)
  32.         self.square.setStyleSheet("QWidget{background-color:%s}" % self.color.name())

  33.     def set_green(self):
  34.         if self.green.isChecked():
  35.             self.color.setGreen(255)
  36.         else:
  37.             self.color.setGreen(0)
  38.         self.square.setStyleSheet("QWidget{background-color:%s}" % self.color.name())

  39.     def set_blue(self):
  40.         if self.blue.isChecked():
  41.             self.color.setBlue(255)
  42.         else:
  43.             self.color.setBlue(0)
  44.         self.square.setStyleSheet("QWidget{background-color:%s}" % self.color.name())

  45. app = QtWidgets.QApplication(sys.argv)
  46. tb = ToggleButton()
  47. tb.show()
  48. sys.exit(app.exec_())
复制代码
在这个例子中,我们创建了三个开关按钮和一个 QWidget 部件,并将 QWidget 部件的背景颜色设置为黑色。用户通过开关按钮从红、绿、蓝选择出 QWidget 部件的背景颜色组合。若开关按钮被按下,则其对应的颜色即被选中。
  1. self.red = QtWidgets.QPushButton("红", self)
  2. self.red.setCheckable(True)
复制代码
通过创建一个 QPushButton 并将其设置为可被选择的,即得到我们想要的开关按钮。
  1. self.red.clicked.connect(self.set_red)
复制代码
我们将 red 开关按钮的clicked()信号和自定义的 setRed()方法连接起来。
  1. self.color = QtGui.QColor(0, 0, 0)
复制代码
这行语句用来设置初始颜色,红绿蓝三种颜色值均为 0 时的颜色为黑色。
  1. self.square.setStyleSheet("QWidget{background-color:%s}" % self.color.name())
复制代码
该行语句用来将应用程序的外观样式设置为cleanlooks 的。之所以这样做是因为 Linux系统下的默认样式存在一个小的设计缺陷,该缺陷使用户无法快速的分辨出开关按钮的两种状态。而采用 cleanlooks 样式外观的表现会好些。PS:我用的win7,将该条语句注释掉之后发现效果无变化。
  1.         if self.red.isChecked():
  2.             self.color.setRed(255)
  3.         else:
  4.             self.color.setRed(0)
复制代码
我们使用 if 语句来判断开关按钮的状态并设置对应的颜色值。
  1. self.square.setStyleSheet("QWidget{background-color:%s}" % self.color.name())
复制代码
使用 setStyleSheet()方法改变 QWidget 部件的背景色。

                               
登录/注册后可看大图

截图:开关按钮示例
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2015-4-18 12:32:51 | 显示全部楼层
本帖最后由 lightninng 于 2015-5-16 14:27 编辑

7.3 QSlider滑块、QLabel标签
         滑块部件由一个简单的操控杆构成,用户可以通过向前或向后滑动滑块来选择数据。这种选择数据的方式对一些特殊的任务来说比单纯的提供一个数据或使用 spin box 调整数据大小的方式要自然与友好的多。而标签部件则用来显示文本或图片。
在以下的示例中,我们将在窗口中显示一个滑块和一个标签。这次我们将在标签部件中显示图片,并使用滑块来控制其显示内容。
  1. # -*- coding: utf-8 -*-
  2. """滑块和标签示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore, QtGui


  5. class SliderLabel(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(SliderLabel, self).__init__()

  8.         self.setWindowTitle("滑块和标签演示程序")
  9.         self.setGeometry(300, 300, 300, 200)

  10.         self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
  11.         self.slider.setGeometry(30, 40, 100, 30)
  12.         self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
  13.         self.slider.valueChanged.connect(self.change_value)

  14.         self.label = QtWidgets.QLabel(self)
  15.         self.label.setPixmap(QtGui.QPixmap(r"sample_06.png"))
  16.         self.label.setGeometry(160, 40, 128, 128)

  17.     def change_value(self):
  18.         pos = self.slider.value()
  19.         if pos == 0:
  20.             self.label.setPixmap(QtGui.QPixmap(r"sapmle_06.png"))
  21.         elif 0 < pos < 60:
  22.             self.label.setPixmap(QtGui.QPixmap(r"sapmle__12.png"))
  23.         else:
  24.             self.label.setPixmap(QtGui.QPixmap(r"sapmle__05.png"))

  25. app = QtWidgets.QApplication(sys.argv)
  26. sl = SliderLabel()
  27. sl.show()
  28. sys.exit(app.exec_())
复制代码
在这个示例中我们模拟一个速度控制的场景(请勿吐槽),通过拖动滑块来改变标签部件中的图片显示。
  1. self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
复制代码
通过该语句我们创建了一个水平滑块部件。
  1. self.label = QtWidgets.QLabel(self)
  2. self.label.setPixmap(QtGui.QPixmap(“sample_06.png”))
复制代码
以上两行语句用来创建一个标签部件并将 sample_06.png 加入到该部件中显示。
  1. self.slider.valueChanged.connect(self.change_value)
复制代码
这行语句将滑块的valueChanged()信号与自定义的 changeValue()方法相连接。
  1. pos = self.slider.value()
复制代码
这条语句用来获取当前的滑块位置。

                               
登录/注册后可看大图

截图:滑块和标签示例
7.4 QProgressBar进度条
当我们在处理一个耗时较长的任务时,可能就会用到进度条部件。因为使用进度条可以形象告诉用户当前的任务正在进行中。PyQt5 工具包提供了水平和垂直两种类型的进度条部件。我们可以设置进度条的最大和最小值,默认的最大和最小值分别为 0 99

  1. # -*- coding: utf-8 -*-
  2. """进度条示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore


  5. class ProgressBar(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(ProgressBar, self).__init__()

  8.         self.setWindowTitle("进度条演示程序")
  9.         self.setGeometry(300, 300, 250, 150)

  10.         self.progress_bar = QtWidgets.QProgressBar(self)
  11.         self.progress_bar.setGeometry(30, 40, 200, 25)

  12.         self.button = QtWidgets.QPushButton("开始", self)
  13.         self.button.setFocusPolicy(QtCore.Qt.NoFocus)
  14.         self.button.move(40, 80)
  15.         self.button.clicked.connect(self.on_start)

  16.         self.timer = QtCore.QBasicTimer()
  17.         self.step = 0

  18.     def timerEvent(self, *args, **kwargs):
  19.         if self.step >= 100:
  20.             self.timer.stop()
  21.             return
  22.         self.step += 1
  23.         self.progress_bar.setValue(self.step)

  24.     def on_start(self):
  25.         if self.timer.isActive():
  26.             self.timer.stop()
  27.             self.button.setText("开始")
  28.         else:
  29.             self.timer.start(100, self)
  30.             self.button.setText("停止")

  31. app = QtWidgets.QApplication(sys.argv)
  32. pb = ProgressBar()
  33. pb.show()
  34. sys.exit(app.exec_())
复制代码
在这个示例中,我们创建了一个水平的进度条和一个按钮。按钮用来启动或终止进度。
  1. self.progress_bar = QtWidgets.QProgressBar(self)
复制代码
使用该构造器来创建一个进度条。
  1. self.timer = QtCore.QBasicTimer()
复制代码
创建一个定时器对象。
  1. self.timer.start(100, self)
复制代码
要激活该进度条,我们需要使用定时器的start()方法启动定时器。该方法的第一个参数为超时时间。第二个参数表示当前超时时间到了以后定时器触发超时事件的接收对象。
  1. def timerEvent(self, *args, **kwargs):
  2.         if self.step >= 100:
  3.             self.timer.stop()
  4.             return
  5.         self.step += 1
  6.         self.progress_bar.setValue(self.step)
复制代码
每一个 QObject 对象或其子对象都有一个QObject.timerEvent 方法。在本实例中,为了响应定时器的超时事件,我们需要使用上面的代码重写进度条的 timerEvent 方法。
PS:在输入这个例子的过程中我把进度条和按钮创建语句中的self忘了输入,结果最后出来的例子中没有这两个部件,部件生成语句中的参数其中一个应该就是这个部件所属的部件,在这个例子中,进度条和按钮都应该被放置在主窗体上,也就是ProgressBar类的一个实例上。

                               
登录/注册后可看大图

截图:进度条示例
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-18 12:35:15 | 显示全部楼层
7.5 QCalendarWidget日历部件
QCalendarWidget 类提供了以月为单位的日历部件。该部件允许用户以一种简单而直接的方式选择日期。
  1. # -*- coding: utf-8 -*-
  2. """日历部件示例"""
  3. import sys
  4. from PyQt5 import QtWidgets, QtCore


  5. class CalendarWidget(QtWidgets.QWidget):
  6.     def __init__(self):
  7.         super(CalendarWidget, self).__init__()

  8.         self.setWindowTitle("日历部件演示程序")
  9.         self.setGeometry(300, 300, 350, 300)

  10.         self.calendar = QtWidgets.QCalendarWidget(self)
  11.         self.calendar.setGridVisible(True)
  12.         self.calendar.selectionChanged.connect(self.show_date)

  13.         date = self.calendar.selectedDate()
  14.         self.label = QtWidgets.QLabel(self)
  15.         self.label.setText(str(date.toPyDate()))

  16.         v_box = QtWidgets.QVBoxLayout()
  17.         v_box.addWidget(self.calendar)
  18.         v_box.addWidget(self.label)
  19.         self.setLayout(v_box)

  20.     def show_date(self):
  21.         date = self.calendar.selectedDate()
  22.         self.label.setText(str(date.toPyDate()))

  23. app = QtWidgets.QApplication(sys.argv)
  24. cw = CalendarWidget()
  25. cw.show()
  26. sys.exit(app.exec_())
复制代码
该示例窗口拥有一个日历部件和一个标签部件。当前被选中的日期被显示在标签部件中。
  1. self.calendar = QtWidgets.QCalendarWidget(self)
复制代码
使用上面的语句创建一个日历对象。
  1. self.calendar.selectionChanged.connect(self.show_date)
复制代码
上面的语句将日历对象的selectionChanged()信号和自定义的 showDate()方法相连接。这样在我们选定一个日期后,日历对象的selectionChanged()信号就会被触发,而与之相连的 showDate()方法就会被调用。
  1. def show_date(self):
  2.         date = self.calendar.selectedDate()
  3.         self.label.setText(str(date.toPyDate()))
复制代码
在 showDate 方法中,我们使用 selectedDate方法获取被选择的日期。然后将其转换为字符串并显示在标签部件中。

                               
登录/注册后可看大图

截图:日历部件示例

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-16 18:39

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表