建筑项目 可以说是更平易近人、更有效的编程学习方法之一。真实的项目要求您应用不同的编码技能。他们还鼓励您研究在解决开发过程中出现的问题时出现的主题。在本教程中,您将使用 Python、PyQt 和 SQLite 创建一个通讯录应用程序。
在本教程中,您将学习如何:
创建一个图形用户界面 (GUI) 使用 Python 和 PyQt 的通讯录应用程序
将应用程序连接到SQLite数据库 使用PyQt 的 SQL 支持
使用管理联系人数据PyQt 的模型视图架构
在本项目结束时,您将拥有一个功能齐全的通讯录应用程序,可让您存储和管理您的联系信息。
要获取应用程序的完整源代码以及您将在本教程中完成的每个步骤的代码,请单击下面的链接:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
通讯录是一种有用且广泛使用的应用程序。他们无处不在。您的手机和计算机上可能有一本通讯录。通过通讯录,您可以存储和管理家人、朋友、同事等的联系信息。
在本教程中,您将使用 Python 编写通讯录 GUI 应用程序,SQLite , 和pyqt 。以下是您按照本教程中的步骤操作后通讯录的外观和工作方式的演示:
您的通讯录将提供此类应用程序所需的最少功能集。您将能够显示、创建、更新和删除联系人列表中的信息。
项目概况
要构建通讯录应用程序,您需要将代码组织到模块和包中,并为您的项目提供连贯的结构。在本教程中,您将使用以下目录和文件结构:
rpcontacts_project/
│
├── rpcontacts/
│ ├── __init__.py
│ ├── views.py
│ ├── database.py
│ ├── main.py
│ └── model.py
│
├── requirements.txt
├── README.md
└── rpcontacts.py
以下是项目目录内容的简要摘要:
rpcontacts_project/
is the project’s root directory. It’ll contain the following files:
requirements.txt
提供项目的需求列表。
README.md
提供有关该项目的一般信息。
rpcontacts.py
提供运行应用程序的入口点脚本。
rpcontacts/
is a subdirectory that provides the application’s main package. It provides the following modules:
__init__.py
views.py
database.py
main.py
model.py
您将在本教程中逐步介绍每个文件。每个文件的名称表明了它在应用程序中的作用。例如,views.py
将包含生成窗口和对话框的 GUI 的代码,database.py
将包含使用数据库的代码,并且main.py
将托管应用程序本身。最后,model.py
将实现模型来管理应用程序数据库中的数据。
一般来说,应用程序会有一个主窗口来显示、添加、删除和更新联系人。它还将有一个对话框用于将新联系人添加到数据库中。
先决条件
为了充分利用这个项目,之前使用 Python 和 PyQt 进行 GUI 编程的一些知识将会有所帮助。在这方面,您需要了解如何执行以下操作的基础知识:
使用 PyQt 和 Python 创建 GUI 应用程序
使用 PyQt 构建和布局 GUI
使用 Python 和 PyQt 管理 SQL 数据库
与 一起工作SQLite 数据库
要温习这些主题,您可以查看以下资源:
Python 和 PyQt:构建 GUI 桌面计算器
Python 和 PyQt:创建菜单、工具栏和状态栏
PyQt 布局:创建具有专业外观的 GUI 应用程序
使用 PyQt 处理 SQL 数据库:基础知识
Python SQL 库简介
使用 Python、SQLite 和 SQLAlchemy 进行数据管理
在开始本教程之前,如果您不是这些领域的专家,请不要担心。您将通过亲身参与实际项目的过程来学习。如果您遇到困难,请花点时间查看上面链接的资源。然后回到代码。
您将在本教程中构建的通讯录应用程序有一个外部依赖项:PyQt。
笔记: 在本教程中,您将使用 PyQt 版本 5.15.2 构建通讯录应用程序。该项目需要版本 5.15.2 才能在 macOS Big Sur 上运行。
PyQt 版本 6.0 于 2021 年 1 月 4 日发布。这是绑定到的库的第一个版本Qt版本6 。但是,本教程中的项目尚未使用 PyQt 6.0 进行测试。
如果您觉得需要使用这个新版本的 PyQt 来运行项目,那么请尝试一下。作为提示,您应该pip install PyQt6
然后更新要使用的导入PyQt6
代替PyQt5
.
要在开发过程中遵循最佳实践,您可以首先创建一个虚拟环境 进而安装 PyQt 使用pip 。安装 PyQt 后,您就可以开始编码了!
在第一步中,您将创建一个最小但功能齐全的 PyQt GUI 应用程序,为您开始构建通讯录提供基础。您还将创建所需的最小项目结构,包括项目的主包和运行应用程序的入口点脚本。
您将在本节中添加到通讯录项目的所有代码和文件都收集在source_code_step_1/
目录。您可以点击下面的链接下载它们:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
在本节结束时,您将能够首次运行通讯录的框架 GUI 应用程序。
要开始编写应用程序,请继续创建一个名为的新目录rpcontacts_project/
。这将是项目的根目录。现在创建一个名为的新子目录rpcontacts/
里面rpcontacts_project/
。该子目录将保存应用程序的主目录包裹 。最后,点燃你的代码编辑器或IDE 根目录内。
要将目录转换为包,Python 需要一个__init__.py
模块来初始化包。内创建此文件rpcontacts/
并向其中添加以下代码:
# -*- coding: utf-8 -*-
"""This module provides the rpcontacts package."""
__version__ = "0.1.0"
这个文件告诉Pythonrpcontacts
是一个包。当您导入包或其某些模块时,文件中的代码就会运行。
您不需要将任何代码放入__init__.py
文件来初始化包。一个空的__init__.py
文件将完成这项工作。但是,在这种情况下,您定义了一个名为的模块级常量__version__
保存应用程序的版本号。
创建应用程序的主窗口
现在是时候创建通讯录的主窗口了。为此,创建一个名为的模块views.py
在你的rpcontacts
包裹。然后将以下代码添加到模块中并保存:
# -*- coding: utf-8 -*-
"""This module provides views to manage the contacts table."""
from PyQt5.QtWidgets import (
QHBoxLayout ,
QMainWindow ,
QWidget ,
)
class Window ( QMainWindow ):
"""Main Window."""
def __init__ ( self , parent = None ):
"""Initializer."""
super () . __init__ ( parent )
self . setWindowTitle ( "RP Contacts" )
self . resize ( 550 , 250 )
self . centralWidget = QWidget ()
self . setCentralWidget ( self . centralWidget )
self . layout = QHBoxLayout ()
self . centralWidget . setLayout ( self . layout )
首先,您从以下位置导入所需的类PyQt5.QtWidgets
。然后你创建Window
。这个类继承自Q主窗口 并提供生成应用程序主窗口的代码。在初始化方法中,将窗口的标题设置为"RP Contacts"
,将窗口大小调整为550
经过250
像素,使用定义和设置中央小部件QWidget ,最后定义一个布局 对于使用水平框布局的中央小部件。
编码和运行应用程序
由于您已经有了联系簿的主窗口,因此是时候使用以下代码编写创建功能性 PyQt 应用程序的代码了Q应用 。为此,创建一个名为的新模块main.py
在你的rpcontacts
打包并添加以下代码:
# -*- coding: utf-8 -*-
# rpcontacts/main.py
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .views import Window
def main ():
"""RP Contacts main function."""
# Create the application
app = QApplication ( sys . argv )
# Create the main window
win = Window ()
win . show ()
# Run the event loop
sys . exit ( app . exec ())
在此模块中,您导入sys 访问出口() ,它允许您在用户关闭主窗口时干净地退出应用程序。然后你导入QApplication
从PyQt5.QtWidgets
和Window
从views
。最后一步是定义主要的() 作为应用程序的主要功能。
里面main()
,你实例化QApplication
和Window
。然后你打电话.show()
在Window
,最后运行应用程序的主循环 , 或者事件循环 , 使用.exec() .
现在移动到项目根目录rpcontacts_project/
并创建一个名为rpcontacts.py
。该文件提供运行应用程序的入口点脚本。将以下代码添加到文件中并保存:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# rpcontacts_project/rpcontacts.py
"""This module provides RP Contacts entry point script."""
from rpcontacts.main import main
if __name__ == "__main__" :
main ()
该文件导入main()
从你的main.py
模块。然后你实施传统的条件语句 那个叫main()
如果用户运行 该模块作为 Python 脚本。现在通过运行命令启动应用程序python rpcontacts.py
在您的 Python 环境中。您将在屏幕上看到以下窗口:
就是这样!您已经创建了一个最小但功能齐全的 PyQt GUI 应用程序,您可以将其用作构建通讯录的起点。此时,您的项目应具有以下结构:
./rpcontacts_project/
│
├── rpcontacts/
│ ├── __init__.py
│ ├── views.py
│ └── main.py
│
└── rpcontacts.py
在本部分中,您使用 Python 模块和包为通讯录项目创建了所需的最小结构。您已经构建了应用程序的主窗口并将样板代码组合在一起以创建 PyQt GUI 应用程序。您也是第一次运行该应用程序。接下来,您将开始向 GUI 添加功能。
现在您已经构建了通讯录应用程序的框架,您可以开始对主窗口的 GUI 进行编码。在本节结束时,您将完成使用 Python 和 PyQt 创建通讯录 GUI 所需的步骤。 GUI 将如下所示:
在窗口的中央,您有一个表格视图来显示您的联系人列表。在表单的右侧,您有三个按钮:
Add 将新联系人添加到列表中
删除 从列表中删除选定的联系人
全部清除 从列表中删除所有联系人
您将在本节中添加或修改的所有代码和文件都收集在source_code_step_2/
目录。您可以点击下面的链接下载它们:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
回到views.py
模块并更新代码Window
生成上述 GUI:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/views.py
3
4 """This module provides views to manage the contacts table."""
5
6 from PyQt5.QtWidgets import (
7 QAbstractItemView ,
8 QHBoxLayout ,
9 QMainWindow ,
10 QPushButton ,
11 QTableView ,
12 QVBoxLayout ,
13 QWidget ,
14 )
15
16 class Window ( QMainWindow ):
17 """Main Window."""
18 def __init__ ( self , parent = None ):
19 """Initializer."""
20 # Snip...
21
22 self . setupUI ()
23
24 def setupUI ( self ):
25 """Setup the main window's GUI."""
26 # Create the table view widget
27 self . table = QTableView ()
28 self . table . setSelectionBehavior ( QAbstractItemView . SelectRows )
29 self . table . resizeColumnsToContents ()
30 # Create buttons
31 self . addButton = QPushButton ( "Add..." )
32 self . deleteButton = QPushButton ( "Delete" )
33 self . clearAllButton = QPushButton ( "Clear All" )
34 # Lay out the GUI
35 layout = QVBoxLayout ()
36 layout . addWidget ( self . addButton )
37 layout . addWidget ( self . deleteButton )
38 layout . addStretch ()
39 layout . addWidget ( self . clearAllButton )
40 self . layout . addWidget ( self . table )
41 self . layout . addLayout ( layout )
首先导入一些额外的 PyQt 类以在 GUI 中使用。以下是一些更相关的内容:
Q按钮 来创建Add , 删除 , 和全部清除 纽扣
QTableView 提供显示联系人列表的类似表格的视图
QAbstractItemView 提供对表视图选择行为策略的访问
在此代码中,首先添加Window
是一个电话.setupUI()
在......的最后__init__()
。当您运行应用程序时,此调用会生成主窗口的 GUI。
这是里面的代码.setupUI()
做:
27号线 创建一个QTableView
显示联系人列表的实例。
28号线 设置.selectionBehavior 财产给QAbstractItemView.SelectRows 。这确保当用户单击表视图的任何单元格时,将选择完整的行。表视图中的行保存与联系人列表中单个联系人相关的所有信息。
第 31 至 33 行 将三个按钮添加到 GUI:Add , 删除 , 和全部清除 。这些按钮尚不执行任何操作。
第 35 至 41 行 为 GUI 中的所有小部件创建并设置一致的布局。
有了这些补充Window
,您可以再次运行该应用程序。屏幕上的窗口将类似于您在本节开头看到的窗口。
笔记: 上述代码以及本教程中其余代码示例中的行号旨在方便解释。它们与最终模块或脚本中的行顺序不匹配。
在本部分中,您已运行创建通讯录主窗口 GUI 所需的所有步骤。您现在已准备好开始研究应用程序如何管理和存储您的联系人数据。
此时,您已经创建了一个 PyQt 应用程序及其主窗口的 GUI 来构建您的通讯录项目。在本部分中,您将编写代码来定义应用程序如何连接到联系人数据库。要完成此步骤,您将使用 SQLite 来处理数据库并PyQt 的 SQL 支持 将应用程序连接到数据库并使用您的联系人数据。
您将在本节中添加或修改的源代码和文件存储在source_code_step_3/
目录。您可以点击下面的链接下载它们:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
首先,回到main.py
在里面rpcontacts/
目录并更新代码以创建与数据库的连接:
# -*- coding: utf-8 -*-
# rpcontacts/main.py
"""This module provides RP Contacts application."""
import sys
from PyQt5.QtWidgets import QApplication
from .database import createConnection
from .views import Window
def main ():
"""RP Contacts main function."""
# Create the application
app = QApplication ( sys . argv )
# Connect to the database before creating any window
if not createConnection ( "contacts.sqlite" ):
sys . exit ( 1 )
# Create the main window if the connection succeeded
win = Window ()
win . show ()
# Run the event loop
sys . exit ( app . exec_ ())
在这种情况下,您首先导入createConnection()
从database.py
。此函数将包含用于创建和打开与联系人数据库的连接的代码。你将创建database.py
和写createConnection()
在下一节中。
里面main()
,第一行突出显示的行是尝试使用以下命令创建与数据库的连接createConnection()
。如果由于某种原因应用程序无法创建连接,则调用sys.exit(1)
将关闭应用程序而不创建图形元素,并指示发生了错误。
您必须以这种方式处理连接,因为应用程序依赖于数据库才能正常工作。如果您没有功能连接,那么您的应用程序将根本无法运行。
这种做法允许您在出现问题时处理错误并彻底关闭应用程序。您还可以向用户提供有关应用程序在尝试连接数据库时遇到的错误的相关信息。
添加完这些内容后,是时候深入研究代码了createConnection()
.
使用 PyQt 和 SQLite 连接到数据库
将通讯录应用程序连接到其关联的数据库是开发应用程序的基本步骤。为此,您将编写一个名为的函数createConnection()
,这将创建并打开与数据库的连接。如果连接成功,则该函数将返回 True
。否则,它将提供有关连接失败原因的信息。
回到rpcontacts/
目录并创建一个名为的新模块database.py
在其中。然后将以下代码添加到该模块:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/database.py
3
4 """This module provides a database connection."""
5
6 from PyQt5.QtWidgets import QMessageBox
7 from PyQt5.QtSql import QSqlDatabase
8
9 def createConnection ( databaseName ):
10 """Create and open a database connection."""
11 connection = QSqlDatabase . addDatabase ( "QSQLITE" )
12 connection . setDatabaseName ( databaseName )
13
14 if not connection . open ():
15 QMessageBox . warning (
16 None ,
17 "RP Contact" ,
18 f "Database Error: { connection . lastError () . text () } " ,
19 )
20 return False
21
22 return True
在这里,您首先导入一些必需的 PyQt 类。然后你定义createConnection()
。该函数采用一个参数:databaseName
保存文件系统中物理 SQLite 数据库文件的名称或路径。
这是里面的代码createConnection()
做:
11号线 使用创建数据库连接QSQLITE 司机。
12号线 设置文件名或数据库路径。
14号线 尝试打开连接。如果在通话过程中出现问题.open()
,那么if
代码块显示错误消息然后返回False
指示连接尝试失败。
22号线 回报True
如果连接尝试成功。
你已经编码了createConnection()
。现在您可以编写代码来创建contacts
数据库中的表。
使用创建并打开数据库连接的函数后,您可以继续编写辅助函数来创建contacts
桌子。您将使用此表来存储有关您的联系人的信息。
这是实现的代码_createContactsTable()
:
# -*- coding: utf-8 -*-
# rpcontacts/database.py
# Snip...
from PyQt5.QtSql import QSqlDatabase , QSqlQuery
def _createContactsTable ():
"""Create the contacts table in the database."""
createTableQuery = QSqlQuery ()
return createTableQuery . exec (
"""
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
job VARCHAR(50),
email VARCHAR(40) NOT NULL
)
"""
)
def createConnection ( databaseName ):
# Snip...
_createContactsTable ()
return True
在这里,您首先添加一个新的导入。你导入QSql查询 执行和操作 SQL 语句。
里面_createContactsTable()
,你创建一个QSqlQuery
实例。然后你打电话.exec()
使用基于字符串的 SQL 查询对象创建表语句 作为一个论点。该语句创建一个名为的新表contacts
在你的数据库中。该表包含以下列:
Column
Content
id
An integer with the table’s primary key
name
A string with the name of a contact
job
A string with the job title of a contact
email
A string with the email of a contact
这contacts
数据库中的表将存储有关您的联系人的相关信息。
完成编码的最后一步database.py
是添加一个调用_createContactsTable()
从内部createConnection()
,就在最后一个之前返回声明 。这确保应用程序创建contacts
在对数据库进行任何操作之前先检查表。
一旦您创建了contacts
表中,您可以对数据库运行一些测试,还可以添加一些示例数据以进行进一步测试。
到目前为止,您已经完成了处理通讯录数据库连接所需的代码的编写。在本节中,您将执行一些测试以确保此代码和数据库本身正常工作。您还将向数据库添加一些示例数据,以便在本教程后面执行进一步的测试。
现在打开一个终端 或命令行并移动到项目的根目录,rpcontacts_project/
。到达那里后,启动 Python互动环节 并输入以下代码:
>>> >>> from rpcontacts.database import createConnection
>>> # Create a connection
>>> createConnection ( "contacts.sqlite" )
True
>>> # Confirm that contacts table exists
>>> from PyQt5.QtSql import QSqlDatabase
>>> db = QSqlDatabase . database ()
>>> db . tables ()
['contacts', 'sqlite_sequence']
在这里,您首先导入createConnection()
来自database.py
模块。然后,您调用此函数来创建并打开与联系人数据库的连接。数据库文件名是contacts.sqlite
。由于该文件不存在于项目的根目录中,因此 SQLite 会为您创建它。您可以通过查看当前目录来检查这一点。
接下来,您确认数据库包含一个名为的表contacts
。为此,您可以致电.database()
在QSqlDatabase
。这个类方法返回一个指针 到当前数据库连接。通过对连接的引用,您可以调用.tables()
获取数据库中的表列表。请注意,列表中的第一个表是contacts
,所以现在您确定一切正常。
现在您可以准备 SQL 查询以将示例数据插入到contacts
桌子:
>>> >>> # Prepare a query to insert sample data
>>> from PyQt5.QtSql import QSqlQuery
>>> insertDataQuery = QSqlQuery ()
>>> insertDataQuery . prepare (
... """
... INSERT INTO contacts (
... name,
... job,
... email
... )
... VALUES (?, ?, ?)
... """
... )
True
上述查询允许您将特定值插入到name
, job
, 和email
属性并将这些值保存到数据库中。下面是如何执行此操作的示例:
>>> >>> # Sample data
>>> data = [
... ( "Linda" , "Technical Lead" , "linda@example.com" ),
... ( "Joe" , "Senior Web Developer" , "joe@example.com" ),
... ( "Lara" , "Project Manager" , "lara@example.com" ),
... ( "David" , "Data Analyst" , "david@example.com" ),
... ( "Jane" , "Senior Python Developer" , "jane@example.com" ),
... ]
>>> # Insert sample data
>>> for name , job , email in data :
... insertDataQuery . addBindValue ( name )
... insertDataQuery . addBindValue ( job )
... insertDataQuery . addBindValue ( email )
... insertDataQuery . exec ()
...
True
True
True
True
True
在这段代码中,您首先定义data
保存人员列表的联系信息。接下来,您使用for循环 通过调用插入数据.addBindValue()
。然后你打电话.exec()
在查询对象上有效地在数据库上运行 SQL 查询。
由于所有的电话.exec()
返回True
,可以断定数据已成功插入数据库。如果您想确认这一点,请运行以下代码:
>>> >>> query = QSqlQuery ()
>>> query . exec ( "SELECT name, job, email FROM contacts" )
True
>>> while query . next ():
... print ( query . value ( 0 ), query . value ( 1 ), query . value ( 2 ))
...
Linda Technical Lead linda@example.com
Joe Senior Web Developer joe@example.com
Lara Project Manager lara@example.com
David Data Analyst david@example.com
Jane Senior Python Developer jane@example.com
就是这样!你的数据库工作正常!现在您有一些示例数据可以用来测试应用程序,并且您可以专注于如何在通讯录主窗口中加载和显示联系人信息。
要在应用程序的主窗口中显示您的联系数据,您可以使用QTableView
。这个类是 PyQt 的一部分模型-视图架构 并提供了一种稳健且高效的方式来显示 PyQt 模型对象中的项目。
您将在本节中添加或修改的文件和代码存储在source_code_step_4/
目录。要下载它们,请单击下面的链接:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
完成此步骤后,您的通讯录将如下所示:
主窗口中的表视图对象提供了所需的功能,允许您快速修改和更新联系人信息。
For example, to update the name of a contact, you can double-click the cell containing the name, update the name, and then press Enter to automatically save the changes to the database. But before you can do this, you need to create a model and connect it to the table view.
PyQt提供了丰富的类集 用于使用 SQL 数据库。对于您的通讯录应用程序,您将使用QSql表模型 ,它为单个数据库表提供了可编辑的数据模型。它非常适合这项工作,因为您的数据库只有一个表,contacts
.
返回代码编辑器并创建一个名为的新模块model.py
在 - 的里面rpcontacts/
目录。将以下代码添加到文件中并保存:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/model.py
3
4 """This module provides a model to manage the contacts table."""
5
6 from PyQt5.QtCore import Qt
7 from PyQt5.QtSql import QSqlTableModel
8
9 class ContactsModel :
10 def __init__ ( self ):
11 self . model = self . _createModel ()
12
13 @staticmethod
14 def _createModel ():
15 """Create and set up the model."""
16 tableModel = QSqlTableModel ()
17 tableModel . setTable ( "contacts" )
18 tableModel . setEditStrategy ( QSqlTableModel . OnFieldChange )
19 tableModel . select ()
20 headers = ( "ID" , "Name" , "Job" , "Email" )
21 for columnIndex , header in enumerate ( headers ):
22 tableModel . setHeaderData ( columnIndex , Qt . Horizontal , header )
23 return tableModel
在此代码中,您首先执行一些必需的导入,然后创建ContactsModel
。在类初始值设定项中,定义一个名为的实例属性.model
保存数据模型。
接下来,您添加一个静态方法 创建并设置模型对象。这是里面的代码._createModel()
做:
16号线 创建一个实例QSqlTableModel()
被称为tableModel
.
17号线 将模型对象与contacts
数据库中的表。
18号线 设置.edit策略 模型的属性为QSqlTableModel.OnFieldChange 。这样,您可以确保模型上的更改立即保存到数据库中。
19号线 通过调用将表加载到模型中.select()
.
第 20 至 22 行 定义并设置用户友好的标题contacts
表的列。
23号线 返回新创建的模型。
此时,您的数据模型就可以使用了。现在您需要将表格视图小部件连接到模型,以便可以向用户显示联系信息。
将模型连接到视图
要在通讯录主窗口中显示联系人数据,您需要将表视图与数据模型连接起来。要执行此连接,您需要调用.setModel()
在表视图对象上并将模型作为参数传递:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
from .model import ContactsModel
class Window ( QMainWindow ):
"""Main Window."""
def __init__ ( self , parent = None ):
# Snip...
self . contactsModel = ContactsModel ()
self . setupUI ()
def setupUI ( self ):
"""Setup the main window's GUI."""
# Create the table view widget
self . table = QTableView ()
self . table . setModel ( self . contactsModel . model )
self . table . setSelectionBehavior ( QAbstractItemView . SelectRows )
# Snip...
在此代码中,您首先导入ContactsModel
从model.py
。此类提供管理联系人数据库中的数据的模型。
在初始化程序中Window
,您创建一个实例ContactsModel
。然后里面.setupUI()
,你打电话给.setModel()
在.table
将模型与表视图连接起来。如果您在此更新后运行该应用程序,那么您将看到在开头看到的窗口步骤4 .
PyQt 的模型-视图架构提供了一种强大且用户友好的方式来创建管理数据库的 GUI 应用程序。楷模 与数据库中的数据进行通信并访问数据。模型中的任何更改都会立即更新数据库。意见 负责向用户显示数据,并提供可编辑的小部件以允许用户直接在视图中修改数据。
如果用户通过视图修改数据,那么视图内部会与模型进行通信并更新模型,从而将更改保存到物理数据库中:
In this example, you double-click Joe’s Job field. This gives you access to an editable widget that allows you to modify the value in the cell. Then you update the job description from Senior Web Developer
to Web Developer
. When you hit Enter , the table view communicates the change to the model, and the model saves the change to the database immediately.
要确认更改已成功保存到数据库中,您可以关闭应用程序并再次运行它。表视图应该反映您的更新。
在此步骤中,您的通讯录应用程序提供加载、显示和更新有关您的联系人的信息的功能。尽管您可以修改和更新联系人信息,但您无法在列表中添加或删除联系人。
您将在本节中添加或修改的所有文件和代码都收集在source_code_step_5/
目录。要下载它们,请单击下面的链接:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
在本部分中,您将提供向数据库添加新联系人所需的功能,并使用弹出对话框输入新信息。第一步是创建增加联系人 对话。
对话框是可用于与用户通信的小窗口。在本节中,您将对通讯录进行编码增加联系人 对话框,允许您的用户将新联系人添加到他们当前的联系人列表中。
编码增加联系人 对话框,你将继承QDialog 。此类提供了为 GUI 应用程序构建对话框的蓝图。
现在打开views.py
模块并更新导入部分,如下所示:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QAbstractItemView ,
QDialog ,
QDialogButtonBox ,
QFormLayout ,
QHBoxLayout ,
QLineEdit ,
QMainWindow ,
QMessageBox ,
QPushButton ,
QTableView ,
QVBoxLayout ,
QWidget ,
)
上面代码中突出显示的行导入了构建所需的类增加联系人 对话。通过这些课程,您名称空间 ,在末尾添加以下类views.py
:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/views.py
3
4 # Snip...
5 class AddDialog ( QDialog ):
6 """Add Contact dialog."""
7 def __init__ ( self , parent = None ):
8 """Initializer."""
9 super () . __init__ ( parent = parent )
10 self . setWindowTitle ( "Add Contact" )
11 self . layout = QVBoxLayout ()
12 self . setLayout ( self . layout )
13 self . data = None
14
15 self . setupUI ()
16
17 def setupUI ( self ):
18 """Setup the Add Contact dialog's GUI."""
19 # Create line edits for data fields
20 self . nameField = QLineEdit ()
21 self . nameField . setObjectName ( "Name" )
22 self . jobField = QLineEdit ()
23 self . jobField . setObjectName ( "Job" )
24 self . emailField = QLineEdit ()
25 self . emailField . setObjectName ( "Email" )
26 # Lay out the data fields
27 layout = QFormLayout ()
28 layout . addRow ( "Name:" , self . nameField )
29 layout . addRow ( "Job:" , self . jobField )
30 layout . addRow ( "Email:" , self . emailField )
31 self . layout . addLayout ( layout )
32 # Add standard buttons to the dialog and connect them
33 self . buttonsBox = QDialogButtonBox ( self )
34 self . buttonsBox . setOrientation ( Qt . Horizontal )
35 self . buttonsBox . setStandardButtons (
36 QDialogButtonBox . Ok | QDialogButtonBox . Cancel
37 )
38 self . buttonsBox . accepted . connect ( self . accept )
39 self . buttonsBox . rejected . connect ( self . reject )
40 self . layout . addWidget ( self . buttonsBox )
这段代码中发生了很多事情。总结如下:
5号线 定义一个新类继承 从QDialog
.
第 7 至 15 行 定义类初始值设定项。在这种情况下,最相关的添加是.data
,这是一个实例属性 您将用它来保存用户提供的数据。
In .setupUI()
,您定义对话框的 GUI:
第 20 至 25 行 添加三个QLine编辑 对象:name
, job
, 和email
。您将使用这些行编辑来获取用户输入的姓名、职位描述和要添加的联系人的电子邮件。它们代表数据库中相应的字段。
第 27 至 30 行 创建一个QForm布局 在表单中排列行编辑的实例。这布局管理器 还为每个行编辑或字段提供用户友好的标签。
第 33 至 37 行 添加一个QDialogButtonBox 提供两个标准按钮的对象:OK 和取消 。这OK 按钮接受用户的输入取消 按钮拒绝它。
第 38 行和第 39 行 连接对话框的内置.accepted()
和.rejected()
信号与.accept()
和reject()
插槽,分别。在这种情况下,您将依赖对话框的内置.reject()
槽,它关闭对话框而不处理输入。除此之外,你只需要编写代码.accept()
投币口。
对对话框进行编码.accept()
slot,你需要考虑任何用户输入都需要验证 以确保其正确且安全。当您使用 SQL 数据库时尤其如此,因为存在以下风险:SQL注入攻击 .
在此示例中,您将添加一个最小验证规则,以确保用户为对话框中的每个输入字段提供数据。但是,添加您自己的、更强大的验证规则将是一个很好的练习。
话不多说,回到AddDialog
并为其添加以下代码.accept()
投币口:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/views.py
3
4 # Snip...
5 class AddDialog ( QDialog ):
6 def __init__ ( self , parent = None ):
7 # Snip...
8
9 def setupUI ( self ):
10 # Snip...
11
12 def accept ( self ):
13 """Accept the data provided through the dialog."""
14 self . data = []
15 for field in ( self . nameField , self . jobField , self . emailField ):
16 if not field . text ():
17 QMessageBox . critical (
18 self ,
19 "Error!" ,
20 f "You must provide a contact's { field . objectName () } " ,
21 )
22 self . data = None # Reset .data
23 return
24
25 self . data . append ( field . text ())
26
27 super () . accept ()
里面的代码.accept()
执行以下操作:
14号线 初始化.data
到一个空列表([]
)。该列表将存储用户的输入数据。
15号线 定义了一个for
循环遍历对话框中的三行编辑或字段。
第 16 至 23 行 定义一个条件语句,检查用户是否为对话框中的每个字段提供了数据。如果没有,则该对话框会显示一条错误消息,警告用户缺少数据。
25号线 将每个字段的用户输入添加到.data
.
27号线 调用超类的.accept()
槽提供用户单击后关闭对话框的标准行为OK .
使用此代码,您就可以向通讯录的主窗口添加新位置。该插槽将启动对话框,如果用户提供有效的输入,则该插槽将使用该模型将新添加的联系人保存到数据库中。
现在您已经编写了代码增加联系人 对话框,是时候添加一个新插槽了Window
这样您就可以通过单击启动对话框Add 并在用户点击后处理用户的输入OK .
转到定义Window
并添加以下代码:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/views.py
3
4 # Snip...
5 class Window ( QMainWindow ):
6 # Snip...
7
8 def setupUI ( self ):
9 # Snip...
10 self . addButton = QPushButton ( "Add..." )
11 self . addButton . clicked . connect ( self . openAddDialog )
12 # Snip...
13
14 def openAddDialog ( self ):
15 """Open the Add Contact dialog."""
16 dialog = AddDialog ( self )
17 if dialog . exec () == QDialog . Accepted :
18 self . contactsModel . addContact ( dialog . data )
19 self . table . resizeColumnsToContents ()
以下是上述代码中发生的情况的摘要:
11号线 连接.clicked()
的信号Add 按钮到新创建的插槽,.openAddDialog()
。这样,点击按钮就会自动调用该插槽。
14号线 定义了.openAddDialog()
投币口。
16号线 创建一个实例AddDialog
.
第 17 至 19 行 定义一个条件语句来检查对话框是否被接受。如果是,则第 14 行调用.addContact()
在带有对话框的数据模型上.data
属性作为参数。最终声明中if
代码块调整表视图的大小以适应其更新内容的大小。
现在您有办法启动增加联系人 对话框并处理其数据,您需要提供代码.addContact()
在你的数据模型中。这是下一节的主题。
在模型中处理添加对话框的数据
在本节中,您将添加一个名为的方法.addContact()
到你的数据模型,ContactsModel
。打开model.py
在代码编辑器中,转到定义ContactsModel
,并添加以下代码:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/model.py
3
4 # Snip...
5 class ContactsModel :
6 # Snip...
7
8 def addContact ( self , data ):
9 """Add a contact to the database."""
10 rows = self . model . rowCount ()
11 self . model . insertRows ( rows , 1 )
12 for column , field in enumerate ( data ):
13 self . model . setData ( self . model . index ( rows , column + 1 ), field )
14 self . model . submitAll ()
15 self . model . select ()
里面.addContact()
,代码执行以下操作:
10号线 获取数据模型中的当前行数。
11号线 在数据模型的末尾插入新行。
12、13号线 运行一个for
将每个项目插入其中的循环data
到数据模型中相应的单元格中。为此,第 9 行调用.setData()
在模型上,带有单元格索引和当前数据field
作为参数。
14号线 通过调用将更改提交到数据库.submitAll()
在模型上。
15号线 将数据从数据库重新加载到模型中。
如果您运行带有这些新增功能的应用程序,您将得到以下行为:
现在当你点击Add , 这增加联系人 屏幕上出现对话框。您可以使用该对话框提供新联系人所需的信息,并通过单击将联系人添加到数据库中OK .
您将添加到通讯录应用程序的最后一个功能是能够使用 GUI 从数据库中删除联系人。
同样,您将在本节下找到所有文件和添加或修改的代码source_code_step_6/
目录。您可以点击下面的链接下载它们:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
在本部分中,您将首先添加一次删除单个联系人的功能。然后,您将添加代码以从数据库中删除所有联系人。
要从联系人数据库中删除单个联系人,您需要在通讯录主窗口的表格视图中选择所需的联系人。选择联系人后,您可以单击删除 对数据库执行操作。
前往model.py
模块并添加以下代码来实现.deleteContact()
里面ContactsModel
:
# -*- coding: utf-8 -*-
# rpcontacts/model.py
# Snip...
class ContactsModel :
# Snip...
def deleteContact ( self , row ):
"""Remove a contact from the database."""
self . model . removeRow ( row )
self . model . submitAll ()
self . model . select ()
该方法有三行代码。第一行删除选定的row
。第二行将更改提交到数据库。最后,第三行将数据重新加载到模型中。
接下来,回到views.py
模块并在后面添加代码删除 按钮输入Window
:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
class Window ( QMainWindow ):
# Snip...
def setupUI ( self ):
"""Setup the main window's GUI."""
# Snip...
self . deleteButton = QPushButton ( "Delete" )
self . deleteButton . clicked . connect ( self . deleteContact )
# Snip...
def deleteContact ( self ):
"""Delete the selected contact from the database."""
row = self . table . currentIndex () . row ()
if row < 0 :
return
messageBox = QMessageBox . warning (
self ,
"Warning!" ,
"Do you want to remove the selected contact?" ,
QMessageBox . Ok | QMessageBox . Cancel ,
)
if messageBox == QMessageBox . Ok :
self . contactsModel . deleteContact ( row )
在第一行突出显示的行中,您连接.clicked()
的信号删除 按钮到.deleteContact()
投币口。此连接会触发调用.deleteContact()
每次用户单击按钮时。
In .deleteContact()
,首先获取表视图中当前选定行的索引。这if
语句检查索引是否低于0
,这意味着表视图中没有联系人。如果是,则该方法立即返回,而不执行任何进一步的操作。
然后该方法显示一条警告消息,确认用户想要删除所选联系人。如果用户接受该操作,则.deleteContact(row)
被叫。在这种情况下,row
表示表中当前选定行的索引。
添加这些内容后,您可以再次运行应用程序以获得以下行为:
现在,当您从表视图中选择联系人并单击删除 ,您会看到一条警告消息。如果您单击消息对话框的OK 按钮,然后应用程序会从数据库中删除选定的联系人,并相应地更新表视图。
要从数据库中删除所有联系人,您将首先添加一个名为的方法.clearContacts()
到ContactsModel
。打开你的model.py
模块并在类末尾添加以下方法:
1 # -*- coding: utf-8 -*-
2 # rpcontacts/model.py
3
4 # Snip...
5 class ContactsModel :
6 # Snip...
7
8 def clearContacts ( self ):
9 """Remove all contacts in the database."""
10 self . model . setEditStrategy ( QSqlTableModel . OnManualSubmit )
11 self . model . removeRows ( 0 , self . model . rowCount ())
12 self . model . submitAll ()
13 self . model . setEditStrategy ( QSqlTableModel . OnFieldChange )
14 self . model . select ()
以下是每行代码的作用:
10号线 设置数据模型的.editStrategy
财产给QSqlTableModel.OnManualSubmit
。这允许您缓存所有更改,直到您调用.submitAll()
稍后的。您需要这样做,因为您要同时更改多行。
11号线 从模型中删除所有行。
12号线 将更改保存到数据库。
13号线 重置模型的.editStrategy
财产恢复其原始价值,QSqlTableModel.OnFieldChange
。如果您不将此属性重置为其原始值,那么您将无法直接在表视图中更新联系人。
14号线 将数据重新加载到模型中。
编码完成后.clearContacts()
,你可以回到views.py
文件和更新Window
使用以下代码:
# -*- coding: utf-8 -*-
# rpcontacts/views.py
# Snip...
class Window ( QMainWindow ):
# Snip...
def setupUI ( self ):
"""Setup the main window's GUI."""
# Snip...
self . clearAllButton = QPushButton ( "Clear All" )
self . clearAllButton . clicked . connect ( self . clearContacts )
# Snip...
def clearContacts ( self ):
"""Remove all contacts from the database."""
messageBox = QMessageBox . warning (
self ,
"Warning!" ,
"Do you want to remove all your contacts?" ,
QMessageBox . Ok | QMessageBox . Cancel ,
)
if messageBox == QMessageBox . Ok :
self . contactsModel . clearContacts ()
此代码中第一行突出显示的行连接.clicked()
的信号全部清除 按钮到.clearContacts()
下面的插槽。
In .clearContacts()
,您首先创建一个消息对话框,messageBox
,要求用户确认删除操作。如果用户通过点击确认操作OK , 然后.clearContacts()
调用模型以从数据库中删除所有联系人:
就是这样!通过最后一段代码,您的通讯录应用程序就完成了。该应用程序提供的功能允许您的用户显示、添加、更新和删除数据库中的联系人。
结论
使用 Python、PyQt 和 SQLite 构建通讯录 GUI 应用程序对于您扩展使用这些工具以及作为一般开发人员的技能来说是一个很好的练习。像这样的编码项目可以让您应用已有的知识和技能,并促使您在每次遇到新的编程问题时研究和学习新的主题。
在本教程中,您学习了如何:
构建通讯录应用程序的 GUI 使用 PyQt
使用PyQt 的 SQL 支持 将应用程序连接到SQLite数据库
使用PyQt 的模型视图架构 使用应用程序的数据库
您可以通过单击下面的链接下载通讯录应用程序的完整源代码以及完成本教程中每个步骤的代码:
获取源代码: 单击此处获取您将使用的源代码 在本教程中使用 Python、PyQt 和 SQLite 构建联系簿。
下一步
至此,您已经完成了一个功能齐全的通讯录项目。该应用程序提供了最少的功能,但它是继续添加功能并将您的 Python 和 PyQt 技能提升到新水平的良好起点。以下是您可以实施的一些下一步想法:
添加新数据字段: 添加新的数据字段来存储有关您的联系人的更多信息会很棒。例如,您可以添加联系人的照片、电话号码、网页、Twitter 账号等。为此,您可能需要创建新表并设置它们之间的关系。 PyQt 提供了QSql关系表模型 ,它定义了单个表的可编辑数据模型并提供外键支持。
提供搜索能力: 为用户提供一种在数据库中搜索联系人的方法可以说是此类应用程序的必备功能。为了实现它,你可以使用 PyQt 的QSqlQuery
和QSql查询模型 .
添加备份功能: 提供备份联系信息的方式是另一个有趣的功能。用户可能会遇到计算机问题并丢失数据。您可以提供将数据上传到云服务或将其备份到外部磁盘的选项。
这些只是关于如何继续向通讯录添加功能的一些想法。接受挑战并在此基础上创造一些令人惊奇的东西!