pyqt 初步尝试

写程序难免要面对将自己的程序给其他人使用的场景,这时就需要给自己的程序加上一个界面。 QT 就是一个很好的 GUI 库,而 pyqt 就是 qt 在 python 上的实现。

最近利用 pyqt 写了一个带界面的小程序,在此总结一下 pyqt 的一些操作。相关操作是在 Anaconda 环境下的 Python3 版本下实现的

环境配置

pyqt5 的安装

在这里直接 pip3 install pyqt5 就行了

pycharm 内相关工具配置

pycharm 内需要配置的工具有两个,一个是 QtDesigner ,用来制作图形界面;另一个是 PyUic 用来将 QtDesigner 生成的 UI 文件转化为 .py 格式的文件。

先来说 QtDesigner 的配置

1.首先进入 pycharm 的设置界面

2.然后再进入 tools -> External Tools

然后点击界面上的绿色加号即可进行工具的添加操作,我这是已经配置好的工具列表。接下来进行工具配置,首先来添加 QtDesigner ,详细配置如下:

其中,name 是填加工具的名称,program 是工具程序所在的地址,最后一个是工具的工作地址,也就是做好界面后 UI 文件存储的位置

接下来再看下 PyUic 的添加方法

路径配置项的意义和之前的含义都是相同的,不过具体配置内容当然是有差别的,这些可以直接参照图片里的配置,如果用 Anaconda 的话相对路径是相同的。这里主要说下 Parameters 栏,这里是输入工具运行的命令,我这里用的是$FileName$ -o $FileNameWithoutExtension$.py

界面绘制

界面绘制使用 QtDesigner 拖拽生成,QtDesigner 在 pycharm 中的打开方式如下

QtDesigner 打开创建新界面后的界面如下,界面左侧是各种控件,添加控件的方法十分简单,直接拖到窗口想要放置的地方就行了。右侧是窗体上各个控件的具体属性。

程序编写

窗口显示

编写 GUI 程序的第一步就是让窗口显示出来,这里的步骤如下

1.先将 QtDesigner 中绘制好的界面保存,不出意外的话,界面 UI 文件会保存到之前在 pycharm 中设置好的路径下,如果路径不对记得重新选择路径将文件保存到项目文件夹下,文件保存后会以 .ui 的格式存储

2.在 pycharm 下,在界面 UI 文件上右键唤出右键菜单,选择 External Tools->PyUic

然后程序将会自动执行,并将 UI 文件转化为 py 文件,执行后的结果如下,需要注意的是,在 QtDesigner 中每次改动保存后都需要将 UI 文件处理一次,否则文件不会生效

接着来看一下处理后的 py 文件长啥样

[FNQ1Y90YBVMHK3YUE_[08OH.png](https://i.loli.net/2019/04/28/5cc57488e53d1.png)

这里面都是对页面元素进行描述的语句,也就是说,整个页面的构成都是由这个文件来决定的

到这里页面设计的事情就结束了,接下来要做的就是让界面显示出来

界面显示是通过调用 UI 文件中的 setupUI 方法来实现的,而 setupUI 的参数是一个继承了 pyqt 内部类的类,所以这就需要从另外一个继承了 UI 文件的类中来调用 setupUI 方法。现在来看一下这个类的写法。

1
2
3
4
class MyWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.setupUi(self)

首先,这个类需要继承 ui 文件中的类以及窗口类型在 pyqt 库中对应的类。此外,在构造函数的参数中需要将 parent 的 默认值设为 None。然后从构造函数内调用 setupUI 方法,再将这个类实例化,最后启动程序就能将窗口显示出来了。在这还得介绍一下使用 pyqt 的程序的程序入口的写法:

1
2
3
4
5
6
7
if __name__ == '__main__':
app = QApplication(sys.argv)
# 主窗口类实例化

myWin = MyWindow()
myWin.show()
sys.exit(app.exec_())

动作响应

在 QT 中,动作的响应都是通过槽函数来完成的,每个槽函数对应着一个信号,当指定信号发出时,相应的槽函数将会被触发。一个槽函数可以对应一个或多个信号。

接下来看一下槽函数的编写,槽函数接收信号有两种情况,第一种是同一个窗口的信号传递,另一种是不同窗口的信号传递

同一个窗口内中信号传递

界面上的不同控件虽然有着不同的动作信号,但与槽函数连接的方法都是相似的。

格式为:控件名称.动作.connect(槽函数名) 。需要注意的是槽函数名称后不能加括号,因为此处只是信号与槽的连接而不是函数的调用。再来看一下完整的代码

1
2
3
4
5
6
7
8
9
class MyWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.setupUi(self)
# 连接槽函数,连接函数必须写在构造函数内
        self.pushButton.clicked.connect(self.on_button_click)
# 槽函数
     def on_button_click(self):
# 槽函数内容省略
不同窗口之间的信号传递

不同窗口之间的信号传递由于不在同一个类中所以信号传递需要一个介质,这时候就需要自定义信号来帮忙了

自定义信号 mySignal 从属于类 QtCore ,使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
from PyQt5.QtCore import pyqtSignal

class dialogWindow(QMainWindow,Ui_Dialog):
# 自定义数据要作为类标量声明,不能放在构造函数内

mySignal = pyqtSignal(dict)


def __init__(self, parent=None):
super(dialogWindow, self).__init__(parent)
self.setupUi(self)

自定义数据不仅传递信号还能传递数据,但在传递数据时必须声明数据类型,支持的数据类型有 int,float,str,list,dict 几种,可以同时传递多个参数,例如:

1
2
mySinnal = mySignal(dict)
mySignal = mySignal(int,list)

这些信号最后可以通过 emit 方法发射出去从而被另一个类接收到

自定义信号的大概用法现在是知道了,现在来说说怎样利用自定义信号将两个界面联系起来。首先我们假设现在的需求是点击按钮后将一个界面的内容发送到另一个界面,那么可以确定出以下流程

1.点击按钮触发槽函数

2.槽函数读取文本框内容并在最后运行 mySignal.emit(文本内容) 将信号发射出去

例如:

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
class dialogWindow(QMainWindow,Ui_Dialog):
# 数据类型必须声明
mySignal = pyqtSignal(dict)


def __init__(self, parent=None):
super(dialogWindow, self).__init__(parent)
self.setupUi(self)
# 接受拖拽操作

self.setAcceptDrops(True)
# 将按钮信号与槽函数连接

self.pushButton.clicked.connect(self.on_button_click)

def on_button_click(self):

point = self.textEdit_3.toPlainText()
label = self.textEdit.toPlainText()
info = self.textEdit_2.toPlainText()
img = self.textEdit_4.toPlainText()
content = {'point':point,'label':label,'info':info,'img':img}
# 发射自定义信号

self.mySignal.emit(content)

好了,现在信号已经发射出去了,接下来要处理的就是接收的问题了。

由于这里的自定义信号是子窗口类中的变量,所以没办法直接调用,要调用就得将子窗口的类实例化,可以将信号的接收函数放在主窗口调用子窗口的函数中,并将其与主窗口中相应的槽函数连接起来。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def showDialogWindow(self):
# 实例化子窗口

self.dialogWindow = dialogWindow()
# 将子窗口的信号和主窗口类中的槽函数连接起来

self.dialogWindow.mySignal.connect(self.changeData)
# 缩进有问题,调不回去,不要误会 self.dialogWindow.myDelSignal.connect(self.on_listWidget_doubleClicked)
# 阻塞主窗口

self.dialogWindow.setWindowModality(Qt.ApplicationModal)

# 槽函数,将连接中的数据取出
def changeData(self,connect):
self.dialogWindow.close()
row = self.listWidget.currentRow()
self.station1[row]=connect
self.creatList()

一些小功能

最后再来记录一下本次实践用到的一些小功能

信息框

信息框的使用需要借助QMessageBox 类,引用路径为:from PyQt5.QtWidgets import QMessageBox

信息框共有警告( warning ),提示( information ),询问( question )三类

看一个警告框的示例:

1
2
3
4
5
6
7
reply = QMessageBox.warning(self,"警告","确认删除站点:"+item.text(),QMessageBox.Yes|QMessageBox.No,QMessageBox.No)

# 根据点击的按钮进行相应操作
if reply == QMessageBox.Yes:
...
else:
...

其参数按顺序分别为1. parent(也就是类的实例,self) 2.title(信息框标题) 3.text(信息框内容) 4.button(两个按钮中间用 | 分开) 5.defaultButton(默认按钮)

关于信息框的详细信息可以参考

PyQt5基本控件详解之QMessageBox(十三)

Pyqt5让QMessageBox按钮显示中文

列表

列表中的项目需要一条条单独创建,使用语句 item = QListWidgetItem(字符串) 创建项,然后利用 additem(item) 方法将项添加到列表中,还可以利用 take(行) 方法将项目在列表中删除。此外可以利用 currentRow() 方法获取鼠标点击的项目所在的行,然后结合其他方法进行操作。

-----------本文结束感谢您的阅读-----------
0%