讯享网
静态库与动态库
静态库与动态库的区别可以从以下几个角度来说明:
- 编译方式:静态库在编译时会被完整地链接到可执行文件中,而动态库在编译时只会被引用,最终需要在运行时动态加载。
- 文件大小:静态库会增加可执行文件的大小,因为静态库的代码被完整地复制到可执行文件中。而动态库的代码只需要被引用,所以可执行文件的大小相对较小。
- 内存占用:静态库在程序运行时会被完整地加载到内存中,而动态库在程序运行时需要被动态加载到内存中。因此,动态库在内存占用方面更加灵活,可以在需要时加载和释放。
- 可维护性:静态库的更新需要重新编译整个程序,而动态库的更新只需要替换动态库文件即可。因此,动态库在可维护性方面更加方便。
- 共享性:多个程序可以同时使用同一个动态库,从而节省了系统资源。而静态库每个程序都需要复制一份,增加了系统资源的消耗。
- 跨平台性:动态库通常具有更好的跨平台性,因为可以在不同的操作系统上使用同一个动态库文件。而静态库需要针对不同的操作系统进行编译。
总的来说,静态库在编译时被完整地链接到可执行文件中,占用内存较大,但可执行文件的独立性较强;而动态库在运行时动态加载,占用内存较小,但可执行文件的依赖性较强。选择使用哪种库取决于具体的需求和项目要求。
构建安装程序
Windows打包
在Windows平台上,当构建完Qt程序后,需要使用找到其依赖的动态库(*.dll)。常用工具有Dependency、Dependencies(win10、win11)。
使用Dependencies建议区分依赖分别是来自windows、qt、还是第三方库;
依赖库查找齐全后方可进行构建安装程序,下面是推荐的工具:
NSIS、Inno Setup、Advanced Installer等。
注意事项:验证确认自己安装包完整性,往往需要使用对应系统未安装Qt程序的虚拟机。
Linux打包
Linux下部署Qt应用程序,有如下几种方式:
创建本地分发包
Linux发行版较多主流包管理器有两个:rpm、deb.
rpm参考:https://tldp.org/HOWTO/RPM-HOWTO/
deb参考:https://www.debian.org/doc/manuals/maint-guide/
创建独立应用程序
要将Qt程序独立部署到Linux中,需要将其所需组件捆绑。推荐工具linuxdeployqt,它可以最终生成AppImage。
跨平台打包工具
Qt Installer Framework,简称 Qt IFW,来自Qt官方,现在可以进行通用程序打包。
结尾
其它工具不太了解,接下来我会针对Qt Installer Framework写一篇程序打包和在线升级的教程,敬请期待!
QtIFW 简介
Qt IFW(Qt Installer Framework 的简称 ),是由 Qt 官方提供的安装程序制作框架。进入Qt IFW的官方下载页,选择一个合适版本,这里选择版本号为4.5.0的windows版本进行安装。
官方下载地址:https://download.qt.io/official_releases/qt-installer-framework/
本文会在Windows上基于Qt IFW进行程序安装包程序制作,包括常用的离线安装包和在线更新包的生成和验证都会详细介绍。使用Qt IFW制作安装包默认您已经准备好了完整的程序包(windeployqt或者其它工具生成)。
环境配置
添加到Qt Creator帮助文档
4.5.0安装目录下没有qch文件,此步骤可以跳过。
配置Windows环境变量
Windows下使用binarycreator作为打包工具,必须把binarycreator工具所在的bin目录导入的环境变量Path中。
Qt IFW的使用
构建Example
直接Qt构建examples.pro可查看各个例子安装效果
制作安装包至少应包含config/、packages/两个目录
离线安装
创建配置文件
<?xml version=“1.0” encoding=“UTF-8”?> <Installer> 讯享网<Name>UDS_Updata</Name> <Version>1.0.0</Version> <Title>UDS_Updata Installer</Title> <Publisher>nealwang</Publisher> <StartMenuDir>UDS_Updata</StartMenuDir> <TargetDir>@ApplicationsDir@/UDS_Updata</TargetDir>
</Installer>
讯享网
配置文件指定如下信息:
- < Title > 标题栏上安装程序名称
- < Name > 显示在安装页面上应用程序的名称
- < Version > 应用程序的版本号
- < Publisher > 软件发布者
- < StartMenuDir > 添加到开始菜单默认程序组名称
- < TargetDir > 应用程序的安装目录
创建包信息文件
<?xml version=“1.0” encoding=“UTF-8”?> <Package> 讯享网<DisplayName>UDS_Updata</DisplayName> <Description>This is a demo for Qt IFW </Description> <Version>1.0.0-1</Version> <ReleaseDate>2023-10-19</ReleaseDate> <Default>true</Default> <Script>installscript.qs</Script> <Licenses> <License name="Public License Agreement" file="license.txt" /> </Licenses>
</Package>
各个元素含义如下:
- < DisplayName > 指定组件的名称
- < Description > 显示选中组件的描述信息
- < Version > 组件的版本号信息,可用作后期版本更新
- < ReleaseDate > 组件发布的日期
- < Default > 安装过程中组件是否默认选中,true表示默认选中,false默认补选中。
- < Script > JavaScript文件名,执行一些个性化的安装操作
- < Licenses > 添加许可文件
自定义安装
通过在installscript.qs文件中添加如下内容,分别添加应用程序到开始菜单快捷方式和桌面快捷方式。
function Component() { 讯享网gui.pageWidgetByObjectName("LicenseAgreementPage").entered.connect(changeLicenseLabels);
} changeLicenseLabels = function() { page = gui.pageWidgetByObjectName("LicenseAgreementPage");page.AcceptLicenseLabel.setText("Yes I do!");page.RejectLicenseLabel.setText("No I don't!");
} Component.prototype.createOperations = function() { // 调用默认实现 component.createOperations(); if (systemInfo.productType === “windows”) { // 添加桌面快捷方式 component.addOperation(“CreateShortcut”,“@TargetDir@/UDS_Updata.exe”,“@DesktopDir@/UDS_Updata.lnk”,“workingDirectory=@TargetDir@”); //添加开始菜单快捷方式 component.addOperation(“CreateShortcut”,“@TargetDir@/UDS_Updata.exe”,“@StartMenuDir@/UDS_Updata.lnk”,“workingDirectory=@TargetDir@”); } }
准备打包文件
将提前准备好的程序(.exe、.dll等文件)
开始打包
执行如下命令
讯享网binarycreator -c config\config.xml -p packages UDS_updateInstaller -v
验证测试安装包
双击生成安装包一路next即可,部分截图如下。
在线安装
生成基础安装包
binarycreator –online-only -c config/config.xml -p packages installer.exe
创建初版存储库
repogen -p packages repository
安装基础安装包
此过程若使用Gitee做存储库可能会出现异常,详见异常问题汇总
创建新版本存储库
repogen –update-new-components -p packages_update3.2 repository
使用安装包中maintenancetool安装更新
异常问题汇总
异常1
使用Gitee做资源库时较大文件无法下载,提示协议未知;
暂无解决办法,需切换成其它资源库。
建议使用github存储库或者自建http服务。笔者使用python自带的httpserver进行测试。
github需要修改hosts或者梯子,请自行选择。
异常2
安装目录存在且包含安装程序,这就涉及到自动卸载旧版本或者覆盖安装问题。
总结
QtIFW比较灵活支持离线或在线安装程序,或两者兼而有之,具体取决于您的使用案例。支持资源库、样式表、窗口等的定制化操作。
实操内容已上传Github,感兴趣请移步,欢迎大佬批评指正。后续会持续更新完善
https://github.com/nealwang123/QtIFWOnline.git
本项任务涉及一份每周三定期发送到指定邮箱的数据汇总表格。邮件附件为一个 zip 压缩文件,内含两份资料:一份 doc 文档,以及一份 xlsx 的电子表格。
任务的核心内容是登录邮箱,下载并解压缩这份 zip 文件,随后打开并阅读 xlsx 电子表格。您需要特别注意的是关于黑龙江的相关信息,因为黑龙江地区有专属的联系人负责。
任务完成后,您需要根据所提取的黑龙江信息,找到对应的负责人。在确定负责人后,请使用企业微信发送提醒,以确保他们能及时处理相关事宜。
为了实现所需的功能,我们需要借助 126/163/ 邮箱的 IMAP 协议来收发邮件。首先,您需要登录您的邮箱,启动 IMAP 和 SMTP 的授权操作。在此过程中,您会获得一个一次性密码。最后,只需利用您的邮箱名和该一次性密码,就可以顺利通过 IMAP 协议收发邮件了。
为了实现 IMAP 邮件的接收与发送,我们需要利用 imap_tools 这个包,该包可以通过使用 pip 命令进行安装。imap_tools 包的操作相当简单,只需要知道邮箱名和密码就可以进行相关操作。
以 126 邮箱的 IMAP 服务器为例,其地址是 imap.126.com,无需填写端口号。由于这是一个用于工作的邮箱,发件人是固定的,因此我们可以通过指定发件人信息来缩小搜索范围。
对于邮件的主题 (subject) 匹配,我们可以使用 re.search (pattern, msg.subject) 来进行比对。一旦找到匹配项,那就是我们想要的邮件。之后,就可以进行邮件的下载与保存了。
代码:
mail_pass = ‘*’ # 使用的邮箱发送邮件,为邮箱的授权码,非密码,可在网页的邮箱设置中开通,其它邮箱也类似 sender = ‘@163.cn’ pattern = r“地球物理台网数据质量监控日报” #result = re.search(pattern, string) with MailBox(‘imap.126.com’).login(‘’, mail_pass, ‘INBOX’) as mailbox: 讯享网# 从收件箱文件夹中获取邮件主题列表 #subjects = [msg.subject for msg in mailbox.fetch()] for msg in mailbox.fetch(): result = re.search(pattern, msg.subject) if result: #print("字符串包含地球物理台网数据质量监控日报") print("邮件主题:", msg.subject) print("发件人:", msg.from_) #print("收件人:", msg.to) print("发送时间:", msg.date) print("邮件正文:", msg.text) for attachment in msg.attachments: payload = attachment.payload filename = attachment.filename with open(filename, 'wb') as f: f.write(payload) #print("保存附件:", filename) else: print("字符串不包含地球物理台网数据质量监控日报")
这样一次下载多个文件,对这个 zip 文件进行解压缩。直接使用 zipfile 包即可。在这里 zipfile 包有一点问题,需要手动修改一下源文件。
找到 zipfile.py 这个文件,对两处编码信息进行修改。
第 1376 行 原内容 为 filename = filename.decode(‘cp437’) 修改为 filename = filename.decode(‘GBK’)
1555 行原内容为:fname_str = fname.decode(“cp437”) 修改为 fname_str = fname.decode(“GBK”)
修改后,解压缩出来的文件名是正确的,不会出现乱码,我的 python 是 3.10.11,可能是 3.10 的 windows 版都可能有这个问题。
for filename in os.listdir(directory): 讯享网if filename.endswith('.zip') : zip_path = os.path.join(directory, filename) with zipfile.ZipFile(zip_path, 'r') as zip_ref: for filename in zip_ref.namelist(): print(filename) decoded_filename = filename.encode('utf-8').decode('GBK') zip_ref.extract(filename, directory) new_filename = directory + decoded_filename print(f"解压缩文件: {filename}")
至此,文件收取并解压缩,最后一步是展示。用 PyQt6 来个简单界面,自动加载最新的.xlsx 文件,最后成这么个形态。
用 pandas 读取.xlsx 文件,进行筛选,把筛选的结果加载到 QTableWidget,整体就这些吧。
界面方面可以简单优化一化,加几个按钮、选项等。
之前写的 PyQt6 相关内容:
- Python PyQt6 绘图解析 - PyQt6 GUI 图形界面扫描 ping 程序简单实现和实操
- Copilot 免费实现 ChatPDF 功能,可上传 PDF 附件,对文章进行问答 / 总结
- PyQt6 绘图兰勃特投影中国 9 段线 / 10 段线图,绘制 nc 等值线图,绘图代码 GUI 移植
- PyQt6 绘图解析 - PyQt GUI 图形界面绘图简单实现和实操
- Python PyQt6 设计图形界面,PyQt6 与 MatPlotlib 实现简易绘图小程序
- Python PyQt6 设计图形界面,QGridLayout 实现一个简单的发邮件和简易计算小软件
- Python PyQt6 设计图形界面一点小改进,简单实现标签页面切换
- Python PyQt6 设计图形界面,实现一个简单的 ping 功能小软件
这几天学习 PyQt6,PyQt6 是一个用于创建图形用户界面(GUI)应用程序的 Python 库,它提供了对 Qt 框架的完整绑定和封装。Qt 是一个功能强大、跨平台的 C++ 应用程序开发框架,被广泛用于开发跨平台的 GUI 应用程序。
- PyQt6 库允许开发人员使用 Python 语言创建丰富、交互式的 GUI 应用程序,具有各种功能和特性。以下是 PyQt6 的一些主要特点和优势:
- 跨平台支持:PyQt6 支持多个平台,包括 Windows、macOS、Linux 和其他一些操作系统。这意味着您可以使用相同的代码基础轻松地在不同的操作系统上构建应用程序。
- 强大的 GUI 控件:PyQt6 提供了大量的 Qt 控件和小部件,包括按钮、标签、文本框、列表框、表格、菜单等等。这些控件使开发人员能够创建各种界面元素来满足应用程序的需求。
- 丰富的功能和特性:PyQt6 提供了许多功能和特性,包括布局管理、事件处理、信号与槽机制、动画效果、绘图、多线程支持、数据库访问等等。这些功能使开发人员能够构建复杂和功能丰富的应用程序。
- 可扩展性:PyQt6 是一个灵活的库,它允许开发人员根据需要进行自定义和扩展。您可以使用 Qt 的底层功能和 API,编写自己的定制控件和功能。
- 文档和社区支持:PyQt6 拥有详细的文档和丰富的社区支持,这使得学习和使用 PyQt6 变得更加容易。您可以在文档中找到大量的示例代码、教程和指南,以及在社区中获得帮助和支持。
前几天转发了一个 PyQt6 的开发的一个小例子。
这几天也在加紧学习。PyQt6 安装比较简单,便于打包程序,可以单独建立个虚拟环境:

conda create –name PyQt6 python=3.9 pip install PyQt6 pip install pyqt6-tools
PyQt6-tools 安装好后,会有一个 Qt Designer 设计器,可以拖动进行简单的界面设计,再通过 pyuic6.exe 这个程序把设计好的 ui 界面转化成 py 代码,在这些代码的基础上就可以实现有图形界面的 python 代码开发了。
比如设计这样一个界面:
把设计好的界面保存成 ColorD.ui,通过 pyuic6.exe 把 ui 转化成 py 代码。搜索 pyuic6.exe 文件的位置,把这个路径加入到系统 path。在 cmd 命令行输入:
讯享网pyuic6 -x ColorD.ui -o ColorD.py
转好的代码如下:
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6.QtWidgets import QColorDialog,QFontDialog class Ui_Form(object): 讯享网<span class="nv">def</span> <span class="nv">setupUi</span><span class="p">(</span><span class="nv">self</span><span class="p">,</span> <span class="k">Form</span><span class="p">):</span> <span class="k">Form</span><span class="p">.</span><span class="nv">setObjectName</span><span class="p">(</span><span class="c1">"Form")
Form.resize(400, 300) <span class="nv">self</span><span class="p">.</span><span class="nv">verticalLayout</span> <span class="o">=</span> <span class="nv">QtWidgets</span><span class="p">.</span><span class="nv">QVBoxLayout</span><span class="p">(</span><span class="nv">Form</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">verticalLayout</span><span class="p">.</span><span class="nv">setObjectName</span><span class="p">(</span><span class="c1">"verticalLayout")
self.textEdit = QtWidgets.QTextEdit(parent=Form) 讯享网 <span class="nv">font</span> <span class="o">=</span> <span class="nv">QtGui</span><span class="p">.</span><span class="nv">QFont</span><span class="p">()</span> <span class="nv">font</span><span class="p">.</span><span class="nv">setPointSize</span><span class="p">(</span><span class="mi">14</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">textEdit</span><span class="p">.</span><span class="nv">setFont</span><span class="p">(</span><span class="nv">font</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">textEdit</span><span class="p">.</span><span class="nv">setObjectName</span><span class="p">(</span><span class="c1">"textEdit")
self.verticalLayout.addWidget(self.textEdit) <span class="nv">self</span><span class="p">.</span><span class="nv">horizontalLayout</span> <span class="o">=</span> <span class="nv">QtWidgets</span><span class="p">.</span><span class="nv">QHBoxLayout</span><span class="p">()</span> <span class="nv">self</span><span class="p">.</span><span class="nv">horizontalLayout</span><span class="p">.</span><span class="nv">setObjectName</span><span class="p">(</span><span class="c1">"horizontalLayout")
self.pushButton = QtWidgets.QPushButton(parent=Form) 讯享网 <span class="nv">font</span> <span class="o">=</span> <span class="nv">QtGui</span><span class="p">.</span><span class="nv">QFont</span><span class="p">()</span> <span class="nv">font</span><span class="p">.</span><span class="nv">setPointSize</span><span class="p">(</span><span class="mi">12</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">pushButton</span><span class="p">.</span><span class="nv">setFont</span><span class="p">(</span><span class="nv">font</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">pushButton</span><span class="p">.</span><span class="nv">setObjectName</span><span class="p">(</span><span class="c1">"pushButton")
self.horizontalLayout.addWidget(self.pushButton) <span class="nv">self</span><span class="p">.</span><span class="nv">pushButton</span><span class="p">.</span><span class="nv">clicked</span><span class="p">.</span><span class="nv">connect</span><span class="p">(</span><span class="nv">self</span><span class="p">.</span><span class="nv">ColorDialog</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">pushButton_2</span> <span class="o">=</span> <span class="nv">QtWidgets</span><span class="p">.</span><span class="nv">QPushButton</span><span class="p">(</span><span class="nv">parent</span><span class="o">=</span><span class="nv">Form</span><span class="p">)</span> <span class="nv">font</span> <span class="o">=</span> <span class="nv">QtGui</span><span class="p">.</span><span class="nv">QFont</span><span class="p">()</span> <span class="nv">font</span><span class="p">.</span><span class="nv">setPointSize</span><span class="p">(</span><span class="mi">12</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">pushButton_2</span><span class="p">.</span><span class="nv">setFont</span><span class="p">(</span><span class="nv">font</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">pushButton_2</span><span class="p">.</span><span class="nv">setObjectName</span><span class="p">(</span><span class="c1">"pushButton_2")
self.pushButton_2.clicked.connect(self.fontDialog) 讯享网 <span class="nv">self</span><span class="p">.</span><span class="nv">horizontalLayout</span><span class="p">.</span><span class="nv">addWidget</span><span class="p">(</span><span class="nv">self</span><span class="p">.</span><span class="nv">pushButton_2</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">verticalLayout</span><span class="p">.</span><span class="nv">addLayout</span><span class="p">(</span><span class="nv">self</span><span class="p">.</span><span class="nv">horizontalLayout</span><span class="p">)</span> <span class="nv">self</span><span class="p">.</span><span class="nv">retranslateUi</span><span class="p">(</span><span class="nv">Form</span><span class="p">)</span> <span class="nv">QtCore</span><span class="p">.</span><span class="nv">QMetaObject</span><span class="p">.</span><span class="nv">connectSlotsByName</span><span class="p">(</span><span class="nv">Form</span><span class="p">)</span> <span class="nv">def</span> <span class="nv">ColorDialog</span><span class="p">(</span><span class="nv">self</span><span class="p">):</span> <span class="k">color</span> <span class="o">=</span> <span class="nv">QColorDialog</span><span class="p">.</span><span class="nv">getColor</span><span class="p">()</span> <span class="nv">self</span><span class="p">.</span><span class="nv">textEdit</span><span class="p">.</span><span class="nv">setTextColor</span><span class="p">(</span><span class="nv">color</span><span class="p">)</span> <span class="nv">def</span> <span class="nv">fontDialog</span><span class="p">(</span><span class="nv">self</span><span class="p">):</span> <span class="nv">font</span><span class="p">,</span><span class="nv">ok</span> <span class="o">=</span> <span class="nv">QFontDialog</span><span class="p">.</span><span class="nv">getFont</span><span class="p">()</span> <span class="k">if</span> <span class="nv">ok</span><span class="p">:</span> <span class="nv">self</span><span class="p">.</span><span class="nv">textEdit</span><span class="p">.</span><span class="nv">setFont</span><span class="p">(</span><span class="nv">font</span><span class="p">)</span> <span class="nv">def</span> <span class="nv">retranslateUi</span><span class="p">(</span><span class="nv">self</span><span class="p">,</span> <span class="k">Form</span><span class="p">):</span> <span class="nv">_translate</span> <span class="o">=</span> <span class="nv">QtCore</span><span class="p">.</span><span class="nv">QCoreApplication</span><span class="p">.</span><span class="k">translate</span> <span class="k">Form</span><span class="p">.</span><span class="nv">setWindowTitle</span><span class="p">(</span><span class="nv">_translate</span><span class="p">(</span><span class="c1">"Form", "Form"))
self.pushButton.setText(_translate(“Form”, “Color Dialog”)) self.pushButton_2.setText(_translate(“Form”, “Font Dialog”)) if name == “main”: import sys <span class="nv">app</span> <span class="o">=</span> <span class="nv">QtWidgets</span><span class="p">.</span><span class="nv">QApplication</span><span class="p">(</span> <span class="nv">sys</span><span class="p">.</span><span class="nv">argv</span><span class="p">)</span> <span class="k">Form</span> <span class="o">=</span> <span class="nv">QtWidgets</span><span class="p">.</span><span class="nv">QWidget</span><span class="p">()</span> <span class="nv">ui</span> <span class="o">=</span> <span class="nv">Ui_Form</span><span class="p">()</span> <span class="nv">ui</span><span class="p">.</span><span class="nv">setupUi</span><span class="p">(</span><span class="nv">Form</span><span class="p">)</span> <span class="k">Form</span><span class="p">.</span><span class="nv">show</span><span class="p">()</span> <span class="nv">sys</span><span class="p">.</span><span class="k">exit</span><span class="p">(</span><span class="nv">app</span><span class="p">.</span><span class="nv">exec</span><span class="p">())</span>
运行:
我想做一个带有图形界面的一个 Ping 的程序,提前准备一个 csv 的 ping 列表,三列,前两是名称,第三列是 ip,这个表启动程序自动加载,放入到到 QTableWidget 中,按一定时间间隔 ping 这些 ip 列表,把 ping 的结果放入到 QLineEdit 中显示,ping 通的用绿色字显示,ping 不通用红色字显示,并播放一个提示音。最后把 Ping 的结果总结一下,几通几不能。
设计好的界面如下,这个是直接用代码写的,不是用 Qt Designer 设计的。
执行结果如图:
代码方面,按钮 QPushButton,与动作绑定:
讯享网hbox_layout1 = QHBoxLayout() self.scan_button = QPushButton("开始扫描") self.scan_button.clicked.connect(self.start_scan) hbox_layout1.addWidget(self.scan_button)
加载 QTableWidget 的表,拖动窗口大小时,表格随拖动变化:
讯享网self.table_widget = QTableWidget() self.table_widget.setColumnCount(3) self.table_widget.setHorizontalHeaderLabels(["台站名", "测项名", "IP地址"]) self.table_widget.setRowCount(len(self.ip_list)) self.table_widget.cellChanged.connect(self.handle_cell_changed) self.table_widget.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) self.table_widget.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows) self.table_widget.setSelectionMode(QTableWidget.SelectionMode.MultiSelection) for row, item in enumerate(self.ip_list): station_name, measurement_name, ip = item #self.table_widget.setItem(row, 0, QTableWidgetItem(str(row + 1))) # 序号从1开始 self.table_widget.setItem(row, 0, QTableWidgetItem(station_name)) self.table_widget.setItem(row, 1, QTableWidgetItem(measurement_name)) self.table_widget.setItem(row, 2, QTableWidgetItem("10.23.*.*")) self.table_widget.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) self.table_widget.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) layout.addWidget(self.table_widget)
这个软件功能比较简单,先运行几天,再填加新的功能。
QPushButton 控件提供了一个命令按钮。
推按钮或命令按钮可能是任何图形用户界面中最常用的控件。按(点击)一个按钮命令计算机执行某些操作,或回答一个问题。典型的按钮有 “确定”、“应用”、“取消”、“关闭”、“是”、“否” 和 “帮助”。
命令按钮呈矩形,并通常显示描述其操作的文本标签。
推按钮显示文本标签,并可选显示一个小图标。这些可以使用构造函数设置,并可以使用 setText() 和 setIcon() 之后更改。如果按钮被禁用,文本和图标的外观会被修改,使按钮看起来 “被禁用”。
当鼠标、空格键或键盘快捷键激活推按钮时,它会发出 clicked() 信号。连接到此信号以执行按钮的操作。推按钮还提供了其他不太常用的信号,例如 pressed() 和 released()。
对话框中的命令按钮默认为自动默认按钮,即当它们接收键盘输入焦点时,它们会自动成为默认的推按钮。默认按钮是当用户在对话框中按 Enter 或 Return 键时激活的推按钮。您可以使用 setAutoDefault() 来更改这一点。注意,自动默认按钮预留了一点额外的空间,这是为了绘制默认按钮指示器所必需的。如果您不希望按钮周围有这样的空间,调用 setAutoDefault()(false)。
由于其核心地位,按钮控件在过去十年中已经发展出了许多变种。Microsoft 的样式指南现在显示了关于 Windows 推按钮的大约十种不同状态,文本暗示当所有功能组合都被考虑时,还有几十种状态。
最重要的模式或状态是:
- 可用或不可用(灰色,禁用)。
- 标准推按钮、切换推按钮或菜单按钮。
- 打开或关闭(仅用于切换推按钮)。
- 默认或正常。对话框中的默认按钮通常可以使用 Enter 或 Return 键 “点击”。
- 自动重复或不。
- 按下或不按。
一般来说,当应用程序或对话窗口在用户点击它时执行操作(如应用、取消、关闭和帮助),并且控件应该有一个宽的、带有文本标签的矩形形状时,使用推按钮。小的、通常是正方形的、更改窗口状态而不是执行操作的按钮(如 QFileDialog 的右上角的按钮)不是命令按钮,而是工具按钮。Qt 为这些按钮提供了一个特殊的类(QToolButton)。
如果您需要切换行为(setCheckable())或一个按钮在被按下时自动重复激活信号,如滚动条中的箭头(setAutoRepeat()),命令按钮可能不是您想要的。如有疑问,请使用工具按钮。
命令按钮的一个变体是菜单按钮。当它们被点击时,它们不仅提供一个命令,还提供几个,因为它们会弹出一个选项菜单。使用 setMenu() 方法将弹出菜单与推按钮关联。
其他类型的按钮是选项按钮(参见 QRadioButton)和复选框(参见 QCheckBox)。
在 Qt 中,QAbstractButton 基类提供了大多数模式和其他 API,QPushButton 提供了 GUI 逻辑。有关 API 的更多信息,请参阅 QAbstractButton。
QPushButton 是 PyQt6 中的一个基础控件,用于在图形用户界面中创建按钮。但要完整列出 QPushButton 的所有方法、属性和事件是相当繁琐的,因为它包括了从基类继承而来的大量方法和属性。以下我将列出 QPushButton 的主要方法、属性和事件,提供一个概览:
主要方法:
setCheckable(bool): 设置按钮是否可以被选中。setChecked(bool): 设置按钮的状态(选中或未选中)。setIcon(QIcon): 设置按钮的图标。setIconSize(QSize): 设置图标的大小。setMenu(QMenu): 设置按钮上的菜单(可以创建一个下拉菜单按钮)。showMenu(): 显示按钮的菜单。setDefault(bool): 设置按钮是否为默认按钮。setFlat(bool): 设置按钮是否为扁平样式。
主要属性:
autoDefault: 是否为自动默认按钮。default: 是否为默认按钮。flat: 按钮是否为扁平样式。text: 按钮上的文本。icon: 按钮的图标。iconSize: 图标的大小。
主要信号(事件):
clicked(): 当按钮被点击时发出。pressed(): 当按钮被按下时发出。released(): 当按钮被释放时发出。toggled(bool): 当按钮的选中状态改变时发出。
这只是 QPushButton 的一部分方法、属性和信号,它还继承了很多从 QAbstractButton 和 QWidget 等基类来的方法和属性。如果需要更详细或更深入的信息,建议查阅 PyQt6 的官方文档或专门的教程资料。
下面是一个使用 QPushButton 的例子,这个按钮具有以下特性:
- 按钮上有图标。
- 按钮与一个事件关联。
- 按钮点击时会弹出一个菜单。
讯享网# class AppDemo(QWidget): def __init__(self): super().__init__() # 设置窗口标题和窗口位置及大小 self.setWindowTitle("QPushButton 示例") self.setGeometry(100, 100, 400, 300) # 设置窗口图标 self.setWindowIcon(QIcon('https://www.zhihu.com/topic/icon/python.png')) # 创建并设置按钮 self.button = QPushButton('示例按钮', self) self.button.setGeometry(100, 100, 200, 50) # 设置按钮的图标及大小 self.button.setIcon(QIcon("https://www.zhihu.com/topic/icon/icons8-twitter-240.png")) self.button.setIconSize(QSize(32, 32)) # 将按钮的点击事件与on_click方法关联起来 self.button.clicked.connect(self.on_click) # 创建弹出菜单和两个动作选项 self.menu = QMenu() action1 = QAction('选项1', self) action1.triggered.connect(self.option1_clicked) self.menu.addAction(action1) action2 = QAction('选项2', self) action2.triggered.connect(self.option2_clicked) self.menu.addAction(action2) # 将弹出菜单与按钮关联起来,当点击按钮时,会弹出此菜单 self.button.setMenu(self.menu) # 按钮点击事件的处理函数 def on_click(self): print("按钮被点击了") # 选项1点击事件的处理函数 def option1_clicked(self): print("选项1被选择了") # 选项2点击事件的处理函数 def option2_clicked(self): print("选项2被选择了")
如果当前脚本是主程序,则运行以下代码
if name == ‘main’: 讯享网app = QApplication(sys.argv) demo = AppDemo() demo.show() sys.exit(app.exec())</code></pre></div><p data-pid="bdrIcDT2"><b>代码解释</b>:</p><ol><li data-pid="0DKbN_2g">我们首先导入所需的模块。</li><li data-pid="hUNdo7nu">创建了一个 <code>AppDemo</code> 类,它继承自 <code>QWidget</code>。</li><li data-pid="w9hSmWYu">在这个类的初始化函数中,我们创建了一个 <code>QPushButton</code>,并设置了它的位置和大小。</li><li data-pid="RfVWifvV">给按钮设置了一个图标和图标大小。</li><li data-pid="-ogN-aN5"><code>self.button.clicked.connect(self.on_click)</code>:这行代码将按钮的 <code>clicked</code> 事件连接到 <code>on_click</code> 方法。当按钮被点击时,<code>on_click</code> 方法会被调用。</li><li data-pid="j3VDcYJA">之后,我们创建了一个弹出式菜单,其中有两个动作(或选项)。</li><li data-pid="OQ8CYKd_">每个动作都与一个函数连接,当这个动作被选择时,对应的函数会被调用。</li><li data-pid="gBAj0jee">最后,我们使用 <code>setMenu</code> 方法将这个菜单关联到按钮上。</li></ol><p data-pid="IGcDoOli">当你点击这个按钮时,会出现一个带有两个选项的弹出式菜单。点击其中的一个选项,对应的函数会被调用。如果你点击按钮的非菜单部分,<code>on_click</code> 方法会被调用。</p>
QLineEditQLineEdit 是一个单行文本输入控件。单行文本框允许用户输入和编辑一行简单的文本,它提供了一套有用的编辑功能,包括撤销和重做、剪切和粘贴以及拖放(参见 setDragEnabled())。通过更改单行文本框的 echoMode(),它还可以用作 “只写” 字段,用于输入密码等内容。文本的长度可以限制为 maxLength()。可以使用 validator() 或 inputMask(),或两者都使用,来任意约束文本。在同一个单行文本框上切换验证器和输入掩码时,最好清除验证器或输入掩码,以防止未定义的行为。一个相关的类是 QTextEdit,它允许多行、富文本编辑。你可以使用 setText() 或 insert() 更改文本。使用 text() 获取文本;获取的显示文本(可能与实际文本不同,参见 EchoMode)可以使用 displayText()。可以使用 setSelection() 或 selectAll() 选择文本,选择的文本可以被 cut()、copy() 和 paste()。可以使用 setAlignment() 对齐文本。当文本更改时,会发出 textChanged 信号;当文本由于非调用 setText() 的原因发生更改时,会发出 textEdited 信号;当光标移动时,会发出 cursorPositionChanged 信号;当按下返回或回车键时,会发出 returnPressed 信号。当编辑完成时,无论是因为单行文本框失去了焦点还是因为按下了回车 / 输入键,都会发出 editingFinished 信号。请注意,如果焦点丢失而没有做任何更改,editingFinished 信号将不会被发出。请注意,如果单行文本框上设置了验证器,只有当验证器返回 Acceptable 时,returnPressed/editingFinished 信号才会被发出。默认情况下,QLineEdit 有一个按平台样式指南指定的边框;你可以通过调用 setFrame()(false) 来关闭它。默认的键绑定在下面描述。单行编辑框还提供了一个上下文菜单(通常通过右键点击调用),该菜单呈现了一些这些编辑选项。
setText(): 设置文本框的文本。
text(): 获取文本框的文本。
clear(): 清除文本框的内容。
setPlaceholderText(): 设置占位符文本。
isReadOnly(): 返回文本框是否为只读。
setMaxLength(): 设置最大输入长度。
insert(): 插入文本。
setPasswordMode(): 设置文本框为密码模式。
setAlignment(): 设置文本对齐方式。
text: 文本框的文本内容。
placeholderText: 占位符文本。
maxLength: 最大输入长度。
readOnly: 表明是否只读。
textChanged: 当文本更改时发出。
editingFinished: 当完成编辑时发出。
QTextEdit 是一个高级的所见即所得(WYSIWYG)查看器 / 编辑器,支持使用 HTML 样式标签或 Markdown 格式的富文本格式化。它经过优化,能够处理大型文档,并迅速响应用户输入。QTextEdit 在段落和字符上工作。一个段落是一个格式化的字符串,会自动换行以适应小部件的宽度。默认情况下,在读取纯文本时,一个换行符表示一个段落。一个文档可以由零个或多个段落组成。段落之间用硬换行分隔。每个字符都有自己的属性,如字体和颜色。QTextEdit 可以显示图像、列表和表格。如果文本太大,无法在视口内查看,滚动条会出现。如果只需要显示小段的富文本,考虑使用 QLabel。Qt 中的富文本旨在为应用提供快速、便携且高效的在线帮助功能,并为富文本编辑器提供基础。QTextEdit 可以显示大量的 HTML 子集,包括表格和图像。
- 设置或替换文本:使用
setHtml()。
- 使用
setMarkdown() 设置或替换文本。
- 插入文本:可以使用
QTextCursor 类或其他便捷函数。
默认情况下,文本编辑器会根据文本编辑小部件的宽度进行单词折叠。
- 查找功能:使用
find() 函数查找并选择给定的字符串。
- 限制段落数:使用 QTextDocument 的
maximumBlockCount 属性。 当然可以,以下是按照 Markdown 格式整理的翻译内容:
使用 QTextEdit 作为显示小部件的所有信息在此处也同样适用。当前字符格式的属性可以通过以下方法进行设置:
- 斜体:
setFontItalic()
- 字体粗细:
setFontWeight()
- 下划线:
setFontUnderline()
- 字体家族:
setFontFamily()
- 字体点大小:
setFontPointSize()
- 文字颜色:
setTextColor()
- 当前字体:
setCurrentFont()
当前段落的对齐方式可以使用 setAlignment() 来设置。文本的选择是由 QTextCursor 类处理的,该类为创建选择、检索文本内容或删除选择提供功能。可以使用 textCursor() 方法检索与用户可见的光标对应的对象。如果想在 QTextEdit 中设置选择,只需在 QTextCursor 对象上创建一个,然后使用 setTextCursor() 使该光标成为可见光标。可以使用 copy() 将选择复制到剪贴板,或使用 cut() 将其剪切到剪贴板。使用 selectAll() 可以选择整个文本。当光标移动并且底层格式属性更改时,会发出 currentCharFormatChanged 信号以反映新光标位置的新属性。无论是通过 setText() 还是通过编辑器本身更改文本,都会发出 textChanged 信号。QTextEdit 持有一个可以使用 document() 方法检索的 QTextDocument 对象。你也可以使用 setDocument() 设置自己的文档对象。QTextDocument 提供了一个 isModified() 函数,如果自从加载文本或自上次调用 setModified 并将 false 作为参数以来文本已被修改,它将返回 true。此外,它还提供了撤消和重做的方法。
setHtml(): 设置富文本内容。
toHtml(): 返回当前的 HTML 内容。
setPlainText(): 设置普通文本。
toPlainText(): 获取普通文本内容。
insertHtml(): 插入 HTML 文本。
clear(): 清除文本。
isReadOnly(): 返回是否只读。
setAlignment(): 设置文本对齐方式。
find(): 在文本中查找字符串。
text: 文本内容。
readOnly: 表明是否只读。
acceptRichText: 是否接受富文本。
textChanged: 当文本更改时发出。
undoAvailable: 当撤销操作可用时发出。
redoAvailable: 当重做操作可用时发出。
cursorPositionChanged: 当光标位置变化时发出。
下面是一个简单的文本编辑器示例,该编辑器使用 QPushButton, QLabel, QLineEdit, 和 QTextEdit 控件:
#d:/work/pyqt6/42/textEd.py class SimpleTextEditor(QWidget): 讯享网def __init__(self): super().__init__() # 初始化UI self.init_ui() self.setWindowIcon(QIcon('https://www.zhihu.com/topic/icon/icons8-twitter-240.png')) def init_ui(self): # 设置窗口标题和大小 self.setWindowTitle('桥然:简单文本编辑器') self.resize(600, 400) # 主布局设置 layout = QVBoxLayout() # 创建水平布局,用于存放 QLabel, QLineEdit 和 打开文件的按钮 hbox_layout = QHBoxLayout() # 标签 - 显示"文件名" self.file_label = QLabel('文件名:', self) hbox_layout.addWidget(self.file_label) # QLineEdit - 输入或显示文件路径 self.file_path_input = QLineEdit(self) hbox_layout.addWidget(self.file_path_input) # QPushButton - 打开文件按钮 self.open_button = QPushButton('打开文件', self) self.open_button.clicked.connect(self.open_file) hbox_layout.addWidget(self.open_button) # 将hbox_layout添加到主布局中 layout.addLayout(hbox_layout) # QTextEdit - 文本编辑区域 self.text_edit = QTextEdit(self) layout.addWidget(self.text_edit) # QPushButton - 保存文件按钮 self.save_button = QPushButton('保存文件', self) self.save_button.clicked.connect(self.save_file) layout.addWidget(self.save_button) # 设置主布局 self.setLayout(layout) def open_file(self): #options = QFileDialog.Options() file_path, _ = QFileDialog.getOpenFileName(self, "打开文件", "", "所有文件 (*);;文本文件 (*.txt)") if file_path: with open(file_path, 'r', encoding='gb2312', errors='replace') as file: content = file.read() self.text_edit.setPlainText(content) self.file_path_input.setText(file_path) def save_file(self): file_path = self.file_path_input.text() if not file_path: #options = QFileDialog.Options() file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "所有文件 (*);;文本文件 (*.txt)") if file_path: with open(file_path, 'w', encoding='utf-8') as file: content = self.text_edit.toPlainText() file.write(content) self.file_path_input.setText(file_path)
if name == ‘main’: app = QApplication(sys.argv) window = SimpleTextEditor() window.show() sys.exit(app.exec())
- 定义了一个名为
SimpleTextEditor 的窗口类,继承自 QWidget。
init_ui 方法用于初始化 UI 界面,其中定义了标签(显示文件名或路径)、输入框(用于输入或显示文件路径)、按钮(打开和保存文件的操作)和文本编辑区域。
open_file 方法使用 QFileDialog 来选择并打开一个文件,读取其内容,并显示在 QTextEdit 中。
save_file 方法允许用户保存编辑器中的文本到一个文件中。
- 注意,为了简单起见,这个示例在打开和保存文件时使用了 UTF-8 编码格式。
以上代码在 Python3.10.12 和 PyQt6 6.4.2 下可正常运行。
组建了 PyQt6 学习交流群有 2 个多月了,大家积极交流,现在有 200 多位参与者,群内高手云集,有很多都有成熟作品,让我们借鉴,让我受益良多。群比较松散,开放进入就会比较乱,现在进群只能邀请,如果需要进群,加下面微信,拉进群。群内会不定期发放些学习材料、代码、视频等。
代码下载后台回复 “QTextEdit” 获取相关代码。后面想加入互动环节,如果你在 PyQt6 的学习遇到问题,可以在下面留言,或者群内提问。写字不容易,大家如果觉得有用,写的还行,记得点赞,关注,转发,点 “在看”。 在知乎上看到一个关于 给 QTableWidget 分布的问题,之前的演示也多次用到过 QTableWidget 组件,试着回答一下这个问题。为了在 PyQt 中给 QTableWidget 实现分页功能,您需要结合使用分页控件(如按钮、标签)和逻辑来控制表格显示的数据。以下是实现步骤的概述:首先,在界面中添加必要的分页控件。通常包括:
- “上一页” 和 “下一页” 按钮:用于切换页码。
- 页码显示标签:显示当前页码和总页数。
在类的构造函数中初始化一些分页相关的参数,如:
current_page(当前页码)records_per_page(每页显示的记录数)total_records(总记录数)total_pages(总页数)
编写一个函数(例如 load_data),用于根据当前页码从数据源(例如数据库)加载数据,并更新 QTableWidget。为 “上一页” 和 “下一页” 按钮添加点击事件处理函数。这些函数应该更新 current_page 的值,并调用 load_data 函数重新加载并显示数据。每次翻页时,更新页码显示标签以反映当前页码和总页数。以下是一段简化的示例代码,展示了如何实现这些步骤:
讯享网from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTableWidget class AppWindow(QWidget): def __init__(self): super().__init__() self.init_ui() self.init_pagination() def init_ui(self): self.layout = QVBoxLayout(self) self.table_widget = QTableWidget() self.layout.addWidget(self.table_widget) self.init_pagination_controls() def init_pagination_controls(self): self.pagination_layout = QHBoxLayout() self.prev_page_btn = QPushButton('上一页') self.next_page_btn = QPushButton('下一页') self.page_label = QLabel('第 1 页') self.pagination_layout.addWidget(self.prev_page_btn) self.pagination_layout.addWidget(self.page_label) self.pagination_layout.addWidget(self.next_page_btn) self.layout.addLayout(self.pagination_layout) self.prev_page_btn.clicked.connect(self.prev_page) self.next_page_btn.clicked.connect(self.next_page) def init_pagination(self): self.current_page = 1 self.records_per_page = 50 # 假设 total_records 从数据源获取 self.total_records = 1000 self.total_pages = (self.total_records + self.records_per_page - 1) // self.records_per_page self.load_data() def load_data(self): # 这里应该根据 current_page 和 records_per_page 加载数据 # 更新 QTableWidget 的内容 pass def update_pagination_label(self): self.page_label.setText(f'第 {self.current_page} 页,共 {self.total_pages} 页') def prev_page(self): if self.current_page > 1: self.current_page -= 1 self.load_data() self.update_pagination_label() def next_page(self): if self.current_page < self.total_pages: self.current_page += 1 self.load_data() self.update_pagination_label()
if name == ‘main’: 讯享网app = QApplication([]) ex = AppWindow() ex.show() app.exec()
在这个例子中,load_data 方法应该根据 current_page 和 records_per_page 从数据源中加载数据,并更新 QTableWidget。prev_page 和 next_page 方法用于处理翻页动作。update_paginationlabel 用于更新显示当前页码和总页数的标签。2023 年 12 月 28 日写了 [# PyQt6 与 MySQL 合体演示:打造高效地震目录查询系统 Demo + 代码](https://mp.weixin..com/s/5gfLU-MyPO9JVf6O4v4qA“PyQt6 与 MySQL 合体演示:打造高效地震目录查询系统 Demo + 代码”),主要功能就是可以抓取地震目录,写入到本地数据库,并在下面用 QTableWidget 展示库中的目录,这里的目录有几百条,没有分页。
今天就是把这个 QTableWidget 加上分布,以做演示。在整个页面下部填加 QHBoxLayout,上面加两个按钮一个标签。
self.pagination_layout = QHBoxLayout() self.prev_page_btn = QPushButton(‘上一页’) self.next_page_btn = QPushButton(‘下一页’) #self.page_label = QLabel(‘第 1 页’) self.pagination_layout.addWidget(self.prev_page_btn) self.pagination_layout.addWidget(self.page_label) self.pagination_layout.addWidget(self.next_page_btn) vbox.addLayout(self.pagination_layout) 分页按钮事件
self.prev_page_btn.clicked.connect(self.prev_page) self.next_page_btn.clicked.connect(self.next_page) 初始化分页参数
self.current_page = 1 self.records_per_page = 50 self.total_records = self.get_total_records() self.total_pages = (self.total_records + self.records_per_page - 1) // self.records_per_page self.update_pagination_label()
两个按钮绑定上一页、下一页,设定每页 50 条地震目录,默认初始化程序时是第 1 页。
讯享网def prev_page(self): if self.current_page > 1: self.current_page -= 1 self.load_data() self.update_pagination_label() def next_page(self): if self.current_page < self.total_pages: self.current_page += 1 self.load_data() self.update_pagination_label()
更新标签:
def update_pagination_label(self): self.page_label.setText(f‘第 {self.current_page} 页,共 {self.total_pages} 页’)
获取总记录条目数:
讯享网def get_total_records(self): # … [数据库连接代码] … connection = None try: # 连接到数据库 connection = pymysql.connect( host=‘localhost’, # 数据库主机地址 database=‘earthquake’, # 数据库名 user=‘root’, # 数据库用户名 password=‘’) # 数据库密码 # 使用 cursor() 方法创建一个游标对象 cursor cursor = connection.cursor() query = “SELECT COUNT(*) FROM earthquake_data” cursor.execute(query) result = cursor.fetchone() return result[0] except Error as e: print(“数据库错误:”, e) return 0 finally: # 关闭数据库连接 if connection: cursor.close() connection.close() print(“数据库连接已关闭”)
修改初始化,加载第 N 页地震目录。
def load_data(self): try: # 连接到数据库 # 创建 cursor cursor = connection.cursor() offset = (self.current_page - 1) * self.records_per_page query = f“SELECT Date, Latitude, Longitude, Magnitude, DiMing, Depth FROM earthquake_data LIMIT {self.records_per_page} OFFSET {offset}” cursor.execute(query) results = cursor.fetchall() # 更新表格数据 self.table_widget.setRowCount(0) for row_number, row_data in enumerate(results): self.table_widget.insertRow(row_number) for column_number, data in enumerate(row_data): 讯享网item = QTableWidgetItem(str(data)) item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) self.table_widget.setItem(row_number, column_number, item)
# 更新分页标签 self.update_pagination_label() #self.page_label.setText(f‘第 {self.current_page} 页’) except Error as e: print(“数据库错误:”, e) finally: if connection: cursor.close() connection.close()
经过以上修改最终界面如图
翻页之后的效果
最早一版查询目录入库时没有深度,深度是后加上的,第一次写入库的深度为空。示例代码环境为 Python3.10.12、PyQt6 6.6.0,后台回复修改地震目录获取相关代码。
2024 年 1 月 6 日晚修改
背景
因为在公司中负责小工具的开发(数据处理 文件生成等),不可避免的会使用到Python的窗体界面,最初都是手敲出来的,费时费力,后来在网上百度了一下,发现一款比较好用的工具-QT designer,使用鼠标拖拽就可以完成窗体的设计,方便好用。
话不多说。现在就体验一下这个工具的强大之处吧。
1. 安装QT designer
这里需要安装两个东西:PyQt5和PyQt5-tools:
- 安装PyQt5:打开CMD或者PowerShell,在命令窗中输入
执行结果如下:
- 安装PyQt5-tools:打开CMD或者PowerShell,在命令窗中输入
点击查看代码
pip install -i https://pypi.douban.com/simple/ –trusted-host=pypi.douban.com/simple PyQt5
执行结果如下:
2. 配置开发工具
QT designer install完成后,在pycharm中进行相关的配置
File–setting–External tools—-点击 + 号进行配置
需要配置两个
- 配置QtDesigner,用来打开QT可视化开发工具
如下图,分别在Name、Program、Working dirctory填入如下信息:
Name:QtDesigner
Program:C:\LegacyApp\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe
注意:该路径为你Python安装路径下Lib\site-packages\pyqt5_tools文件夹里
Working dirctory:\(FileDir\)
- 配置PyUIC,用来将Qt Designer开发工具生成的.ui文件转换为.py文件
如下图,分别在Name、Program、Arguments、Working dirctory填入如下信息:
Name:PyUIC
Program:C:\LegacyApp\Python36\Scripts\pyuic5.exe
tips:该路径为你Python安装路径下Scripts文件夹里
Arguments:\(FileName\) -o \(FileNameWithoutExtension\).py
Working dirctory:\(FileDir\)
至此,安装和配置过程全部结束,下面介绍简单的使用教程。
3.使用Qt Designer设计界面
在PyCharm中创建一个项目,然后点击“Tools”–“External Tools”–“QtDesinger”打开QT Desinger,如下图:
在New Form对话框里选择Widget模板,然后点击创建:
然后就会出现Qt Designer主界面,向Form中分别拖入一个“Push Button”和一个“Text Edit”,如下图:
指定点击事件及其响应函数
在工具栏点击 这个图标 ,然后光标移动到“PushButton”按钮上,鼠标左键 点击 “PushButton”按钮 不要松开,拖动光标 到 按钮旁边的任一位置后 再松开鼠标左键
随后就出现了如下界面,在对话框左侧选中“clicked()”,右侧点击“Edit”
然后点击绿色“+”按钮,指定click事件的响应函数,名称随意,比如我这里命名为“pushButton_click()”
(这里只是指定事件与响应函数的关联关系,函数是没有实现的,根据业务自行实现)
最后,将设计的界面保存。
4.使用PyUIC将文件转成python代码
关闭QT Designer回到PyCharm,查看项目,可以看到只有刚才保存的untitled.ui文件在PyCharm是打不开的,我们需要将这个文件转成.py代码才能使用。
选中“untitled.ui”,在其上点击鼠标右键,到“External Tools”中点击“PyUIC”
之后再看项目文件,就可以看到多了一个“untitled.py”,双击查看其内容如下:
5.编写逻辑代码
界面与业务逻辑分离实现:这一步主要实现业务逻辑,也就是点击登录和退出按钮后程序要执行的操作。为了后续维护方便,采用界面与业务逻辑相分离来实现。也就是通过创建主程序调用界面文件方式实现。这有2个好处:
1.就是实现逻辑清晰。
2.后续如果界面或者逻辑需要变更,好维护。新建一个.py文件程序,在里边创建一个子类(MyPyQT_Form)继承untitled.py中的Ui_Form。具体代码如下:
讯享网import sys from PyQt5 import QtWidgets from PyQT_Form import Ui_Form class MyPyQT_Form(QtWidgets.QWidget,Ui_Form): <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="nb">super</span><span class="p">(</span><span class="n">MyPyQT_Form</span><span class="p">,</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">setupUi</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="c1">#实现pushButton_click()函数,textEdit是我们放上去的文本框的id</span> <span class="k">def</span> <span class="nf">pushButton_click</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">textEdit</span><span class="o">.</span><span class="n">setText</span><span class="p">(</span><span class="s2">"你点击了按钮"</span><span class="p">)</span>
if name == ‘main’: 讯享网<span class="n">app</span> <span class="o">=</span> <span class="n">QtWidgets</span><span class="o">.</span><span class="n">QApplication</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="n">my_pyqt_form</span> <span class="o">=</span> <span class="n">MyPyQT_Form</span><span class="p">()</span> <span class="n">my_pyqt_form</span><span class="o">.</span><span class="n">show</span><span class="p">()</span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">exec_</span><span class="p">())</span></code></pre></div><p data-pid="Bw-ms-18">至此,第一个Python界面的设计完成,运行效果如下:</p><p class="ztext-empty-paragraph"><br/></p><figure data-size="normal"><img src="https://pic4.zhimg.com/v2-02257a1d22c084c8a80c812dc02bbf3b_r.jpg" data-caption="" data-size="normal" data-rawwidth="824" data-rawheight="326" class="origin_image zh-lightbox-thumb" width="824" data-original="https://pic4.zhimg.com/v2-02257a1d22c084c8a80c812dc02bbf3b_r.jpg"/></figure><p></p>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/152173.html