Python疑惑以及所有使用库问题汇总笔记记录

此文以记录一些常见的、模糊的Python知识点以及在使用其所有的模块库过程中产生的疑惑为主,在此记录以观后效之用。

Python如何运行程序

大多数程序员仅知道运行Python就是在文本中输入代码,然后将其交与“解释器”去执行运行。但是,透过表面去确切了解一下这个步骤:第一步是编译成所谓的“字节码”,之后再将其转发到所谓的“虚拟机”中。了解这个步骤可以帮助我们宏观上掌握程序的执行。

字节码编译

当程序执行时,Python内部(对大多数用户来说是完全隐藏的)会先将源代码(文中的语句)编译成所谓字节码的形式。概括地说,Python通过把每一条源语句分解为单一步骤来将这些源代码翻译成一组字节码指令,这是一个简单的翻译步骤,而且字节码是源代码底层的、与平台无关的表现形式。另外值得一提的是:这些字节码可以提高执行速度,比起文本文件中的原始的源代码语句,它的运行速度要快得多。

下面来看看其中的奇妙之处:若是Python进程在机器上拥有写入权限,那么它将把程序的字节码保存为一个以.pyc.pyc即为编译过的.py源代码)为扩展名的文件,程序运行之后,这些文件会在源代码附近的文件处可看到。实际上Python这样保存字节码是作为一种启动速度的优化。下一次运行程序时,若是在上次保存字节码之后没有修改过源代码,Python将会直接加载上次的.pyc文件并跳过编译的这个步骤。相反的,若是源代码有改动,在保存了之后,运行之时字节码也会重新创建,另外,当Python必须重编译时,它会自动检查源文件和字节码文件的时间戳。

值得注意的是:如果Python无法在机器上写入字节码,程序依然是可以工作的:字节码会在内存中生成并在程序结束时简单地丢弃。尽管这样,由于.pyc文件能够加速启动,所以最好保证在大型程序中可以写入。字节码文件同样是分发Python程序的方法之一:如果Python找到的是.pyc文件,它会很乐意去运行这个程序,尽管这里没有原始的.py源代码文件。

另外因为Python字节码不是机器的二进制代码(例如Intel芯片的指令),字节码仅仅相当于Python定义的一种表现形式。另外,字节码相较二进制,后者更为低级,而Python源代码相较于字节码,后者更为低级。

Python虚拟机(PVM)

一旦程序编译成字节码或者是从已保存的.pyc文件中载入,之后的字节码会被发送到通常被称为Python虚拟机(Python Virtual Machine,简写为PVM)上来执行。实际上PVM只是Python整体中的一个组件,可理解为是运行脚本的组件,从技术上来说,就是所谓的“Python解释器”的最后一步。简单的Python代码运行可理解为以下的图片中的样子:

必须要理解的是这些复杂性的运行结构都是有意识地被隐藏起来,字节码的编译时自动完成的,PVM亦只是安装好的Python系统中的一部分,而程序员只是简单的编写、运行即可。关于PVM与Python解释器之间的关系简单的可总结为:PVM是Python是Python运行时引擎,从技术上讲只是解释器中执行的“最后一步”,而解释器其中还承担着其它的PVM不涉及到的任务,即可理解为PVM的执行功能属于解释器的一个子集。在此不妨简单的介绍一下Python的解释器:实际情况来说,Python就是一个名为解释器的软件包,是代码与计算机硬件之间的软件逻辑层,当编写了一段Python代码,Python解释器将读取程序,并按照其中的命令执行,得出结果。另外可额外说明一下,CPython为当今标准的解释器(这个名字来自它是由可移植的ANSI C/C语言代码编写而成的这个事实)。当然还有其他语言实现的Python解释器,但是由于CPython是这门语言的标准参照实现,所以与其它语言实现的解释器相比,它运行的最快、最完整、最新,而且最健全。

Python的运行速度

在Python的工作中通常没有build或者是make的步骤:即为代码在写好之后立即运行。加上Python的字节码的特性,PVM循环(而不是CPU芯片)仍然须解释这些字节码,而且字节码指令与CPU指令相比需要做更多的工作,另外与其他的经典的解释器不同,Python中有内部的编译步骤:Python并不需要反复地重分析和重分解每一行语句。另外需要牢记在心的心的是:Python中的运行是发生在实时性之中的,完全不需要先将所有源代码先编译好再丢给解释器去执行(静态语言常常如此),所有的建立的函数和类的操作以及连接的模块,这些都是在代码运行之时”编译-解释”如此一个步骤进行的。

这也是为什么Python的运行速度比不上C/C++之类的语言的运行速度的原因(C/C++将源代码编译为二进制机器码,而Python编译为字节码,而前者比后者更为低级,所以运行起来执行速度更快),Python的运行速度介于传统的编译语言与传统的解释语言之间,并且具有动态的弹性编程体验。

在此简单介绍一下PyPy:PyPy是原先的Psyco即时编译器(just-in-time,JIT)的继任者(即时编译器其实只是PVM的一个扩展,可见上方图的最右边方框所代表的),并将Psyco纳入一个追求速度的纯Python,也属于CPython标准的另一个实现,更为注重性能。它可将字节码中的部分转换为运行速度更快的二进制机器码(这一切发生在运行时期,而非运行前的编译阶段)。而且即时编译器可通过追踪程序中的对象数据类型,创建针对Python语言动态特性的机器代码,通过这种方式部分地替换字节码,从而达到程序将在运行时越跑越快。此外,一些Python代码在PyPy下运行也会占用更少的内存。值得一提的是:在某些情况下,它利用动态优化的优势可让Python运行得跟C代码一样的快,甚至可以超越。这点对于算法密集和计算密集型的程序尤为明显(CPU密集型)。

关于什么是CPU密集型、IO密集型可参考:什么是CPU密集型、IO密集型?

另外,由于Python的动态特性以及更为灵活简要等的特性,使得Python相较于C/C++使其达到了属于“高级语言”的行列。

交互式命令行与文件

一般在交互式命令行中的代码是实时的,是不会保存的,即运行之后的代码是不会保存的,需要重新输入代码之后才能继续运行;而在文件中是可以永久保存的,另外,我们认为的一般的编写代码的主文件称之为“脚本”(属于于一个顶层程序文件的非正式说法),调用的文件称之为“模块”,实际上,代码运行的可永久保存的文件通常是称之为模块的,可以直接运行的模块文件是称之为脚本的。

在交互式命令行中输入的复合式代码运行时需要在结束时的最后一行空出一行(即按下Entry键)以表示复合句结束;而在文件中的空格不是必须的,因为在解释器运行时,空格会被忽略掉一行一行地运行,但是为了代码的美观以及可读性,加上一些空格实际上也是不可少的。

Python值得一看的函数以及用法

固定的“一值”列表

1
weights = [100 for i in range(256)] #256组数字为100的列表

random模块的权重

1
2
3
4
5
6
>>> weighted_choices = [('Red', 3), ('Blue', 2), ('Yellow', 1), ('Green', 4)]
>>> population = [val for val, cnt in weighted_choices for i in range(cnt)]
>>> population
['Red', 'Red', 'Red', 'Blue', 'Blue', 'Yellow', 'Green', 'Green', 'Green', 'Green']
>>> random.choice(population)
'Green'

3.6版本新增这种方式中,为了给元素增加权重,按照元素的权重构造了一个新的列表,如上述代码中的population。在population中我们可以看到Red、Blue、Yellow、Green按照权重的方式各自新增元素,这就造成了使用choice()函数,即使是等几率的,出现的结果也会不一样,多的元素当然被选中的机会多.

itertools.accumulate对权重进行累加

1
2
3
4
5
>>> import itertools
>>> weights = [5, 5, 2, 5, 5]
>>> cumdist = list(itertools.accumulate(weights))
>>> cumdist
[5, 10, 12, 17, 22]

itertools.accumulate(iterable[, func])即为数字的权重累加,在总数上占几率较少的数字被选中的几率就会小。

1
2
3
cumdist = list(itertools.accumulate(weights)) #数的累加
x = random.random() * cumdist[-1] #定义的数字/矿
isgold = ore_list[bisect.bisect(cumdist, x)] #返回定义的数字在列表中的位置,以二分查找的方式

random.random()与最后一个cumdist相乘,random.random()的范围是浮点数0.0-1.0(不含)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import bisect
import random
random.seed(1)
print'New Pos Contents'
print'--- --- --------'
l = []
for i in range(1, 15):
r = random.randint(1, 100)
position = bisect.bisect(l, r)
bisect.insort(l, r)
print'%3d %3d' % (r, position), l
>>>
New Pos Contents
--- --- --------
14 0 [14]
85 1 [14, 85]
77 1 [14, 77, 85]
26 1 [14, 26, 77, 85]
50 2 [14, 26, 50, 77, 85]
45 2 [14, 26, 45, 50, 77, 85]
66 4 [14, 26, 45, 50, 66, 77, 85]
79 6 [14, 26, 45, 50, 66, 77, 79, 85]
10 0 [10, 14, 26, 45, 50, 66, 77, 79, 85]
3 0 [3, 10, 14, 26, 45, 50, 66, 77, 79, 85]
84 9 [3, 10, 14, 26, 45, 50, 66, 77, 79, 84, 85]
44 4 [3, 10, 14, 26, 44, 45, 50, 66, 77, 79, 84, 85]
77 9 [3, 10, 14, 26, 44, 45, 50, 66, 77, 77, 79, 84, 85]
1 0 [1, 3, 10, 14, 26, 44, 45, 50, 66, 77, 77, 79, 84, 85]

类似的函数:

1
random.choices(population, weights=None, *, cum_weights=None, k=1)

3.6版本新增!从population集群中随机抽取K个元素(可重复)。weights是相对权重列表,cum_weights是累计权重,两个参数不能同时存在。

几种Python执行时间的计算方法

来源:几种Python执行时间的计算方法

python脚本使用统计时间的方式是time.clock(),而这种方式统计的是CPU的执行时间,不是程序的执行时间。这样会导致在调度Python脚本执行并监控这个进程,python脚本运行时间远远大于python脚本中自己统计的程序执行时间。

方法一

1
2
3
4
5
6
import datetime
starttime = datetime.datetime.now()
#long running
#do something other
endtime = datetime.datetime.now()
print (endtime - starttime).seconds

datetime.datetime.now()获取的是当前日期,在程序执行结束之后,这个方式获得的时间值为程序执行的时间。

方法二

1
2
3
4
5
start = time.time()
#long running
#do something other
end = time.time()
print end-start

ime.time()获取自纪元以来的当前时间(以秒为单位)。如果系统时钟提供它们,则可能存在秒的分数。所以这个地方返回的是一个浮点型类型。这里获取的也是程序的执行时间。

方法三

1
2
3
4
5
start = time.clock()
#long running
#do something other
end = time.clock()
print end-start

time.clock()返回程序开始或第一次被调用clock()以来的CPU时间。 这具有与系统记录一样多的精度。返回的也是一个浮点类型。这里获得的是CPU的执行时间。程序执行时间=cpu时间 + io时间 + 休眠或者等待时间。

PyQt5问题

PyQT5模块解读

QtCore模块涵盖了包的核心的非GUI功能,此模块被用于处理程序中涉及到的 time、文件、目录、数据类型、文本流、链接、mime、线程或进程等对象。

QtGui模块涵盖多种基本图形功能的类; 包括但不限于:窗口集、事件处理、2D图形、基本的图像和界面和字体文本。

QtWidgets模块包含了一整套UI元素组件,用于建立符合系统风格的classic界面,非常方便,可以在安装时选择是否使用此功能。

QtMultimedia模块包含了一套类库,该类库被用于处理多媒体事件,通过调用API接口访问摄像头、语音设备、收发消息(radio functionality)等。

QtBluetooth模块包含了处理蓝牙活动的类库,它的功能包括:扫描设备、连接、交互等行为。

QtNetwork模块包含用于网络编程的类库,这组类程序通过提供便捷的TCP/IP 及 UDP 的 c/s 程式码集合,使得基于Qt的网络编程更容易。

QtPositioning模块用于获取位置信息,此模块允许使用多种方式达成定位,包括但不限于:卫星、无线网、文字信息。此应用一般用于网络地图定位系统。

Enginio模块用于构建客户端的应用程式库,用于在运行时访问 Qt Cloud 服务器托管的应用程序。

QtWebSockets模块包含了一组类程序,用以实现websocket协议。

QtWebKit包含了用于实现基于webkit2的网络浏览器的类库。

QtWebKitWidgets模块包含用于基于WebKit1的Web浏览器实现的类,用于基于QtWidgets的应用程序.

QtXml模块包含了用于处理XML的类库,此模块为SAX和DOM API 的实现提供了方法。

QtSvg模块通过一组类,为显示矢量图形文件的内容提供了方法。

QtSql模块提供了数据库对象的接口以供使用.

QtTest模块包含了可以通过单元测试,以调试PyQt5应用程式的功能。

值得记录的细节

sys.argv参数

1
app = QApplication(sys.argv)

每个PyQt5应用程序必须创建一个应用程序对象。sys.argv参数是来自命令行的参数列表。Python脚本可以从shell运行。写了这句话就能让我们的程序从命令行启动。

QWidget()

1
w = QWidget()

QWidget小部件是PyQt5中所有用户界面对象的基类。我们提供了QWidget的默认构造函数。默认构造函数没有父类。没有父类口小部件称为窗口。

主循环(main loop)

GUI应用程序都是事件驱动的。比如键盘事件、鼠标事件等等。还有一些事件来自于系统内部,比如定时事件、其它文件事件等等。在没有任何事件的情况下,应用程序处于睡眠状态。这种事件驱动机制,GUI应用程序都需要一个主循环(main loop)。主循环(main loop)控制应用程序什么时候进入睡眠状态,什么时候被唤醒。所以主循环(main loop)就是干这个的。

1
sys.exit(app.exec_())

事件处理从这一点开始。主循环(main loop)从窗口系统接收事件并将它们分派到应用程序小部件。如果我们调用exit()方法或者主窗口小部件被破坏,那么主循环(main loop)就会结束。

sys.exit()方法确保一个干净的退出。

exec_()方法有一个下划线。这是因为exec是一个Python关键字。 因此,使用exec_()。

setGeometry()

组合了resize()move()方法,它在屏幕上定位窗口并设置它的大小;前两个参数是窗口的x和y位置;第三个是宽度;第四个是窗口的高度。

三个函数均可结合部件以做绝对定位之用。

qbtn.clicked.connect(QCoreApplication.instance().quit)

PyQt5中的事件处理系统采用信号和槽机制构建。 如果我们点击按钮,点击的信号被发出。槽可以是Qt槽函数或任何Python可调用的函数。QCoreApplication包含主事件循环; 它处理和调度所有事件。instance()方法给我们当前的实例。QCoreApplication是通过QApplication创建的。点击的信号连接到终止应用程序的quit()方法。通信在两个对象之间完成:发送方和接收方。发送方是按钮,接收者是应用对象。

QLineEdit()部件配合使用

1
2
3
4
self.text = QLineEdit('在这里输入数字', self)
self.text.selectAll()
self.text.setFocus()
self.text.setGeometry(80, 50, 150 ,30)

selectAll()方法则是可以理解为将“在这里输入数字”进行全选,方便输入数字,否则还得手动全选删除默认字符;

setFocus()就是让焦点置于文本栏中,方便用户输入,不然还得手动在文本栏中单击一下,很是麻烦;

setGeometry()就是设置小部件的摆放坐标以及大小。

QMessageBox的主要使用

QMessageBox.about就是弹出一个对话框,告诉你结果是什么样的;

QMessageBox.question问题询问;

QMessageBox.critical图标打叉;

QMessageBox.warning图标警告;

QMessageBox.information消息询问;

QMessageBox对话框包含类型只是图标不同其他无太大差别。

QLCDNumber、QDial、QSlider

1
2
3
4
lcd = QLCDNumber(self)
dial = QDial(self)
dial.valueChanged.connect(lcd.display) # 数字牵动的函数

依次为屏幕上的数字变化、刻盘、滑动条。

keyPressEvent()键盘响应

1
2
3
4
5
6
7
8
9
10
self.lab = QLabel('方向',self)
def keyPressEvent(self, e):
if e.key() == Qt.Key_Up:
self.lab.setText('↑')
elif e.key() == Qt.Key_Down:
self.lab.setText('↓')
elif e.key() == Qt.Key_Left:
self.lab.setText('←')
else:
self.lab.setText('→')

按住上、下、左、右方向键的时候,窗口中依次会出现对应方位。

self.setMouseTracking(True)

默认情况下禁用鼠标跟踪,如果启用鼠标跟踪,即使没有按钮被按下,小部件也会接收鼠标移动事件。当然也可以不写,只需要在执行的过程中按照鼠标左键也行。

QFormLayout表单布局

1
2
3
4
5
6
7
8
9
formlayout = QFormLayout()
nameLabel = QLabel("姓名")
nameLineEdit = QLineEdit("")
introductionLabel = QLabel("简介")
introductionLineEdit = QTextEdit("")
formlayout.addRow(nameLabel,nameLineEdit)
formlayout.addRow(introductionLabel,introductionLineEdit)
self.setLayout(formlayout)

类似于将其一一对应(“姓名”:一空…)。QFormLayout是一个方便的布局类,其中的控件以两列的形式被布局在表单中。左列包括标签,右列包含输入控件,例如:QLineEdit、QSpinBox、QTextEdit等。

常用函数使用

clear()、accept()、ignore()函数

1
2
3
4
5
6
7
8
# 示例
def closeEvent(self, event):
reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()

clear()函数:内容清除;

accept()函数:接收并终止应用程序的事件;

ignore()函数:跳过并终止应用程序的事件。

update()、drawLine()函数

1
2
3
4
5
def mouseMoveEvent(self, event):
distance_from_center = round(((event.y() - 250)**2 + (event.x() - 500)**2)**0.5)
self.label.setText('坐标: ( x: %d ,y: %d )' % (event.x(), event.y()) + " 离中心点距离: " + str(distance_from_center))
self.pos = event.pos()
self.update()

update()函数:更新图形;

1
2
3
4
def paintEvent(self, event):
if self.pos:
q = QPainter(self)
q.drawLine(0, 0, self.pos.x(), self.pos.y())

drawLine()方法绘制一条线,需要四个参数,起点的坐标,终点的坐标。可配合鼠标实现。

sender()、text()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 石头剪刀布游戏
import sys
from PyQt5.QtWidgets import (QApplication, QMessageBox, QWidget, QPushButton)
from random import randint
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 300, 300)
self.setWindowTitle('学点编程吧')
bt1 = QPushButton('剪刀',self)
bt1.setGeometry(30,180,50,50)
bt2 = QPushButton('石头',self)
bt2.setGeometry(100,180,50,50)
bt3 = QPushButton('布',self)
bt3.setGeometry(170,180,50,50)
bt1.clicked.connect(self.buttonclicked)
bt2.clicked.connect(self.buttonclicked)
bt3.clicked.connect(self.buttonclicked)
self.show()
def buttonclicked(self):
computer = randint(1,3)
player = 0
sender = self.sender()
if sender.text() == '剪刀':
player = 1
elif sender.text() == '石头':
player = 2
else:
player = 3
if player == computer:
QMessageBox.about(self, '结果', '平手')
elif player == 1 and computer == 2:
QMessageBox.about(self, '结果', '电脑:石头,电脑赢了!')
elif player == 2 and computer == 3:
QMessageBox.about(self, '结果', '电脑:布,电脑赢了!')
elif player == 3 and computer == 1:
QMessageBox.about(self,'结果','电脑:剪刀,电脑赢了!')
elif computer == 1 and player == 2:
QMessageBox.about(self,'结果','电脑:剪刀,玩家赢了!')
elif computer == 2 and player == 3:
QMessageBox.about(self,'结果','电脑:石头,玩家赢了!')
elif computer == 3 and player == 1:
QMessageBox.about(self,'结果','电脑:布,玩家赢了!')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

sender()函数方法即为.clicked.connect()一类的函数相接;

1
2
3
4
5
6
7
sender = self.sender()
if sender.text() == '剪刀':
player = 1
elif sender.text() == '石头':
player = 2
else:
player = 3

在以上代码中,sender()函数可作为实例对象,text()函数主要以文字接收为主。

自定义信号Signal()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 单击鼠标的时候,就会弹出对话框告知我们单击了鼠标。
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QMessageBox)
from PyQt5.QtCore import (pyqtSignal, QObject)
class Signal(QObject):
showmouse = pyqtSignal()
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 300, 300)
self.setWindowTitle('学点编程吧')
self.s = Signal()
self.s.showmouse.connect(self.about)
self.show()
def about(self):
QMessageBox.about(self,'鼠标','你点鼠标了吧!')
def mousePressEvent(self, e):
self.s.showmouse.emit()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

建一个名为showmouse的新信号。该信号在鼠标按压事件期间发出。 该信号连接到QMainWindow的about()的槽。

1
2
class Signal(QObject):
showmouse = pyqtSignal()

使用pyqtSignal()作为外部Signal类的类属性创建一个信号。

1
2
self.s = Signal()
self.s.showmouse.connect(self.about)

自定义showmouse信号连接到QMainWindow的about()的槽。

1
2
def mousePressEvent(self, e):
self.s.showmouse.emit()

当我们用鼠标指针点击窗口时,会发出showmouse信号,调用相应的槽函数。

addStretch()函数

1
2
3
4
5
6
7
8
9
10
11
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(bt1)
hbox.addWidget(bt2)
hbox.addWidget(bt3)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)

HBoxLayout和一个QVBoxLayout主要以做水平垂直布局之用,addStretch(1)addStretch()函数的作用是在布局器中增加一个伸缩量,里面的参数表示QSpacerItem的个数,默认值为零,会将你放在layout中的空间压缩成默认的大小。例如用addStretch函数实现将QHBoxLayout的布局器的空白空间分配,addStretch()函数可在设定好的布局前提下将整个窗口进行拉伸(可缩小、放大)。并非每个布局函数均可使用!!

QGridLayout()、lcd.display()、zip()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 计算机界面核心代码
names = ['Cls', 'Bc', '', 'Close',
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+']
positions = [(i,j) for i in range(4,9) for j in range(4,8)]
for position, name in zip(positions, names):
if name == '':
continue
button = QPushButton(name)
grid.addWidget(button, *position)
button.clicked.connect(self.Cli)
self.show()
def Cli(self):
sender = self.sender().text()
ls = ['/', '*', '-', '=', '+']
if sender in ls:
self.lcd.display('A')
else:
self.lcd.display(sender)
1
2
grid = QGridLayout()
self.setLayout(grid)

创建QGridLayout的实例并将其设置为应用程序窗口的布局。

1
2
grid.addWidget(self.lcd,0,0,3,0)
grid.setSpacing(10)

如果我们向窗格添加窗口小部件,我们可以提供窗口小部件的行跨度和列跨度。在我们的例子中,我们使QLCDNumber小部件跨越4行。同时我们创建一个网格布局并在窗口小部件之间设置间距。

1
2
3
4
5
6
names = ['Cls', 'Bc', '', 'Close',
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+']
positions = [(i,j) for i in range(4,9) for j in range(4,8)]

我们创建了19个按钮并指定了具体的坐标位置。

1
2
3
4
5
if name == '':
continue
button = QPushButton(name)
grid.addWidget(button, *position)
button.clicked.connect(self.Cli)

使用addWidget()方法创建并添加到布局中的按钮。同时当我们按下按钮的时候调用self.Cli()方法

1
2
3
4
5
6
7
def Cli(self):
sender = self.sender().text()
ls = ['/', '*', '-', '=', '+']
if sender in ls:
self.lcd.display('A')
else:
self.lcd.display(sender)

当我们按下按钮的时候我们会得到按钮上显示的名称,如果是操作符则在LCD上显示“A”,LCD的显示功能有限,否则显示我们按下的信息。

lcd.display()函数结合QLCDNumber较为常见。

另外解释一下zip()函数:zip()用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。可以使用list()转换来输出列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用*号操作符,可以将元组解压为列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"""
zip 语法:
zip([iterable, ...])
参数说明:
iterabl -- 一个或多个迭代器;
返回值:
返回一个对象。
"""
# 实例
>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b) # 返回一个对象
>>> zipped
<zip object at 0x103abc288>
>>> list(zipped) # list() 转换为列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(a,c)) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> a1, a2 = zip(*zip(a,b)) # 与 zip 相反,zip(*) 可理解为解压,返回二维矩阵式
>>> list(a1)
[1, 2, 3]
>>> list(a2)
[4, 5, 6]

statusBar()、showMessage()函数

1
self.statusBar().showMessage('准备就绪')

要获取状态栏,我们调用QWidget.QMainWindow类的statusBar()方法。该方法的第一个调用创建一个状态栏。后续调用返回状态栏对象。showMessage()在状态栏上显示一条消息。

菜单

简单的菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp
from PyQt5.QtGui import QIcon
import sys
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.InitUI()
def InitUI(self):
self.statusBar().showMessage('准备就绪')
self.setGeometry(300,300,400,300)
self.setWindowTitle('关注微信公众号:学点编程吧--简单的菜单')
exitAct = QAction(QIcon('exit.png'), '退出(&E)', self)
exitAct.setShortcut('command+Q')
exitAct.setStatusTip('退出程序')
exitAct.triggered.connect(qApp.quit)
menubar = self.menuBar()
fileMenu = menubar.addMenu('文件(&F)')
fileMenu.addAction(exitAct)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

在上面的例子中,用了一个菜单创建一个菜单。此菜单将包含一个选择时终止应用程序的操作。还创建状态栏。该操作可通过command + Q快捷方式访问。

1
2
3
exitAct = QAction(QIcon('exit.png'), '退出(&E)', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('退出程序')

QAction是使用菜单栏,工具栏或自定义键盘快捷方式执行操作的抽象。在上述三行中,我们创建一个具有特定图标和“退出”标签的动作。此外,为此操作定义了快捷方式。当我们将鼠标指针悬停在菜单项上时,第三行创建状态栏显示在状态栏中。

1
exitAct.triggered.connect(qApp.quit)

当我们选择这个特定的动作时,发出触发信号。信号连接到QApplication小部件的quit()方法。 这终止了应用程序。

1
2
3
menubar = self.menuBar()
fileMenu = menubar.addMenu('文件(&F)')
fileMenu.addAction(exitAct)

menuBar()方法创建一个菜单栏。我们使用addMenu()创建文件菜单,并使用addAction()添加操作。

上面的代码中我们在退出、文件后面都增加了“&”这个符号,增加这个符号后,当我们按住“Alt+F”的时候就能快速打开文件这个菜单,同理按住“Alt+E”的时候就能退出了。

子菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp, QMenu
from PyQt5.QtGui import QIcon
import sys
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.InitUI()
def InitUI(self):
self.statusBar().showMessage('准备就绪')
self.setGeometry(300,300,400,300)
self.setWindowTitle('关注微信公众号:学点编程吧--子菜单')
exitAct = QAction(QIcon('exit.png'), '退出(&E)', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('退出程序')
exitAct.triggered.connect(qApp.quit)
saveMenu = QMenu('保存方式(&S)', self)
saveAct = QAction(QIcon('save.png'),'保存...', self)
saveAct.setShortcut('Ctrl+S')
saveAct.setStatusTip('保存文件')
saveasAct = QAction(QIcon('saveas.png'),'另存为...(&O)', self)
saveasAct.setStatusTip('文件另存为')
saveMenu.addAction(saveAct)
saveMenu.addAction(saveasAct)
newAct = QAction(QIcon('new.png'),'新建(&N)',self)
newAct.setShortcut('Ctrl+N')
menubar = self.menuBar()
fileMenu = menubar.addMenu('文件(&F)')
fileMenu.addAction(newAct)
fileMenu.addMenu(saveMenu)
fileMenu.addSeparator() # 貌似达成子菜单不可少的函数
fileMenu.addAction(exitAct)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

在这个例子中,有三个菜单项:其中两个位于文件菜单中(新建、退出),另一个位于文件的保存子菜单中。

1
saveMenu = QMenu('保存方式(&S)', self)

使用QMenu创建新菜单。

1
2
3
4
5
6
7
saveAct = QAction(QIcon('save.png'),'保存...', self)
saveAct.setShortcut('Ctrl+S')
saveAct.setStatusTip('保存文件')
saveasAct = QAction(QIcon('saveas.png'),'另存为...(&O)', self)
saveasAct.setStatusTip('文件另存为')
saveMenu.addAction(saveAct)
saveMenu.addAction(saveasAct)

两个动作使用addAction()被添加到子菜单中。

右键菜单/上下文菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp, QMenu
from PyQt5.QtGui import QIcon
import sys
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.InitUI()
def InitUI(self):
self.statusBar().showMessage('准备就绪')
self.setGeometry(300,300,400,300)
self.setWindowTitle('关注微信公众号:学点编程吧--上下文菜单')
exitAct = QAction(QIcon('exit.png'), '退出(&E)', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('退出程序')
exitAct.triggered.connect(qApp.quit)
saveMenu = QMenu('保存方式(&S)', self)
saveAct = QAction(QIcon('save.png'),'保存...', self)
saveAct.setShortcut('Ctrl+S')
saveAct.setStatusTip('保存文件')
saveasAct = QAction(QIcon('saveas.png'),'另存为...(&O)', self)
saveasAct.setStatusTip('文件另存为')
saveMenu.addAction(saveAct)
saveMenu.addAction(saveasAct)
newAct = QAction(QIcon('new.png'),'新建(&N)',self)
newAct.setShortcut('Ctrl+N')
newAct.setStatusTip('新建文件')
menubar = self.menuBar()
fileMenu = menubar.addMenu('文件(&F)')
fileMenu.addAction(newAct)
fileMenu.addMenu(saveMenu)
fileMenu.addSeparator()
fileMenu.addAction(exitAct)
self.show()
def contextMenuEvent(self, event):
cmenu = QMenu(self)
newAct = cmenu.addAction("新建")
opnAct = cmenu.addAction("保存")
quitAct = cmenu.addAction("退出")
action = cmenu.exec_(self.mapToGlobal(event.pos()))
if action == quitAct:
qApp.quit()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

要使用上下文菜单,必须重新实现contextMenuEvent()方法。

1
action = cmenu.exec_(self.mapToGlobal(event.pos()))

使用exec_()方法显示上下文菜单。从事件对象获取鼠标指针的坐标。 mapToGlobal()方法将窗口小部件坐标转换为全局屏幕坐标。

globalPos(),给出的坐标信息是相对于桌面的,即以桌面左上角为原点。

pos(),是相对于窗口的,以窗口左上角为原点(去除边框)。即pos()给出的是一个相对位置坐标。而globalPos(),给出的是一个绝对坐标。

简单来说可理解为:一个相对于全电脑屏幕,一个仅仅相对于建立的界面。

1
2
if action == quitAct:
qApp.quit()

如果从上下文菜单返回的操作等于退出操作,终止应用程序。

工具栏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp, QMenu
from PyQt5.QtGui import QIcon
import sys
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.InitUI()
def InitUI(self):
self.statusBar().showMessage('准备就绪')
self.setGeometry(300,300,400,300)
self.setWindowTitle('关注微信公众号:学点编程吧--上下文菜单')
exitAct = QAction(QIcon('exit.png'), '退出(&E)', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('退出程序')
exitAct.triggered.connect(qApp.quit)
saveMenu = QMenu('保存方式(&S)', self)
saveAct = QAction(QIcon('save.png'),'保存...', self)
saveAct.setShortcut('Ctrl+S')
saveAct.setStatusTip('保存文件')
saveasAct = QAction(QIcon('saveas.png'),'另存为...(&O)', self)
saveasAct.setStatusTip('文件另存为')
saveMenu.addAction(saveAct)
saveMenu.addAction(saveasAct)
newAct = QAction(QIcon('new.png'),'新建(&N)',self)
newAct.setShortcut('Ctrl+N')
newAct.setStatusTip('新建文件')
menubar = self.menuBar()
fileMenu = menubar.addMenu('文件(&F)')
fileMenu.addAction(newAct)
fileMenu.addMenu(saveMenu)
fileMenu.addSeparator()
fileMenu.addAction(exitAct)
toolbar = self.addToolBar('工具栏')
toolbar.addAction(newAct)
toolbar.addAction(exitAct)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

可以把一些常用的命令放在工具栏上,例如新建、打开、保存等等。

1
2
3
toolbar = self.addToolBar('工具栏')
toolbar.addAction(newAct)
toolbar.addAction(exitAct)

工具栏使用addToolBar()方法创建。可使用addAction()向工具栏添加两个动作对象。

对话框窗口

对话框窗口或对话框是大多数现代GUI应用程序中不可或缺的一部分。在计算机应用程序中,一个对话框是一个用于“与应用程序”通话的窗口。对话框用于输入数据,修改数据,更改应用程序设置等。

标准对话框、QInputDialog的主要方法

提供了一个简单的便利对话框,可以从用户获取单个值。 输入值可以是列表中的字符串,数字或项目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 可以输入浮点型小数,最小值、最大值可以自己设定。
getDouble(QWidget, str, str, value: float = 0, min: float = -2147483647, max: float = 2147483647, decimals: int = 1, flags: Union[Qt.WindowFlags,Qt.WindowType]=Qt.WindowFlags())->Tuple[float,bool]
# 可以输入整数,最小值、最大值可以自己设定,步长也可以自己设定。
getInt(QWidget, str, str, value: int = 0, min: int = -2147483647, max: int = 2147483647, step: int = 1, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags()) -> Tuple[int, bool]
# 输入选择项,待选放到列表中,需提前设定
getItem(QWidget, str, str, Iterable[str], current:int=0,editable:bool=True,flags:Union[Qt.WindowFlags,Qt.WindowType]=Qt.WindowFlags(),inputMethodHints:Union[Qt.InputMethodHints,Qt.InputMethodHint] = Qt.ImhNone) -> Tuple[str, bool]
# 可以输入富文本,在里面增加一些格式信息。如将文字加粗等操作。
getMultiLineText(QWidget, str, str, text: str = '', flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags(), inputMethodHints: Union[Qt.InputMethodHints, Qt.InputMethodHint] = Qt.ImhNone)-> Tuple[str, bool]
# 直接获取输入的字符文本数据。
getText(QWidget, str, str, echo: QLineEdit.EchoMode = QLineEdit.Normal,text: str = '', flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags(),inputMethodHints: Union[Qt.InputMethodHints, Qt.InputMethodHint] = Qt.ImhNone) -> Tuple[str, bool]

以上为主要使用的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QLabel, QInputDialog, QTextBrowser)
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(500,500,500,550)
self.setWindowTitle('关注微信公众号:学点编程吧--标准输入对话框')
self.lb1 = QLabel('姓名:',self)
self.lb1.move(20,20)
self.lb2 = QLabel('年龄:',self)
self.lb2.move(20,80)
self.lb3 = QLabel('性别:',self)
self.lb3.move(20,140)
self.lb4 = QLabel('身高(cm):',self)
self.lb4.move(20,200)
self.lb5 = QLabel('基本信息:',self)
self.lb5.move(20,260)
self.lb6 = QLabel('学点编程',self)
self.lb6.move(80,20)
self.lb7 = QLabel('18',self)
self.lb7.move(80,80)
self.lb8 = QLabel('男',self)
self.lb8.move(80,140)
self.lb9 = QLabel('175',self)
self.lb9.move(120,200)
self.tb = QTextBrowser(self)
self.tb.move(20,320)
self.bt1 = QPushButton('修改姓名',self)
self.bt1.move(200,20)
self.bt2 = QPushButton('修改年龄',self)
self.bt2.move(200,80)
self.bt3 = QPushButton('修改性别',self)
self.bt3.move(200,140)
self.bt4 = QPushButton('修改身高',self)
self.bt4.move(200,200)
self.bt5 = QPushButton('修改信息',self)
self.bt5.move(200,260)
self.show()
self.bt1.clicked.connect(self.showDialog)
self.bt2.clicked.connect(self.showDialog)
self.bt3.clicked.connect(self.showDialog)
self.bt4.clicked.connect(self.showDialog)
self.bt5.clicked.connect(self.showDialog)
def showDialog(self):
sender = self.sender()
sex = ['男','女']
if sender == self.bt1:
text, ok = QInputDialog.getText(self, '修改姓名', '请输入姓名:')
if ok:
self.lb6.setText(text)
elif sender == self.bt2:
text, ok = QInputDialog.getInt(self, '修改年龄', '请输入年龄:', min = 1)
if ok:
self.lb7.setText(str(text))
elif sender == self.bt3:
text, ok = QInputDialog.getItem(self, '修改性别', '请选择性别:',sex)
if ok:
self.lb8.setText(text)
elif sender == self.bt4:
text, ok = QInputDialog.getDouble(self, '修改身高', '请输入身高:', min = 1.0)
if ok:
self.lb9.setText(str(text))
elif sender == self.bt5:
text, ok = QInputDialog.getMultiLineText(self, '修改信息', '请输入个人信息:')
if ok:
self.tb.setText(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

该示例具有按钮和标签和文本浏览器。通过按钮显示输入对话框以便获取值。输入的文本将显示在窗口的标签和文本浏览器中。

1
2
3
4
5
self.bt1.clicked.connect(self.showDialog)
self.bt2.clicked.connect(self.showDialog)
self.bt3.clicked.connect(self.showDialog)
self.bt4.clicked.connect(self.showDialog)
self.bt5.clicked.connect(self.showDialog)

单击按钮连接对应的槽函数。

1
2
if sender == self.bt1:
text, ok = QInputDialog.getText(self, '修改姓名', '请输入姓名:')

若按下按钮1,此时显示输入对话框。第一个字符串是一个对话标题,第二个是对话框中的一个消息。对话框返回输入的文本和布尔值。如果点击Ok按钮,布尔值为true。

1
2
if ok:
self.lb6.setText(text)

如果按下ok键,则对应标签的text值是从对话框接收的文本。

颜色、字体、打开文件对话框:QColorDialog, QFontDialog, QTextEdit, QFileDialog、QTextEdit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QColorDialog, QFontDialog, QTextEdit, QFileDialog
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 500, 300)
self.setWindowTitle('关注微信公众号:学点编程吧--记得好看点')
self.tx = QTextEdit(self)
self.tx.setGeometry(20, 20, 300, 270)
self.bt1 = QPushButton('打开文件',self)
self.bt1.move(350,20)
self.bt2 = QPushButton('选择字体',self)
self.bt2.move(350,70)
self.bt3 = QPushButton('选择颜色',self)
self.bt3.move(350,120)
self.bt1.clicked.connect(self.openfile)
self.bt2.clicked.connect(self.choicefont)
self.bt3.clicked.connect(self.choicecolor)
self.show()
def openfile(self):
fname = QFileDialog.getOpenFileName(self, '打开文件','./')
if fname[0]:
with open(fname[0], 'r',encoding='gb18030',errors='ignore') as f:
self.tx.setText(f.read())
def choicefont(self):
font, ok = QFontDialog.getFont()
if ok:
self.tx.setCurrentFont(font)
def choicecolor(self):
col = QColorDialog.getColor()
if col.isValid():
self.tx.setTextColor(col)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

通过上述代码了解到主要是涉及QColorDialog,QFontDialog,QTextEdit, QFileDialog这四个类,其中QColorDialog, QFontDialog, QFileDialog分别负责颜色选择对话框、字体选择对话框、打开文件对话框,QTextEdit则是将刚才提到的类的结果用于呈现。QTextEdit能够呈现富文本,也能够呈现普通输出文本。

1
2
3
self.bt1.clicked.connect(self.openfile)
self.bt2.clicked.connect(self.choicefont)
self.bt3.clicked.connect(self.choicecolor)

当单击不同的按钮的时候,会调用对应的槽函数。

1
fname = QFileDialog.getOpenFileName(self, '打开文件','./')

我们弹出QFileDialog对话框。getOpenFileName()方法中的第一个字符串是标题。第二个字符串指定对话框工作目录。默认情况下,文件过滤器设置为所有文件(*),即不限制打开文件的类型。该函数返回值类型是元组。如果增加文件过滤,可以改成如下语句:

1
fname = QFileDialog.getOpenFileName(self, '打开文件','./',("Images (*.png *.xpm *.jpg)"))
1
2
3
if fname[0]:
with open(fname[0], 'r',encoding='gb18030',errors='ignore') as f:
self.tx.setText(f.read())

读取所选择的文件名,并将文本编辑小部件的内容设置为文件读取的内容。这里提一下使用with语句来自动调用close()方法,避免由于文件读写时产生IOError,导致close()不会调用,需要try ... finally来实现的不便。

1
font, ok = QFontDialog.getFont()

这里弹出字体对话框。getFont()方法返回字体名称以及用户点击按钮的状态。如果用户点击Ok,则等于True;否则是假的。

1
2
if ok:
self.tx.setCurrentFont(font)

如果用户点击ok键,那么在文本编辑小部件中选择的内容会使用我们选择的字体。

1
2
3
col = QColorDialog.getColor()
if col.isValid():
self.tx.setTextColor(col)

这段代码的意思和刚才描述的大致相同,弹出颜色选择的对话框。检查颜色是否有效。如果点击“取消”按钮,则不会返回有效的颜色。如果颜色有效,那么在文本编辑小部件中选择的内容会使用选择的颜色。

QFileDialog打印文案对象QtPrintSupport类:QPageSetupDialog、QPrintDialog、QPrinter

本知识点主要以一个打印机的例子作为开端学习,用以说明如何打开多文件、保存文件以及打印文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QTextEdit, QFileDialog, QDialog
from PyQt5.QtPrintSupport import QPageSetupDialog, QPrintDialog, QPrinter
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.printer = QPrinter()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 500, 400)
self.setWindowTitle('关注微信公众号:学点编程吧--保存、打印文件')
self.tx = QTextEdit(self)
self.tx.setGeometry(20, 20, 300, 270)
self.bt1 = QPushButton('打开文件',self)
self.bt1.move(350,20)
self.bt2 = QPushButton('打开多个文件',self)
self.bt2.move(350,70)
self.bt5 = QPushButton('保存文件',self)
self.bt5.move(350,220)
self.bt6 = QPushButton('页面设置',self)
self.bt6.move(350,270)
self.bt7 = QPushButton('打印文档',self)
self.bt7.move(350,320)
self.bt1.clicked.connect(self.openfile)
self.bt2.clicked.connect(self.openfiles)
self.bt5.clicked.connect(self.savefile)
self.bt6.clicked.connect(self.pagesettings)
self.bt7.clicked.connect(self.printdialog)
self.show()
def openfile(self):
fname = QFileDialog.getOpenFileName(self, '学点编程吧:打开文件','./')
if fname[0]:
with open(fname[0], 'r',encoding='gb18030',errors='ignore') as f:
self.tx.setText(f.read())
def openfiles(self):
fnames = QFileDialog.getOpenFileNames(self, '学点编程吧:打开多个文件','./')
if fnames[0]:
for fname in fnames[0]:
with open(fname, 'r',encoding='gb18030',errors='ignore') as f:
self.tx.append(f.read())
def savefile(self):
fileName = QFileDialog.getSaveFileName(self, '学点编程吧:保存文件','./',"Text files (*.txt)")
if fileName[0]:
with open(fileName[0], 'w',encoding='gb18030',errors='ignore') as f:
f.write(self.tx.toPlainText())
def pagesettings(self):
printsetdialog = QPageSetupDialog(self.printer,self)
printsetdialog.exec_()
def printdialog(self):
printdialog = QPrintDialog(self.printer,self)
if QDialog.Accepted == printdialog.exec_():
self.tx.print(self.printer)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
1
from PyQt5.QtPrintSupport import QPageSetupDialog, QPrintDialog, QPrinter

从类的字面意思可以了解到QPageSetupDialog涉及页面设置的,QPrintDialog涉及打印,而QPrinter类是PyQt的打印主要使用,即打印类。大量和打印相关的函数均会涉及到该类。根据Qt的官方文档的介绍,QPrinter类与其他绘图类(如QWidgetQPixmap)原理几乎完全相同。提供了一组附加功能来管理设备的特定功能,例如方向和分辨率等。可理解为就是高度抽象的虚拟打印机,通过与这台打印交互达到控制本地实际打印机的功能。

1
2
3
4
5
class Example(QWidget):
def __init__(self):
super().__init__()
self.printer = QPrinter()
self.initUI()

因为下面代码中QPageSetupDialogQPrintDialog涉及到QPrinter()对象,所以将其在类初始化的时候生成,便于函数的调用。

1
2
3
4
5
6
def openfiles(self):
fnames = QFileDialog.getOpenFileNames(self, '学点编程吧:打开多个文件','./')
if fnames[0]:
for fname in fnames[0]:
with open(fname, 'r',encoding='gb18030',errors='ignore') as f:
self.tx.append(f.read())

QFileDialog.getOpenFileNames将返回用户选择的一个或多个现有文件,注意这里返回值是元组。元组的第0个元素则是列表,例如fnames其实是这样的:

1
(['C:/Users/yangff/Desktop/PyQt5/10/美文.txt', 'C:/Users/yangff/Desktop/PyQt5/10/十九大(new).txt', 'C:/Users/yangff/Desktop/PyQt5/10/十九大.txt'], '')

所以才需要通过对fnames[0]进行遍历,分别读取每个文件的内容,然后在QTextEdit显示出来。需要注意的是:使用了QTextEditappend方法,让每次显示的内容均会存留在QTextEdit上。这个选择元组中列表数据是与之前对爬取的数据(.json)进行数据清洗类似的操作,而在使用append方法表示依次将所取得的文件全部打印在窗口。这个函数的第二个参数是对话框的标题,第三个参数是设置打开文件的目录。当然还可以增加第四个,也就是增加一个过滤器,以便仅显示与过滤器匹配的文件。 例如:

1
2
3
4
5
6
7
fnames = QFileDialog.getOpenFileNames(self, '学点编程吧:打开多个文件','./',"Text files (*.txt)")
def savefile(self):
fileName = QFileDialog.getSaveFileName(self, '学点编程吧:保存文件','./',"Text files (*.txt)")
if fileName[0]:
with open(fileName[0], 'w',encoding='gb18030',errors='ignore') as f:
f.write(self.tx.toPlainText())

getSaveFileName()具体的用法与getOpenFileNames()类似,只是用来保存文件的。最后我们使用write函数将QTextEdit的内容保存在文件中。获取的QTextEdit的内容可以使用这个函数toPlainText()(转为纯文本保存)。

1
2
3
def pagesettings(self):
printsetdialog = QPageSetupDialog(self.printer,self)
printsetdialog.exec_()

QPageSetupDialog类为打印机上的页面相关选项提供了一个配置对话框。这个就必须使用到QPrinter对象了。另外说明一下的是exec_()函数,这个函数即为执行脚本文件(如.py)用的,在这里是起到启用QPrinter的代码的意思。

1
printsetdialog.exec_()

这句话就相当于执行确认的页面设置信息。

1
2
3
4
def printdialog(self):
printdialog = QPrintDialog(self.printer,self)
if QDialog.Accepted == printdialog.exec_():
self.tx.print(self.printer)

这个函数的意思就是调用QPrintDialog准备进行打印了。QPrintDialog类提供了一个用于指定打印机配置的对话框。对话框允许用户更改文档相关设置,如纸张尺寸和方向,打印类型(颜色或灰度),页面范围和打印份数。还提供控制以使用户可以从可用的打印机中进行选择,包括任何配置的网络打印机。通常,QPrintDialog对象使用QPrinter对象构造,并使用exec()函数执行。

1
2
if QDialog.Accepted == printdialog.exec_():
self.tx.print(self.printer)

在选择好打印机等等后,点击打印(即对话框被用户接受,则QPrinter对象被正确配置为打印),则会调用QTextEdit中的print方法进行相关的打印(内容输出即打印)。

QFileDialog消息对话框QMessageBox类,QPixmap类:setIconPixmap()、QMessageBox.Warning、QMessageBox.Information、QMessageBox.Question、QMessageBox.Critical

消息对话框主要涉及QMessageBox类。QMessageBox类提供了一个模态对话框,用于通知用户或询问用户问题并接收答案。消息框显示主要文本以提醒用户情况,信息性文本以进一步解释警报或询问用户一个问题,以及可选的详细文本,以便在用户请求时提供更多数据。消息框还可以显示用于接受用户响应的图标和标准按钮。提供了两个使用QMessageBox的API,基于属性的API和静态函数。调用静态函数是更简单的方法,但是比使用基于属性的API更不灵活,结果信息较少。两种方法在程序中都使用了。一般而言,消息对话框分为五种,分别是提示信息、询问、警告、错误、关于,其中关于又分为两种,一种是一般性关于、另一种是关于Qt的介绍,可以明显看见不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QMessageBox, QLabel, QCheckBox
from PyQt5.QtGui import QPixmap
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 330, 300)
self.setWindowTitle('关注微信公众号:学点编程吧--消息对话框')
self.la = QLabel('这里将会显示我们选择的按钮信息',self)
self.la.move(20,20)
self.bt1 = QPushButton('提示',self)
self.bt1.move(20,70)
self.bt2 = QPushButton('询问',self)
self.bt2.move(120,70)
self.bt3 = QPushButton('警告',self)
self.bt3.move(220,70)
self.bt4 = QPushButton('错误',self)
self.bt4.move(20,140)
self.bt5 = QPushButton('关于',self)
self.bt5.move(120,140)
self.bt6 = QPushButton('关于Qt',self)
self.bt6.move(220,140)
self.bt1.clicked.connect(self.info)
self.bt2.clicked.connect(self.question)
self.bt3.clicked.connect(self.warning)
self.bt4.clicked.connect(self.critical)
self.bt5.clicked.connect(self.about)
self.bt6.clicked.connect(self.aboutqt)
self.show()
def info(self):
reply = QMessageBox.information(self,'提示','这是一个消息提示对话框!', QMessageBox.Ok | QMessageBox.Close, QMessageBox.Close)
if reply == QMessageBox.Ok:
self.la.setText('你选择了Ok!')
else:
self.la.setText('你选择了Close!')
def question(self):
reply = QMessageBox.question(self,'询问','这是一个询问消息对话框,默认是No', QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, QMessageBox.No)
if reply == QMessageBox.Yes:
self.la.setText('你选择了Yes!')
elif reply == QMessageBox.No:
self.la.setText('你选择了No!')
else:
self.la.setText('你选择了Cancel!')
def warning(self):
# reply = QMessageBox.warning(self,'警告','这是一个警告消息对话框', QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, QMessageBox.Save)
cb = QCheckBox('所有文档都按此操作')
msgBox = QMessageBox()
msgBox.setWindowTitle('警告')
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText('这是一个警告消息对话框')
msgBox.setInformativeText('出现更改愿意保存吗?')
Save = msgBox.addButton('保存', QMessageBox.AcceptRole)
NoSave = msgBox.addButton('取消', QMessageBox.RejectRole)
Cancel = msgBox.addButton('不保存', QMessageBox.DestructiveRole)
msgBox.setDefaultButton(Save)
msgBox.setCheckBox(cb)
cb.stateChanged.connect(self.check)
reply = msgBox.exec()
if reply == QMessageBox.AcceptRole:
self.la.setText('你选择了保存!')
elif reply == QMessageBox.RejectRole:
self.la.setText('你选择了取消!')
else:
self.la.setText('你选择了不保存!')
def critical(self):
# reply = QMessageBox.critical(self,'错误','这是一个错误消息对话框', QMessageBox.Retry | QMessageBox.Abort | QMessageBox.Ignore , QMessageBox.Retry)
msgBox = QMessageBox()
msgBox.setWindowTitle('错误')
msgBox.setIcon(QMessageBox.Critical)
msgBox.setText("这是一个错误消息对话框")
msgBox.setStandardButtons(QMessageBox.Retry | QMessageBox.Abort | QMessageBox.Ignore)
msgBox.setDefaultButton(QMessageBox.Retry)
msgBox.setDetailedText('这是详细的信息:学点编程吧,我爱你!')
reply = msgBox.exec()
if reply == QMessageBox.Retry:
self.la.setText('你选择了Retry!')
elif reply == QMessageBox.Abort:
self.la.setText('你选择了Abort!')
else:
self.la.setText('你选择了Ignore!')
def about(self):
#QMessageBox.about(self,'关于','这是一个关于消息对话框!')
msgBox = QMessageBox(QMessageBox.NoIcon, '关于','不要意淫了,早点洗洗睡吧!')
msgBox.setIconPixmap(QPixmap("beauty.png"))
msgBox.exec()
def aboutqt(self):
QMessageBox.aboutQt(self,'关于Qt')
def check(self):
if self.sender().isChecked():
self.la.setText('你打勾了哦')
else:
self.la.setText('怎么又不打了啊')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

从几个槽函数来开始介绍五种消息对话框,至于界面定义、信号与槽函数调用属于以前的知识点,这里不再重复。

1
2
3
4
5
6
def info(self):
reply = QMessageBox.information(self,'提示','这是一个消息提示对话框!',QMessageBox.Ok | QMessageBox.Close, QMessageBox.Close)
if reply == QMessageBox.Ok:
self.la.setText('你选择了Ok!')
else:
self.la.setText('你选择了Close!')

这里描述了一个信息提示的对话框。它的函数调用格式如下:

1
QMessageBox.information(QWidget, str, str, buttons: Union[QMessageBox.StandardButtons, QMessageBox.StandardButton] = QMessageBox.Ok, defaultButton: QMessageBox.StandardButton = MessageBox.NoButton)

打开包含指定父窗口小部件并给定了标题和文本的信息消息对话框。这句话分别对应了第一、二、三个参数。第四个参数则是我们要在消息对话框上想要显示的按钮。第五个参数defaultButton指定按Enter键时使用的按钮。如果defaultButton是QMessageBox.NoButton,QMessageBox会自动选择合适的默认值(即为默认的按钮选项)。

当然还有更多的按钮参数可以供我们选择,可查看官网。这个函数中显示的按钮分别是Ok、Close,默认按钮是Close(即为默认的按钮焦点选项)。

1
2
3
4
if reply == QMessageBox.Ok:
self.la.setText('你选择了Ok!')
else:
self.la.setText('你选择了Close!')

标签上的信息会根据我们选择的按钮信息相应的变化,判断是选择了OK还是Close。

1
2
3
4
5
6
7
8
def question(self):
reply = QMessageBox.question(self,'询问','这是一个询问消息对话框,默认是No', QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, QMessageBox.No)
if reply == QMessageBox.Yes:
self.la.setText('你选择了Yes!')
elif reply == QMessageBox.No:
self.la.setText('你选择了No!')
else:
self.la.setText('你选择了Cancel!')

这个函数与上一个函数的内容差不多,唯一不同的地方是,产生的消息对话框带了一个“?”。

两种产生消息对话框的方式,一是调用静态函数的方式(即为直接调用现成的函数如QMessageBox.warning之类的函数),二则是基于属性的调用(即为自定义静态函数,并且槽函数均为自定义编写)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def warning(self):
# reply = QMessageBox.warning(self,'警告','这是一个警告消息对话框', QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, QMessageBox.Save)
cb = QCheckBox('所有文档都按此操作')
msgBox = QMessageBox()
msgBox.setWindowTitle('警告')
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText('这是一个警告消息对话框')
msgBox.setInformativeText('出现更改愿意保存吗?')
Save = msgBox.addButton('保存', QMessageBox.AcceptRole)
NoSave = msgBox.addButton('取消', QMessageBox.RejectRole)
Cancel = msgBox.addButton('不保存', QMessageBox.DestructiveRole)
msgBox.setDefaultButton(Save)
msgBox.setCheckBox(cb)
cb.stateChanged.connect(self.check)
reply = msgBox.exec()
if reply == QMessageBox.AcceptRole:
self.la.setText('你选择了保存!')
elif reply == QMessageBox.RejectRole:
self.la.setText('你选择了取消!')
else:
self.la.setText('你选择了不保存!')

这个函数分别使用了基于属性和静态函数的方式产生消息对话框,当然实际使用时需要注释一种。

1
cb = QCheckBox('所有文档都按此操作')

因为要在对话框中增加一个复选框(打勾的框框),所以新建了一个复选框对象,复选框的内容就是“所有文档都按此操作”。

1
2
3
4
msgBox.setWindowTitle('警告')
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText('这是一个警告消息对话框')
msgBox.setInformativeText('出现更改愿意保存吗?')

这四个语句分别有如下表示:

  • 设置消息对话框的标题:警告。

  • 设置消息对话框的图标:QMessageBox.Warning,也就是警告图标,当然也可以选择QMessageBox.InformationQMessageBox.QuestionQMessageBox.Critical(静态函数)。

  • 设置消息对话框的要显示的消息框文本,如果文本格式设置(QMessageBox.textFormat),文本将被解释为纯文本或富文本。 默认设置为Qt.AutoText,即消息框将尝试自动检测文本的格式。

  • 设置消息对话框更完整描述的信息性文本,可以使用Infromative文本来扩展text()以向用户提供更多信息。 在Mac上,此文本以text()下方的小系统字体显示。 在其他平台上,它只是附加到现有文本。

1
2
3
4
Save = msgBox.addButton('保存', QMessageBox.AcceptRole)
NoSave = msgBox.addButton('取消', QMessageBox.RejectRole)
Cancel = msgBox.addButton('不保存', QMessageBox.DestructiveRole)
msgBox.setDefaultButton(Save)

这里实际上是新建了三个按钮,当然是中文的,每个对应着一种事件的角色,是接受、拒绝还是放弃。最后设置了默认的按钮是保存。即焦点是在这个按钮上。

1
2
msgBox.setCheckBox(cb)
cb.stateChanged.connect(self.check)

需要在消息对话框上设置之前建立的那个复选框。当选择这个复选框的时候产生了stateChanged信号,对应的将连接check()这个槽函数。

1
reply = msgBox.exec()

这行这个语句让消息对话框能够显示出来,并将选中的按钮返回给reply这个变量。

1
2
3
4
5
6
if reply == QMessageBox.AcceptRole:
self.la.setText('你选择了保存!')
elif reply == QMessageBox.RejectRole:
self.la.setText('你选择了取消!')
else:
self.la.setText('你选择了不保存!')

当选择不同的按钮时候,则在标签上有不同的显示。

  • AcceptRole表示点击按钮可以接受对话框;

  • RejectRole表示单击该按钮将导致对话框被拒绝;

  • DestructiveRole表示单击该按钮将导致破坏性更改(例如“丢弃更改”)并关闭对话框。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def check(self):
if self.sender().isChecked():
self.la.setText('你打勾了哦')
else:
self.la.setText('怎么又不打了啊')
```
`self.sender()`就是传递信号过来的对象,这里就是复选框;`isChecked()`返回的是一个布尔值,也就是判断是否被选中,选中了就显示打勾,否则就是不打勾。
```python
def critical(self):
# reply = QMessageBox.critical(self,'错误','这是一个错误消息对话框', QMessageBox.Retry | QMessageBox.Abort | QMessageBox.Ignore , QMessageBox.Retry)
msgBox = QMessageBox()
msgBox.setWindowTitle('错误')
msgBox.setIcon(QMessageBox.Critical)
msgBox.setText("这是一个错误消息对话框")
msgBox.setStandardButtons(QMessageBox.Retry | QMessageBox.Abort | QMessageBox.Ignore)
msgBox.setDefaultButton(QMessageBox.Retry)
msgBox.setDetailedText('这是详细的信息:学点编程吧,我爱你!')
reply = msgBox.exec()
if reply == QMessageBox.Retry:
self.la.setText('你选择了Retry!')
elif reply == QMessageBox.Abort:
self.la.setText('你选择了Abort!')
else:
self.la.setText('你选择了Ignore!')

这个函数大部分的使用和上面的差不多。

1
msgBox.setStandardButtons(QMessageBox.Retry | QMessageBox.Abort | QMessageBox.Ignore)

表明消息对话框中使用哪些标准按钮。

1
msgBox.setDetailedText('这是详细的信息:学点编程吧,我爱你!')

该属性保存要在详细信息区域中显示的文本。文本将被解释为纯文本。默认情况下,此属性包含一个空字符串。只有设置了这个属性,ShowDetails这个按钮才会出来,点击此按钮会呈现设定好的文本内容。

1
2
3
4
5
def about(self):
#QMessageBox.about(self,'关于','这是一个关于消息对话框!')
msgBox = QMessageBox(QMessageBox.NoIcon, '关于','不要意淫了,早点洗洗睡吧!')
msgBox.setIconPixmap(QPixmap("beauty.png"))
msgBox.exec()

这里用了两种方式建立关于消息对话框,重点说明第二种,即基于属性的。建立了QMessageBox对象,一开始的时候就将标题还有要显示的内容带入了,同时还表明这是一个没有图标的消息对话框。然后对图标进行了设计,使用setIconPixmap()函数,注意参数必须是QPixmap类型的(用于呈现图片管用)。

1
2
3
4
5
6
from PyQt5.QtGui import QPixmap
def aboutqt(self):
QMessageBox.aboutQt(self,'关于Qt')

这里将调用关于Qt的对话框。

组合框使用QComboBox

由于时间问题直接贴上学习的地址以观后效之用:PyQt5系列教程(45):QComboBox的使用

其中的新颖用法以及常用的函数:

1
combox.addItem(QIcon("./res/latin_b.png"),'这个选项有图标哦')

combox.addItemQIcon的结合使用,下方会显示出来带图标的文字。

1
self.label3.setText(combox.currentText())

将label3的文本设置为当前选项的值。currentText()属性保存当前文本。如果下拉框是可编辑的,则当前文本是下拉框中显示的值。否则,如果下拉框为空或未设置当前项目,则为当前项目的值或空字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
combox.activated[str].connect(self.zhuangB)
def zhuangB(self, text):
self.label3.setText(text)
if text == "我要开始装B了":
msgBox = QMessageBox(QMessageBox.NoIcon, '装B',"让你装B")
msgBox.setIconPixmap(QPixmap("./res/zhuangB.png"))
msgBox.setWindowIcon(QIcon("./res/latin_b.png"))
msgBox.exec()
```
我们选择下拉框下面的项目时发出`activated信号`,这个信号会把选中的值(字符串)传递给槽函数zhuangB()。`activated()`信号在用户选择下拉框中的项目时发送。请注意,即使选择没有改变,也会发送此信号。除了可以传字符串以外,还可以传项目的索引。如:
```python
combox.activated[int].connect(self.zhuangB)

密码输入框:QEvent、 QRegExp、 QKeyEvent、QKeySequence、 QRegExpValidator

实现了三种密码输入框的方式来进行说明:

  • 输入的密码不可见;
  • 输入的密码可见,但是鼠标点击其他控件后,密码不可见;
  • 输入的密码不可见,同时为了更加的安全,屏蔽了鼠标右键、禁用复制、粘贴快捷键、鼠标在密码框中不可移动,不可全选。就类似在输入QQ密码的时候一样。

文本输入栏QLineEdit

QLineEdit小部件是一个单行文本编辑器。行编辑允许用户使用一组有用的编辑功能输入和编辑纯文本行,包括撤消和重做,剪切和粘贴以及拖放。通过更改行编辑的echoMode(),还可以将其用作“只写”字段,以输入密码等输入。文本的长度可以限制为maxLength()。文本可以使用validator()inputMask()或两者来任意约束。在同一行编辑中在验证器和输入掩码之间切换时,最好清除验证器或输入掩码以防止未定义的行为。相关的类是QTextEdit,它允许多行,富文本编辑。可以使用setText()insert()来更改文本。文本用text()检索;显示的文本(可参阅EchoMode)使用displayText()检索。可以使用setSelection()selectAll()选择文本,并且可以使用cut()copy()paste()。文本可以与setAlignment()对齐。

纯文本输入框QPlainTextEdit

WYSIWYG(所见即所得)查看器/编辑器QTextEdit

QTextEdit类提供了一个用于编辑和显示纯文本和富文本的小部件。QTextEdit是一款先进的WYSIWYG查看器/编辑器,支持使用HTML样式标签的丰富文本格式。它经过优化处理大型文档并对用户输入做出快速响应。QTextEdit适用于段落和字符。段落是一个格式化的字符串,它被字符包装以适应窗口小部件的宽度。默认情况下,当阅读纯文本时,一个换行符表示一个段落。文档由零个或多个段落组成。该段中的文字按照该段的对齐方式进行调整。段落以硬换行符分隔。段落中的每个字符都有其自己的属性,例如字体和颜色。QTextEdit可以显示图像,列表和表格。如果文本太大而无法在文本编辑的视口中查看,则会出现滚动条。文本编辑可以加载纯文本和富文本文件。富文本使用HTML 4标记的子集进行描述,在文本小部件中使用HTML标记。小部件自动检测HTML标记并相应地显示丰富的文本。 例如,使用字符串”<b>Hello </ b> <i>xdbcb8!</ i>”设置标签的文本属性将导致标签显示如下所示的文本:Helloxdbcb8!
如果只需要显示一小段富文本,请使用QLabel。Qt中丰富的文本支持旨在为应用程序添加合理的在线帮助功能提供快速,便携和高效的方式,并为富文本编辑器提供基础。如果发现HTML支持不足以满足需求,可以考虑使用Qt WebKit,它提供了一个全功能的Web浏览器小部件。QTextEdit上鼠标光标的形状默认为Qt.IBeamCursor。它可以通过viewport()的游标属性进行更改。QTextEdit可以显示一个大的HTML子集,包括表格和图像。使用setHtml()设置或替换文本,删除任何现有文本并将其替换为在setHtml()调用中传递的文本。如果使用传统HTML调用setHtml(),然后调用toHtml(),则返回的文本可能具有不同的标记,但呈现相同。整个文本可以用clear()删除。可以使用QTextCursor类或使用函数insertHtml()insertPlainText()append()paste()来插入文本本身。 QTextCursor还能够将表格或列表等复杂对象插入到文档中,并处理创建选择和对选定文本应用更改。setLineWrapMode()函数用于指定想要的换行类型,或者如果不想要换行,则使用NoWrap。调用setLineWrapMode()以设置固定像素宽度FixedPixelWidth或字符列(例如80列)FixedColumnWidth,并使用setLineWrapColumnOrWidth()指定像素或列。如果使用WrapgetWidth WidgetWidth的自动换行,则可以使用setWordWrapMode()指定是否在空白处或任何地方断开。find()函数可用于查找和选择文本中的给定字符串。如果想限制QTextEdit中段落的总数,例如在日志查看器中它通常很有用,那么可以使用QTextDocumentmaximumBlockCount属性。

QTimer类、多线程QThread类、进度条QProgressBar类、QThreadPool、QRunnable

QTimer类提供重复和单次定时器。QTimer类为定时器提供高级编程接口。要使用它,先创建一个QTimer,将其timeout()信号连接到相应的插槽,然后调用start()。从那时起,它将以恒定的间隔发出timeout()信号。

QTimer的替代品和QThread类、进度条QProgressBar的相关知识的更多内容可参考:

QRunnable是所有runnable对象的基类,而QThreadPool类用于管理QThreads集合。QRunnable类是一个接口,用于表示一个任务或要执行的代码,需要重新实现run()函数。QThreadPool管理和循环使用单独的QThread对象,以帮助程序减少创建线程的成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()访问。

Qt有两种多线程的方法,其中一种是继承QThreadrun函数,另外一种是把一个继承于QObject的类转移到一个Thread里。Qt4.8之前都是使用继承QThreadrun这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。两种方法区别不大,用起来都比较方便,但继承QObject的方法更加灵活。这里要记录的是如何正确的创建一个线程,特别是如何正确的退出一个线程。

QSettings

QSettings 类提供平台无关的持久化应用程序设置。

用户通常期待应用程序在不同会话中保留其设置(窗口大小和位置、设置项等等)。这些信息在 Windows 上经常存储在注册表中,在 Mac OS X 和 iOS 上则保存在 plist 文件中。在 Unix 系统上,由于缺少标准,许多应用程序(包括 KDE 程序)使用 INI 文本文件(来存储设置)。

QSettings 是围绕这些技术提供的一个抽象层,让你使用一种可移植的方式来存储和恢复应用程序设置。它同时支持自定义存储格式。

来源(好文):PyQt5 使用 QSettings

事件、信号槽简要解释

GUI应用程序是事件驱动的。事件主要由应用程序的用户生成。但它们也可以通过其他手段产生,例如:网络连接,窗口管理器或定时器。当我们调用应用程序的exec_()方法时,应用程序进入主循环。主循环获取事件并将其发送到对象。

在事件模型中,有三个参与者:

  • 事件来源
  • 事件对象
  • 事件目标

事件源是其状态更改的对象。它会生成事件。事件对象(event)将状态更改封装在事件源中。事件目标是要通知的对象。事件源对象将处理事件的任务委托给事件目标。

PyQt5具有独特的信号和插槽机制来处理事件。信号和槽用于对象之间的通信。发生特定事件时发出信号。槽可以是任何Python可调用的函数。当发射连接的信号时会调用一个槽,槽是对信号作出反应的方法。

Python调用自定义槽函数的疑惑

1
2
3
4
5
6
7
8
9
10
11
12
13
class():
''''''
''''''
self.Start_Button.clicked.connect(self.Sele_Format)
self.show()
def Clear_URL_Result(self):
"""
清空URL列表以及结果显示处
"""
self.YouTube_URL_Line.setText("")
self.result.setText("")

规范调用槽函数:即在面向对象之内的self其实只是Python面向对象的基础知识…

参考来源

  • 以上知识参考来源:《Python学习手册》Mark Lutz著

基本上的Python疑惑知识点均来自此书籍,一本很好的参考学习书籍,赞~

基本上上面关于PyQT5的知识点均来自于此,感谢作者的付出,学习了很多~直接放上作者的代码未经修改是为了方便以后参考之用。

---------------本文终---------------

文章作者:刘俊

最后更新:2019年04月19日 - 21:04

许可协议: 转载请保留原文链接及作者。