QTableWidget
如果我们想以表格格式查看数据库数据,PyQt5 为此提供了 QTableWidget。
QTableWidget 由单元格组成;每个单元格都是 QTableWidgetItem 类的一个实例。
让我们设计一个包含 QTableWidget 和 QPushButton 的表单。
从小部件框中拖动一个表格小部件和一个按钮。
然后保存并转换设计以使用它。
要向 QTableWidget 添加行,我们可以使用 setRowCount() 方法。
要将列添加到 QTableWidget,我们可以使用 setColumnCount() 方法。
from PyQt5 import QtWidgets from mydesign import Ui_MainWindow import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.tableWidget.setColumnCount(2) self.ui.tableWidget.setRowCount(4) app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
现在我们可以在 QTableWidget 单元格中手动输入文本。
清除 QtableWidget 内容
要清除 QTableWidget 内容,我们可以使用像这样的 clear 方法:
def clear(): self.ui.tableWidget.clear() self.ui.pushButton.clicked.connect(clear)
通过代码填充 QTableWidget
要以编程方式填充 QTableWidget,我们应该为每个 QTableWidgetItem 使用 setItem() 方法。
from PyQt5.QtWidgets import QTableWidgetItem from mydesign import * import sys data = [] data.append(('Populating', 'QtableWidget')) data.append(('With data', 'In Python')) data.append(('Is easy', 'Job')) class mywindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.tableWidget.setRowCount(3) self.ui.tableWidget.setColumnCount(2) row=0 for tup in data: col=0 for item in tup: cellinfo=QTableWidgetItem(item) self.ui.tableWidget.setItem(row, col, cellinfo) col+=1 row += 1 app = QtWidgets.QApplication([]) win = mywindow() win.show() sys.exit(app.exec())
- 首先,我们创建一个包含三个元组的 Python 列表。
- 在主窗口的构造函数中,我们设置行数和列数。
- 然后我们遍历列表并使用 setItem() 方法获取列表中的每个元组以填充表格单元格。
- 最后,我们显示主窗口。
使 QTableWidget 不可编辑(只读)
在某些情况下,我们可能不喜欢让用户可以编辑表格单元格。
就像显示只读数据一样,任何编辑过程都是没有意义的。
要使 QTableWidget 不可编辑,我们可以使用 setFlags() 方法将每个 QTableWidgetItem 设置为不可编辑。
cellinfo.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) #make it not editable
我们必须在设置单元格内容之前设置标志。
因此,代码将是这样的:
from PyQt5.QtWidgets import QTableWidgetItem from mydesign import * import sys data = [] data.append(('Populating', 'QtableWidget')) data.append(('With data', 'In Python')) data.append(('Is easy', 'Job')) class mywindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.tableWidget.setRowCount(3) self.ui.tableWidget.setColumnCount(2) row=0 for tup in data: col=0 for item in tup: cellinfo=QTableWidgetItem(item) cellinfo.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) # make cell not editable self.ui.tableWidget.setItem(row, col, cellinfo) col+=1 row += 1 app = QtWidgets.QApplication([]) win = mywindow() win.show() sys.exit(app.exec())
现在,如果我们尝试编辑任何单元格,则不能;因为 QTableWidgetItem 不可编辑。
设置 QTableWidget 列(标题)名称
到目前为止,QTableWidget 的列名都是数字。
将列名设置为其他名称怎么样。
要设置 QTableWidget 标题文本,我们可以使用 setHorizontalHeaderLabels() 方法,如下所示:
from PyQt5.QtWidgets import QTableWidgetItem from mydesign import * import sys data = [] data.append(('Populating', 'QtableWidget')) data.append(('With data', 'In Python')) data.append(('Is easy', 'Job')) class mywindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.tableWidget.setRowCount(3) self.ui.tableWidget.setColumnCount(2) self.ui.tableWidget.setHorizontalHeaderLabels(('Column 1', 'Column 2')) # set header text row=0 for tup in data: col=0 for item in tup: cellinfo=QTableWidgetItem(item) self.ui.tableWidget.setItem(row, col, cellinfo) col+=1 row += 1 app = QtWidgets.QApplication([]) win = mywindow() win.show() sys.exit(app.exec())
同样,我们可以使用 setVerticalHeaderLabels() 方法更改行标题:
self.ui.tableWidget.setVerticalHeaderLabels(('Row 1', 'Row 2', 'Row 3'))
如何对 QTableWidget 进行排序
我们可以使用 setSortingEnabled() 方法使 QTableWidget 可排序。
self.ui.tableWidget.setSortingEnabled(True)
现在,如果用户单击任何列标题,他可以按升序或者降序对数据进行排序。
我们可以在使用数据填充 QTableWidget 之前或者之后使用此方法。
仅将 QTableWidget 排序到特定列怎么样?
我们可以使用 sortByColumn() 方法并像这样设置列索引和排序顺序:
from PyQt5.QtWidgets import QTableWidgetItem from mydesign import * import sys data = [] data.append(('Populating', 'QtableWidget')) data.append(('With data', 'In Python')) data.append(('Is easy', 'Job')) class mywindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.tableWidget.setRowCount(3) self.ui.tableWidget.setColumnCount(2) row=0 for tup in data: col=0 for item in tup: cellinfo=QTableWidgetItem(item) self.ui.tableWidget.setItem(row, col, cellinfo) col+=1 row += 1 self.ui.tableWidget.sortByColumn(0, QtCore.Qt.AscendingOrder) # sort by the first column app = QtWidgets.QApplication([]) win = mywindow() win.show() sys.exit(app.exec())
此外,默认情况下,我们可以使用 sortItems() 方法按升序对 QTableWidget 进行排序。
self.ui.tableWidget.sortItems(0)
或者我们可以指定排序顺序:
self.ui.tableWidget.sortItems(0,QtCore.Qt.DescendingOrder)
请记住,如果我们想以编程方式对列进行排序,则必须在使用数据填充 QTableWidget 后使用排序方法,否则将不会对数据进行排序。
在 QTableWidget 中添加 QComboBox
我们可能需要用户在 QTableWidget 中选择一个值,而不是输入文本。
在 QTableWidgetItem 中添加一个 QComboBox 怎么样?
要在 QTableWidgetItem 中添加 QComboBox,可以使用 setCellWidget() 方法:
from PyQt5.QtWidgets import QTableWidgetItem from mydesign import * import sys data = ['PyQt5','Is','Awesome'] class mywindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.tableWidget.setRowCount(3) self.ui.tableWidget.setColumnCount(2) row=0 for item in data: cellinfo=QTableWidgetItem(item) combo = QtWidgets.QComboBox() combo.addItem("First item") combo.addItem("Second item") self.ui.tableWidget.setItem(row, 0, cellinfo) self.ui.tableWidget.setCellWidget(row, 1, combo) row += 1 app = QtWidgets.QApplication([]) win = mywindow() win.show() sys.exit(app.exec())
QLabel 小部件
要将 QLabel 小部件添加到表单,请执行以下操作:
- 打开 PyQt5 设计器并选择主窗口模板。
- 从左侧的小部件框中拖动一个标签小部件。
现在,将设计保存为 .ui 文件并将其转换为 .py 文件,然后让我们使用代码来处理标签小部件。
更改字体
要更改 QLabel 字体,请使用 setFont() 方法并将 QFont 传递给它,如下所示:
from PyQt5 import QtWidgets, QtGui from mydesign import Ui_MainWindow import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.label.setFont(QtGui.QFont('SansSerif', 30)) # change font type and size app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
如果你运行这段代码,你会注意到标签没有正确显示,因为大小小于我们使用的字体大小。
更改大小
要更改 QLabel 大小,我们需要使用 setGeometry() 方法设置其几何形状,如下所示:
from PyQt5 import QtWidgets, QtGui,QtCore from mydesign import Ui_MainWindow import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.label.setFont(QtGui.QFont('SansSerif', 30)) self.ui.label.setGeometry(QtCore.QRect(10, 10, 200, 200)) # change label geometry app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
更改文本
要更改 QLabel 文本,我们可以使用 setText() 方法,如下所示:
from PyQt5 import QtWidgets, QtGui,QtCore from mydesign import Ui_MainWindow import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.label.setFont(QtGui.QFont('SansSerif', 30)) self.ui.label.setGeometry(QtCore.QRect(10, 10, 200, 200)) self.ui.label.setText("onitroad") #change label text app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
QPushButton 小部件
大多数 Python 程序都有这个 QPushButton 小部件。
我们单击按钮,一些代码就会运行。
因此,当我们单击 QPushButton 时,会发出一个信号。
在这种情况下,信号名称称为 clicked()。
要将发出的信号与插槽绑定,我们需要使用 connect() 方法,正如我们现在将看到的。
此事件处理过程将继续工作,直到我们关闭表单或者主窗口小部件。
让我们用 QLabel 和 QPushButton 构建一个表单并将其导出到 .py 文件。
现在,我们将使用 connect() 方法将 clicked() 信号与插槽连接,如下所示:
self.ui.pushButton.clicked.connect(self.btnClicked)
这里的 btnClicked 是当我们单击 QPushButton 时将运行的插槽或者函数。
所以你的代码会是这样的:
from PyQt5 import QtWidgets from mydesign import Ui_MainWindow import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.pushButton.clicked.connect(self.btnClicked) # connecting the clicked signal with btnClicked slot def btnClicked(self): self.ui.label.setText("Button Clicked") app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
安装 PyQt5
PyQt5 有两个版本,我们将在本教程中使用的商业版本和免费 GPL 版本。
要安装 PyQt5,我们有两种方法:
- 使用pip
- 使用源代码
使用pip
要使用 pip 安装 PyQt5,请运行以下命令:
$ pip3 install PyQt5
为确保安装成功,请运行以下 Python 代码:
import PyQt5
在 Linux 上使用源代码安装PyQt5
要从源代码安装 PyQt5,我们必须执行以下操作:
- 安装 SIP。
- 下载 PyQt5 源代码。
- 配置和安装。
我们可能知道,PyQt5 是用 C++ 编写的著名库 Qt 的 Python 绑定。
进行此绑定的工具称为 SIP。
因此,要从源代码安装 PyQt5,我们首先需要安装 SIP。
要安装 SIP,请运行以下命令:
$ pip3 install PyQt5-sip
从这里下载 PyQt5 源代码。
https://www.riverbankcomputing.com/software/pyqt/download5
然后解压压缩的源代码并在未压缩文件夹的根目录中运行以下命令:
$ python3 configure.py $ make $ make install
在 Windows 上使用源代码安装PyQt5
由于SIP需要GCC编译器,所以需要安装MinGW,它是Linux GCC编译器的Windows端口。
我们唯一需要更改的是配置步骤;你需要告诉 Python 平台:
$ python configure.py --platform win32-g++ $ make $ make install
加载 .ui VS 将 .ui 转换为 .py
在本教程中,我们将使用 PyQt5 设计器,但在深入dig之前,让我们看看如何使用 PyQt5 设计器生成的设计。
打开 PyQt5 设计器,选择 Main Window template 并点击 create 按钮。
然后从文件菜单中,单击保存; PyQt5 设计器会将表单导出为扩展名为 .ui 的 XML 文件。
现在,要使用此设计,我们有两种方法:
- 在 Python 代码中加载 .ui 文件。
- 使用 pyuic5 将 .ui 文件转换为 .py 文件。
在 Python 代码中加载 .ui 文件
要在 Python 代码中加载 .ui 文件,我们可以使用 uic 中的 loadUI() 函数,如下所示:
from PyQt5 import QtWidgets, uic import sys app = QtWidgets.QApplication([]) win = uic.loadUi("mydesign.ui") #specify the location of your .ui file win.show() sys.exit(app.exec())
如果你运行代码,你应该会看到一个只有一个标签的窗口。
这意味着ui文件加载成功!
我们使用 sys.exit(app.exec()) 而不是直接使用 app.exec() 将正确的状态代码发送到父进程或者调用进程。
如果直接使用 app.exec() ,应用程序将发送零,这意味着成功,即使应用程序崩溃也会发生这种情况。
使用 pyuic5 将 .ui 文件转换为 .py 文件
现在,让我们尝试第二种方式,将 .ui 文件转换为 Python 代码:
$ pyuic5 mydesign.ui -o mydesign.py
这将创建一个名为 mydesign.py 的新文件。
现在,让我们导入该文件以显示我们的窗口。
pyuic5 代表 Python 用户界面转换器版本 5.
from PyQt5 import QtWidgets from mydesign import Ui_MainWindow # importing our generated file import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
如果我们运行此代码,我们应该会再次看到与我们在第一种方法中所做的相同的窗口。
使用第二种方法的好处是 IDE 将提供自动完成,因为所有小部件都已导入,而第一种方法我们只需加载 .ui 文件,并且我们需要知道小部件名称。
使用第二种方法的另一个好处是速度,因为我们不需要解析 XML 来加载 UI。
QLineEdit 小部件
QLineEdit 是一个可编辑的地方,我们可以其中接受来自用户的输入。
LineEdit 有很多方法可以使用。
我将使用 PyQt5 设计器创建一个新设计,并添加六个 QLineEdit 小部件,并将其导出为 .py 文件。
现在,让我们看看一些 QLineEdit 方法:
from PyQt5 import QtWidgets,QtCore from mydesign import Ui_MainWindow import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.lineEdit.setText("Welcome to onitroad website") #change text self.ui.lineEdit_2.setMaxLength(10) #set maximum length self.ui.lineEdit_3.setEchoMode(QtWidgets.QLineEdit.Password) # password input self.ui.lineEdit_4.setReadOnly(True) #QLineEdit readonly self.ui.lineEdit_5.setStyleSheet("color: rgb(28, 43, 255);") #change text color self.ui.lineEdit_6.setStyleSheet("background-color: rgb(28, 43, 255);") #change QLineEdit background color app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
第一个 QlineEdit,我们使用 setText() 方法更改了文本。
第二个QlineEdit,我们将允许的最大字符数设置为10,因此不再接受。
第三个 QlineEdit,我们将其设置为密码模式,因此所有输入都显示为星号。
第四个 QlineEdit,我们将其设置为只读,因此我们无法编辑其内容。
第五个QlineEdit,我们使用setStyleSheet()方法改变了字体颜色,我们插入了像网页CSS值一样的颜色。
第六个 QlineEdit,我们使用 setStyleSheet() 方法更改了背景颜色。
setStyleSheet() 方法
我们可以对所有 PyQt5 小部件使用 setStyleSheet() 方法来更改样式。
我们可以使用 setStyleSheet() 方法更改以下内容:
- 字体类型和大小
- 文字颜色
- 背景颜色
- 边框颜色
- 边框顶部颜色
- 边框底色
- 边框右侧颜色
- 边框左颜色
- 选择颜色
- 选择背景颜色
QDialog、QMainWindow 和 QWidget 的区别
- QWidget 是 PyQt5 中所有 GUI 元素的基类。
- QDialog 用于向用户询问某事,例如询问用户接受或者拒绝某事或者可能要求输入,并且基于 QWidget。
- QMainWindow 是更大的模板,我们可以其中放置工具列、菜单列、状态列和其他小部件。它没有像 QDialog 中的按钮那样的内置允许。
打包 Python 文件(转换为可执行文件)
我们可以使用许多工具将 Python 程序转换为二进制可执行文件。
对我来说,我将使用 pyinstaller,它能够将 Python 代码打包或者冻结为 Windows、Linux、Mac OS X、FreeBSD 和 Solaris 下的可执行文件。
所有这一切都完全支持 32,64 位架构。
pyinstaller 最好的部分是对 PyQt5 的完全支持。
首先,安装pyinstaller:
$ pip3 install pyinstaller
安装后,我们可以像这样转换 Python 程序:
$ pyinstaller test.py
这将在 Python 程序目录的 dist 文件夹中生成可执行文件。
正如我们将要看到的,在可执行文件旁边生成了许多依赖项。
我们可以使用一种文件模式生成一个可执行文件,如下所示:
$ pyinstaller --onefile test.py
每次运行可执行文件时都会出现一个控制台窗口。
我们可以使用 -w 或者 -noconsole 来隐藏控制台窗口:
$ pyinstaller -w test.py
此选项仅适用于 Windows 和 Mac OS X。
Pyinstaller 提供了很多选项来打包应用程序,要列出所有选项,请使用 -help:
$ pyinstaller --help
如何发出信号
我们看到了信号和槽是如何工作的。
我们使用的所有信号都是为我们预定义的。
发射我们的自定义信号怎么样?
好简单!我们可以通过使用 pyqtSignal 类来做到这一点,如下所示:
- 使用 pyqtSignal 类型定义事件。
- 在我们希望触发事件的位置调用 emit() 方法。
假设我们有一个 nut 类,我们想在破解它时发出破解信号。
from PyQt5.QtCore import pyqtSignal,QObject class nut(QObject): cracked = pyqtSignal() def __init__(self): QObject.__init__(self) def crack(self): self.cracked.emit()
如何使用信号
现在,让我们通过实例化 nut 类的实例并发出破解信号来使我们的示例更加实用:
def crackit(): print("hazelnut cracked!") hazelnut = nut() hazelnut.cracked.connect(crackit) # connecting the cracked signal with crackit slot hazelnut.crack()
破解信号成功发出。
信号(事件)覆盖
有时,我们需要覆盖特定信号或者事件的默认行为。
让我们看一个实际的例子。
如果我们想在用户按下特定键时关闭主窗口,我们可以像这样覆盖主窗口中的 keyPressEvent:
def keyPressEvent(self, e): if e.key() == Qt.Key_F12: self.close()
现在,如果用户按下 F12 键,主窗口将关闭。
这里我们覆盖主窗口的按键信号并关闭窗口。
视觉信号/插槽编辑器
我们看到了如何使用 connect() 方法将小部件信号连接到插槽,但这不是唯一的方法。
每个小部件都有一些预定义的插槽。
我们可以将信号连接到任何预定义的插槽,而无需在 PyQt5 设计器中进行编码。
在表单上拖动 QPushButton 和 QLineEdit。
按 F4 并从 QPushButton 拖动鼠标并在 QLineEdit 顶部释放它。
信号/插槽编辑器将出现。
左侧是预定义信号,右侧是预定义时隙。
假设我们要将 clicked() 信号与 clear slot 连接起来。
从左边选择clicked,从右边选择clear,然后单击OK。
完成信号/插槽连接后,我们可以按 ESC 或者 F3 退出此模式。
现在,如果我们运行此表单并单击 QPushButton,QLineEdit 上的任何文本都将被清除。
我们可以从信号/槽编辑器面板编辑或者删除此连接。
安装 PyQt5 设计器
有两种使用 PyQt5 构建 GUI 应用程序的方法:
- 通过代码设计小部件。
- 使用 PyQt5 设计器。
在本 PyQt5 教程中,我们将使用 PyQt5 设计器,它可以在几秒钟内轻松完成大量工作。
PyQt5 设计器带有 PyQt5 工具。
要安装它,我们需要安装 PyQt5 工具。
$ pip3 install PyQt5-tools
PyQt5 设计器安装在哪里了?
安装成功后,可以在这个位置找到PyQt5设计器:
C:\Program Files\Python36\Lib\site-packages\pyqt5-tools\
此外,如果我们仅为当前用户安装了 Python,我们将在此位置找到 PyQt5 设计器:
C:\Users\onitroad\AppData\Local\Programs\Python\Python36-32\Lib\site-packages\ pyqt5-tools\
我们可以为它创建一个快捷方式,而不是每次要运行 PyQt5 设计器时都进入这个位置。
QComboBox 小部件
我们可以使用 QCombobBox 小部件为用户提供可供选择的选项列表,而不是让用户在 QLineEdit 或者任何可编辑小部件中输入值。
让我们将一个组合框拖到我们的表单中,看看它的一些方法。
如果我们现在运行该应用程序,我们会注意到 QComboBox 是空的。
要将项目添加到 QComboBox,请使用 addItem() 方法:
from PyQt5 import QtWidgets from mydesign import Ui_MainWindow import sys class mywindow(QtWidgets.QMainWindow): def __init__(self): super(mywindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.comboBox.addItem("First item") #add item self.ui.comboBox.addItem("Second item") app = QtWidgets.QApplication([]) application = mywindow() application.show() sys.exit(app.exec())
获取所有项
没有从 QComboBox 获取所有项目的直接方法,但我们可以使用 for 循环来做到这一点。
for i in range(self.ui.comboBox.count()): print(self.ui.comboBox.itemText(i))
选择一个项目
要从 QComboBox 中选择一个项目,我们有两种方法:
self.ui.comboBox.setCurrentIndex(1) #select by index which is zero-based self.ui.comboBox.setCurrentText("Second item") #select by text
请注意,通过文本选择项目时,请确保我们编写正确的文本,否则。
QComboBox 将停留在第一个元素。
PyQt5 是在 Python 中构建 GUI 应用程序中最常用的模块之一,因为它很简单。
还有一个强大的PyQt5 设计器,它可以在短时间内轻松开发复杂的 GUI 应用程序。
如何使用 PyQt5 设计器
打开designer.exe,我们将看到一个对话框,询问我们想要的表单模板。
有五个模板可用:
- 底部带有按钮的对话框:创建一个表单,在表单的右下方带有 OK 和 Cancel 按钮。
- 带有右侧按钮的对话框:创建一个表单,在表单的右上角带有 OK 和 Cancel 按钮。
- 没有按钮的对话框:创建一个空白表单。
- 主窗口:创建一个带有菜单列和工具列的窗口,继承自 QMainWindow。
- Widget:创建一个从 QWidget 类继承的小部件,与从 QDialog 类继承的 Dialogs 模板不同。
那么三种模板,有什么区别呢?