在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 565807 点 威望 12 点 阅读权限 255 积分 174965 相册 1 日志 0 记录 0 帖子 5313 主题 5273 精华 3 分享 0 好友 163
TA的每日心情 开心 2021-8-11 17:59
签到天数: 17 天
[LV.4]偶尔看看III
网络挑战赛参赛者
网络挑战赛参赛者
自我介绍 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
群组 : 2018美赛大象算法课程
群组 : 2018美赛护航培训课程
群组 : 2019年 数学中国站长建
群组 : 2019年数据分析师课程
群组 : 2018年大象老师国赛优
超全!Python图形界面框架PyQt5使用指南! & C0 Q9 b! ^; ]( B' s" W
: k6 s! j' ~% l. D- U
使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。
O0 O' }, @. {. c " h3 i N! \& p" R# w; F6 S
常见GUI框架
/ l$ I7 |: n2 ?. d5 `3 N* V % t* }6 \' h) Z: z; e- G
PyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。# \1 Z0 A, r& `1 ?) }
( p- P0 @# e, d8 h
Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。5 Z" H$ Z% }& y: r' ?
( n8 n8 T! s7 e Tkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。. `9 r0 v, V2 @5 v4 P7 ?& C+ l7 k
, `" d. W5 ~- d& S5 ~" g/ q
PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。9 q8 Z9 t0 R5 Y& g; V
( c8 q8 x1 l7 ? WxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。
5 n8 `: O+ b, K. W$ i # U7 W, G/ U+ c# J2 d8 Q; W' C1 I
Wax:基于wxPython ,为克服wxPython的问题而制作的一个包。
* _2 A! E& Z# ]3 i: E' J, n
9 |) b- W# ^2 U0 p6 s5 k$ W2 u& ?0 C Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。, n! P, J1 A* j7 T7 U4 S7 K
9 W& \% Z9 i- L0 T BeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。* L2 h" `: L4 }; A
$ h: p) F3 r* Z
Toga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。. L1 W+ G( c. f/ e/ p
/ b3 x' p! h% p v! S. @( T Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
" U+ r. y: y& O$ h
4 ], ^$ v% F( Y: Y) C) v- q Flexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。- }( y0 \" U5 p; E) T! l p
. }* h8 k, V' J( F( ~* m& \
pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。2 O- h8 r/ I( P: _
9 n. f% }7 G1 R enaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。0 i1 X) c! d1 F
% S5 m8 y n" ^( i1 k; }- C
个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。
4 n3 L2 Y$ B4 A
9 d$ r) z/ l8 L: ^* a% P, ]: t PyQt5简介$ y$ i; X- V9 ]' Z3 @! F! @; H
5 `8 s) {( A* y! w4 G5 S
PyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。
. y3 S/ @+ {0 z! F- q8 d
0 ?( ]! k5 H9 c. {5 j# n2 o PyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。
0 b' u( K# Q% k! p, _$ o 7 A9 u8 ~0 v$ ?" `, k9 K
PyQt5特性如下:; f: ]2 {7 V: `& U- B: d2 j8 b
* g9 j% b+ y3 t Q$ \ b
基于高性能的Qt的GUI控件集。0 c" V* o+ B* M5 u5 v; x
, v5 q1 l3 l$ h
能够跨平台运行在Linux、Window和Mac OS系统上。
8 b0 n1 l; p! @ H0 R, ^) E4 E! K
使用信号槽机制进行通信。
1 y3 {0 g5 K" y1 q5 g$ l ' Y/ z, L% j: Q' n
对Qt库进行完全封装。
3 C) p( J6 Z( u% ]7 J) n6 Z
# ~' z8 n! x7 F 可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。
9 k* v% C* }; G6 ]4 A* c! \4 | ' T# o( O: y0 W2 j) K
提供一整套种类齐全的窗口控件。) R" K7 \4 T8 j* G- B- _
2 v% M( J' c# ~, a8 I E
PyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:" u$ n( F# G' X/ s; b/ n) u0 _7 N
+ [4 q& w. {% J8 `9 O QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。, i, z; b; V0 j* `# E
9 v1 m' d7 T7 m9 t' k% ?: @8 ~, `0 ~
QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。: `, I: ^/ D r! a( i" ~
# x. j# |* x$ u$ \1 h QtWidgets:包含了一系列创建桌面应用的 UI 元素。
9 }4 I4 c! f/ b: ~6 n3 u, P # \0 g! _9 q' @2 V; ^- B; o
QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。5 i% }) w# X+ m' }
' l7 W. U4 A5 l+ J R7 G QtBluetooth:包含了查找和连接蓝牙的类。
$ Y2 G2 _* g! T$ n v7 S, s+ V) e ; _$ P* k3 z# l L# }
QtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。" `- }% d; m6 ?8 e7 X0 |: j+ S
/ b# S* M1 G5 x% E5 V
QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。
3 `- N) L2 T. ~- `; i # M1 O7 f Z9 n* R
Enginio:包含了通过客户端进入和管理 Qt Cloud 的类。. s% y! w1 t! f3 w. G& O
, e* [4 A* S# y4 r QtWebSockets:包含了 WebSocket 协议的类。5 P/ _ J1 {* O/ m S: A6 s0 U
3 i6 u H2 D' M: m" W QtWebKit:包含了一个基 WebKit2 的 web 浏览器。
. b2 [8 j+ F0 o7 s3 }6 `4 J
0 X+ U" D) L2 B; F# E QtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。- @* c$ ~% \& ]6 ]6 l, Q q) z" k
8 G! Y' Q8 B( F2 Z: R9 o QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。. W% h5 V( Z% Y
4 n) k. w! H. X/ x! T- T! x
QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。& G. L' }1 u4 [8 ?/ L
! J$ z$ ?% ?* @1 E# J. | QtSql:提供了处理数据库的工具。
; k8 U% X+ k7 [+ i
4 ]: k/ [8 |/ K+ [0 H) V QtTest:提供了测试 PyQt5 应用的工具。+ M) z# u/ N; ?5 h# D" K- G
. z6 b, ~# b {0 ^* Z PyQt5的安装
9 o7 {1 p8 u) t4 d ; q, r6 Q) ^' m/ {# T( G
由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5
d% d! \2 g( y B+ L & b# {: q4 Q0 D7 @0 M) U
安装PyQt5' V2 i' c O# f: L
# A- B5 q: M, y/ r8 k7 U% C
pip install pyqt5) K& v+ g6 o. r7 E" w/ J( H8 F1 S3 X
, Q# }7 L- s+ ]6 Y u pip install pyqt5-tools& j" g+ U- e, E. Y5 e" Q
其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
3 g9 k+ t! |0 ~8 z5 z& I
- X+ G# {, F+ N2 u qt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
/ Z* d3 o* H. K7 C+ Z; T 解决方案:
1 j5 D% b+ N) ?: G3 M4 f
6 v: ?" }* S" {: j [; M pip install click~=7.0& q1 W) `/ Y/ x2 c
Qt Designer的配置
; ?( R4 x0 V4 Q/ m2 H y9 R / }$ M3 o8 S/ X) y
Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。3 r4 |" U4 U) x' f* g' H. `0 |
$ z1 _) `" B4 Y+ |' P( u7 H- c
9 t+ Q! @1 X/ x ( u$ g" Y' ~5 f" e3 B7 A' W3 k
整个画面的构成:
, R) |( e# |3 P# S1 ~/ V( ~ $ j: D) B6 Z. f! \. U3 ^
左侧的“Widget Box”就是各种可以自由拖动的组件
/ C6 Z, Y0 k' [7 a* r) A- g# x 2 i1 A; E7 p* D4 ` X- Q
中间的“MainWindow – untitled”窗体就是画布
9 [. A9 N n& K. p$ m- u : R- x# o) S* M8 \/ W
右上方的”Object Inspector”可以查看当前ui的结构) A2 }6 X7 O: W/ m7 S6 }& H& o
$ N) d2 z6 k/ G4 o5 X+ O
右侧中部的”Property Editor”可以设置当前选中组件的属性
+ ]% c$ I1 S1 M* Y& E6 @# O- I
( |5 O5 [5 o" w2 G4 f 右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等# [* o2 e+ l, c# [
: a1 c& I) c1 r8 l9 M$ E
最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。- ~; g5 k5 P, ~. i8 O) c2 S
( t" |4 n! K; ?- J3 X/ M9 p QtDisigner配置, ]( G2 S1 U0 M
3 ^: o8 A) e* c) n; n9 l4 T" g. Q, g 在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
1 u5 t1 V' Q9 h3 Z( ` ( B4 k; ^, {$ U' U+ H% ]0 ?% d
Name: QtDisigner
9 y+ g! c8 f1 I) Y4 H: x
% E8 S2 j2 Z4 a$ E2 J; o- D Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改; U E+ X8 ^& f9 Q2 G
3 v) S" N0 w- C Working directory: $FileDir$
" v( Z4 X' Z3 @ PyUIC配置
3 }5 h, {1 I2 ]* \3 P. s
& d# p( U) N" q$ \* w PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。5 p) {9 d. F$ l; N
* E& K K" t& k+ }9 {# Q/ Y6 Z
在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:8 Q1 W7 J5 H& v6 \3 f2 E8 z
3 e7 T1 J, d* B+ v
Name: PyUIC# h: C& b' q2 u2 \2 e. l
G; A3 [% w# j5 P( X: H" L' t* b+ ? Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改
0 F- Q2 Z" L& Z/ w ) V/ g. P' F. x, R) I4 C4 |8 I
Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py% A" Z9 I& i7 ^0 y% ?
3 r) ~8 o- Z+ J! R) x: d
Working directory: $FileDir$
; |/ Y2 `) t' [ PyRCC配置+ B8 c' |3 A6 A2 M1 ]; P1 G
" e o% b3 [ ^9 _
PyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:! b+ c' `! F! w0 {& O6 _( i( L# o3 j
% ^0 u5 P$ `5 H2 c! S# m# x Name: PyRCC
7 E) C2 p N$ a. J1 i8 l & H3 O6 F Q3 U i
Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改* r1 c: i+ x5 d2 N
1 m( G% |2 u0 d2 J1 _
Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py/ |6 w1 H1 ?3 z5 y
/ M- A; j3 { X( s Working directory: $FileDir$& q+ |; J7 s; N0 l6 M
PyQt5使用示例
1 O7 p5 e7 A5 r
6 f: h9 i# R; }/ l' f& g 创建一个空白的界面:8 {* c# y- y7 o9 a9 F3 ~$ {4 Y8 \
: Y( v5 ]- `" d' Z& _4 U3 h. J; ~ import sys: j* n! S3 G l: _
& u( o; u ?' [5 [3 ~9 a G- I
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel; P* M7 u$ d7 A) b& h* b" [ ~
2 b( A" Z3 N# A$ d' @ app = QApplication(sys.argv)
( f5 _3 P* N- I3 C$ y; l
$ ]: g# T, d! m0 J4 n, u2 q win = QMainWindow()
- G! m0 y. l& B) {# H
" {: K% ~! u# t& i) H/ x9 _ B win.setGeometry(400, 400, 400, 300)
# }6 p! w( Z* A2 Q- J + s9 C' |3 g. V4 e
win.setWindowTitle("Pyqt5 Tutorial")- }$ k; i4 E: m$ [. Y
# E2 }$ [7 t- e7 z
win.show()9 G' \% w" W9 O7 B8 |. j
6 V! T S- |! l- d8 _. |8 e sys.exit(app.exec_())
! y# X4 Z9 L2 r2 I, l 5 K' w9 C# j/ g) _: }
1 R5 E; D6 @. \4 @9 c6 v
2 v$ H) p9 G1 h) m) A }/ V 其中:
' q3 G2 q! P ]0 Q% g) Y- Q
8 f r# V7 N6 L5 k, L; G. d Qapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。
( j4 O$ ^& M' Y4 \4 g7 ^+ B" i
" k7 n9 Q: z8 `) A QMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。
% [% x2 v$ T7 V5 T
H" j( K, }4 r* M, E' S% m5 s SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。
8 e2 R" A% |% V- |. U. H" q1 h ! Z) p7 o8 B7 M; f- v' D2 ]2 F
show():用来显示窗口
9 ~( L7 s8 J U/ o
8 g+ q9 e' C$ l4 a3 v& Z: s2 ~ exit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭6 s7 s0 B$ j& a! J% B' {+ H& r
7 v8 s- W" f# h$ ^$ Q6 Z2 i8 M
PyQt5支持的常见Widgets有:: F- A2 K2 ^" {/ A: J3 `" \7 s
0 b; o3 W4 _6 D4 @1 `4 k
$ l+ r9 m4 l n% g
& b+ S+ Y, N7 g& j2 v 从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar6 j8 @/ q( {) \ X4 |
, V; u0 E; u; P
对于使用Pyqt5设置文本内容,我们使用Qlabel:
& W6 ^7 c. G: m4 @2 u
4 u3 o7 r! n% o2 z4 ] w& K, g- f import sys& U) ^& r: b; g/ `4 }
4 f* n1 [1 ~% k from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel" b, \. }, Y& v5 j+ @' e
, P8 X" s+ g9 u& N' f
app = QApplication(sys.argv)3 ^% q7 _4 z$ w0 F- q4 u- B
& J* f4 Z# r% q0 l win = QMainWindow()
9 \5 [) S2 \' z2 t0 M, t% R % b2 ^7 |( T7 K, T& ]! S( K
win.setGeometry(400, 400, 400, 300)
! Q. \! u3 E% d7 q. ^ k 0 p. w1 E) V% w' J$ ~/ T) F& B7 \
win.setWindowTitle("Pyqt5 Tutorial")
: j+ r2 x& I; P# {9 A
$ r4 ]0 m0 F* m \# Label Text4 V& j& B6 t" ~2 ^ \1 K( [
+ ~6 \" @+ J7 j. a8 Y: G6 ^4 e label = QLabel(win)2 X" g, H: g+ M8 D# k8 w
2 g0 M% d- _' N: @' ?+ j9 \ r label.resize(200, 100)/ s( j8 ^9 V- E
' z7 t" V# M8 s' O k
label.setText("Hi this is Pyqt5")
# Z) ?* f4 m& v4 u1 j 8 O- P% b6 a7 Q- t: s4 f3 E, C
label.move(100, 100)
0 m! O/ z# |+ I
& c3 ~ \+ d& f, q# C win.show()8 O/ Q% y6 c3 o% v. T( M2 E6 j
( p; F: T* r3 t, ~
sys.exit(app.exec_())
$ R+ M* V7 H$ `& L ) K1 m' Q1 x3 `+ U4 `
/ }1 ^$ P1 e/ d
N0 z: ~% ~& |; C 按钮与事件:
7 B0 i! Z6 K1 J: v4 ^( s
+ ~3 u8 u: H; C/ ]/ h" G; \ import sys" m. z9 D8 X# |% E+ L4 p
e2 I6 x4 V9 X# D/ X; a from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
! Q d% \3 k3 _' \2 h; D, i/ S / J1 p& ~% ^% b( l+ E
def click():
9 U' ^0 ?8 |% U Q& W( v, j/ \( O 6 Y9 {# v0 S7 O! x1 B
print("Hy Button is clicked!")" E1 p. ~" b! X5 s9 t
4 j; R' p& s) m app = QApplication(sys.argv). _$ u* M- V- z) k3 V, `
^4 m# U! z( s3 c& f7 z2 \
win = QMainWindow()
, F1 S H/ ]! Q( I7 Y9 x3 l
2 t' \* d+ M4 [0 q# d win.setGeometry(400, 400, 400, 300)
5 \" {( ]+ d) |9 x4 e5 J& F
" A- }$ p' V9 [* j' @5 P2 C win.setWindowTitle("Pyqt5 Tutorial")
5 E6 ?, C+ p1 p& X
i$ p2 M& P" W, s9 i- E6 o, a \# Button
7 j/ D: ~: G5 j4 \6 U0 X
/ t, N: s2 U5 Q7 ^# e button = QPushButton(win)
0 j" N' ?+ K5 n 8 R( R/ n+ d5 Q9 P4 r9 A V
button.resize(200, 100)
2 {! j9 q- j8 G$ g5 T7 h ( H1 U4 t# u: y* _. y3 J6 s6 V: Z
button.setText("Hi! Click Me"); W9 Z$ z" Y( ]. v' C. `+ v
" X$ h8 C; U' H3 k ?
button.move(100, 100)
$ ?% P; x7 n; ^* B. v# I
2 l# [7 Z8 L ^ button.clicked.connect(click)& [/ c* r4 U; b) W) ~( r/ Z; l6 z
, [0 W3 B# ~$ R% n0 t B- A. r
win.show()
9 [: m$ b h; c g* P8 @
4 |, E* O$ y% U' P: m: e sys.exit(app.exec_())
" n1 q1 [- C. Y( s9 Y
* U1 _& k* ^5 e+ z [/ F
9 {- ?% ^! w* Y% J2 p ; l, D; D ^5 ?' ]0 R" E O* ?; m
button.clicked.connect() 在按钮点击后执行特定的事件。1 Q3 }: H+ h8 V
1 I& t$ [+ A7 @
PyQt5实战 F* o3 N" c. p% A! s# U
4 u4 N- A8 Q3 I# t5 @ 实战项目:简易的天气查询软件
% N/ v3 s9 Z9 @/ X % W& z0 n# V$ _! ^9 R4 `# i
1、使用Qt Designer设计一个界面1 d/ r% y/ U. t; }9 s
1 P; b; @( H- |6 B# j
# P" z V! E: O! x
C% u; O' {8 I7 d" R5 E' J 用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:1 ^2 \- s5 w! |! Q8 [+ y6 I1 B: {
# O8 r, C7 D2 p: I8 Z: z4 P1 o6 e 在Qt Designer右下角选择 信号/槽编辑器,点击+号新增: @/ v( v' E5 G" G* ?8 \
+ `5 s$ I) k) r 分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)/ W+ g4 B' q' H' i1 O
y5 v* h; @4 k8 e& M9 A( R; U; x
以上完成后保存为Weather.ui文件。: S- Q2 y- A* a% C
: m# m7 I3 `/ ^0 q
2、转换.ui文件为.py文件+ F/ X8 c/ B. U) D$ }8 Y& }. B
. }: b) e9 _! R: C1 ^ {
PyQt5支持直接使用.ui文件:1 O0 a- A+ d0 i) [2 Q
% c# @: J" t" j9 R import sys9 p, t/ `3 J+ _" _- S9 a1 u, C$ y
- q. X2 Z6 h) H# e from PyQt5 import QtWidgets, uic
# H4 B- C) H7 ~" C# G 7 r, g. L7 [$ K; H6 `
app = QtWidgets.QApplication(sys.argv)
# b2 A/ m6 h0 b! O 5 w1 }* h% f- G( m( L1 l4 e8 A
window = uic.loadUi("mainwindow.ui")
5 `; y/ H5 [& Y
) C. |- ~6 m2 r7 k6 X' P window.show()
5 }6 Z. _$ L! ^3 `, Z A7 o$ `# k , O$ t, b4 {8 ^; ~
app.exec()
9 ^2 G T! {3 @4 t& D5 }* j 但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:7 L0 o b. o, P+ F0 u# E% v/ ^
# x' k! D1 i/ r: E
D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py6 i! w) e4 E% D, o4 ]: ]" w
其中,我们需要把两个按钮绑定的槽函数:
5 N* _& W0 L( O# [
/ W# P: {. W( j& _4 ? \# self.queryBtn.clicked.connect(Dialog.accept)
) {2 B* K5 ~# E' n( [) S
. h+ p# ^8 Y, O \# self.clearBtn.clicked.connect(Dialog.accept)
9 J) x B0 M* E% A( t- M9 N K
" C% l, s& t) f \# 修改为:
3 l+ q+ R8 A) T& m2 u ( E) c; ^( L+ O: U9 }
self.queryBtn.clicked.connect(Dialog.queryWeather)+ X/ T2 Z' o; j s/ F1 i4 v
& ?' g; Q& d1 H+ y- I. S6 p
self.clearBtn.clicked.connect(Dialog.clearText)
3 }) K6 a: D0 O 最终的Weather.py内容如下:
; Q4 R7 l" N; _* i; d a 4 c) x' ~- n+ x/ i, z7 U
\# -*- coding: utf-8 -*-
8 q7 \% ^4 G# S( k! O `
# V ?+ l# j' B ?% {. z4 T' E \# Form implementation generated from reading ui file 'Weather.ui'% s% w& |; H. L+ k& S
7 S# S2 c: v/ S. P7 M6 |* I8 T! x6 W
\#
. @( K: V- P: Y
4 p( t' I6 \( z- C0 \" c; w+ x \# Created by: PyQt5 UI code generator 5.15.43 U" f: n1 x. w4 z( o
; x% R- Z$ m0 h a \#0 Z# O4 |( D$ b+ L
1 f8 r, O; y# g" h/ a \# WARNING: Any manual changes made to this file will be lost when pyuic5 is
7 ^* q. s) x$ L# F0 g. G9 z
, _! K% b- M- V. ]2 T \# run again. Do not edit this file unless you know what you are doing.0 O' e1 f- S9 Y! p# l+ @
- J/ p5 e3 d9 x" ]* d( P
from PyQt5 import QtCore, QtGui, QtWidgets& T3 |( \8 l }1 l/ D! i" q
, U" b( f$ G6 O
class Ui_Dialog(object):
; l) v {3 s6 v# m ) Q$ q" ^' k: t( O0 ?
def setupUi(self, Dialog):
; g/ u2 c1 h! P a3 V% W: W8 i 9 E8 c- w( A5 ]' r( g% p' _
Dialog.setObjectName("Dialog")
7 m5 q- X. u7 Q" t; t
: {' p4 t M9 C# W9 f7 S' k Dialog.resize(600, 600)
' A7 ?. c ^: K# P- D# d
; v( T2 F$ y9 V8 Q self.groupBox = QtWidgets.QGroupBox(Dialog), h5 j, a! e: _ x; @2 p, ~5 L
6 R6 m3 ~0 m1 \$ ]
self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))
! |5 ^$ p8 d1 E
& `. |) U, A( M' X self.groupBox.setObjectName("groupBox")# i; m& O5 y6 [ Y! t u4 X
( u1 O/ L# A- q6 t) ^5 M4 J5 j
self.label_2 = QtWidgets.QLabel(self.groupBox)
: O" C9 l! O" |; |- C6 A
! m% d- v" m' x: ]3 t0 z | self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
9 Y& Q7 `* E) o/ n 6 Q |4 I: H* M( x' g
self.label_2.setObjectName("label_2")7 V" V" t7 d {2 l8 N/ _; x/ R
/ R6 y. b3 B. ^5 | self.comboBox = QtWidgets.QComboBox(self.groupBox)! z- I, g9 G; {1 y
6 S- ^: }# @ h
self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))9 `; }" z" i1 d) x
. a. Y7 g5 D0 t) K e1 l" m& B self.comboBox.setObjectName("comboBox")5 u8 ~, n# x# _9 t2 o' h+ \2 _! E
, t& M0 ], M. x7 [9 Q8 ^; n# e! C self.comboBox.addItem("")
5 q1 ?+ I8 J& G/ T% M1 m& E
8 ^" ]! ?# m% Q0 |4 }2 O' m self.comboBox.addItem("")' r9 p8 t8 W7 F/ h( z6 H
+ P# `, X: y- q* i
self.comboBox.addItem("")$ ~( y1 C) J) c z: ?
7 J0 S: q( U# I5 _4 R5 x
self.textEdit = QtWidgets.QTextEdit(self.groupBox)
3 e! X$ S8 R9 \4 |7 Q8 d' }
4 c- @& l! O" K4 q self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))0 T$ g) @( @7 [, [/ t
, a8 T/ ]: m8 `! u) a; I( _/ U
self.textEdit.setObjectName("textEdit")
8 Q; j' ?% }6 ]: R+ g4 k
* r4 C$ w% G7 K self.queryBtn = QtWidgets.QPushButton(Dialog)
4 K4 r$ ]+ y- ~ 5 T7 [0 G3 r* o2 A% j; b
self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))6 I) T i* k* H0 a
( ^, S$ p- X/ l2 ? self.queryBtn.setObjectName("queryBtn")
" C1 c# m2 w. K) G
' I# G; g: L) ?$ D- V+ E self.clearBtn = QtWidgets.QPushButton(Dialog)
6 {" p0 S) q" M2 e i1 H. i6 T& o1 m
self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
# h0 e; c7 F- [6 S; ^/ L$ W8 p 2 J! \( n4 ]: e. i% f$ y
self.clearBtn.setObjectName("clearBtn")
3 [% P% ~! {5 E) p+ C+ I " [. a) e0 X: u0 P& o; a9 e
self.retranslateUi(Dialog)& s. M" g' j' P$ x
+ D1 I# y2 {! t2 e
self.clearBtn.clicked.connect(Dialog.clearText)2 ~" v& W/ m* N7 ^0 y4 m/ X
7 @# C5 W! B$ g: H' `( k" H/ i
self.queryBtn.clicked.connect(Dialog.queryWeather)
1 R" R4 j: \: K& V) Z( P" K
9 M6 L( x, a# N/ a+ u7 y QtCore.QMetaObject.connectSlotsByName(Dialog)
2 H( l$ q: f, d2 ]& z V6 q
4 T3 n4 i: N- }& }6 _ def retranslateUi(self, Dialog):2 A2 b2 \& Q: E. | d5 Y
) C) |5 R2 o7 N _translate = QtCore.QCoreApplication.translate
% J% O: q7 [$ o0 K7 B
6 R0 ?7 b$ U% J& ^ Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
$ Y, J- Y6 A* y4 X3 M * y U B, y) s7 G
self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))
0 d/ C) r2 S/ w7 n, L" B4 b2 r* A 8 t/ v* a9 x& q
self.label_2.setText(_translate("Dialog", "城市"))
Z) f8 g! i4 q+ o 4 z8 M" T* ^2 i5 L) f* g
self.comboBox.setItemText(0, _translate("Dialog", "北京"))* @# v$ H8 o8 S0 l
& w0 s9 k& W! M; j: o0 [0 K self.comboBox.setItemText(1, _translate("Dialog", "苏州")) H F( d: |$ Z
8 n$ v7 I3 |! u! I9 F, Q self.comboBox.setItemText(2, _translate("Dialog", "上海"))# ^3 B e0 [ o' P; ?1 P6 e8 _
' H& y) @+ h9 n3 C
self.queryBtn.setText(_translate("Dialog", "查询"))4 T. Y$ m/ R" u- B+ F! x3 h- ^3 N, d
" I* s+ q9 y0 A5 N
self.clearBtn.setText(_translate("Dialog", "清空"))
2 r. F, n9 q/ i! \1 n
7 D+ b% M; ` V 3、调用MainDialog
2 w: y) `0 R; w; @3 c
# a, Q9 V; i, v 在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
0 M# ^3 v4 |9 a' m! U( [4 f " \. h6 `1 |' }/ g2 L3 k
完整代码如下:4 ^! f% v8 ^9 E- X' s5 G
& R7 ~9 q! i2 [- F
import sys
, f( i* \4 ^ s/ W* s4 K/ z# n
7 }7 X4 u- B6 Y import Weather9 G2 q1 z3 \: }+ Z" ?
}* Z/ ^( O- L% q0 C: ]
from PyQt5.QtWidgets import QApplication, QDialog
{1 k4 Q$ v3 _1 T& C' |
+ \6 R9 I, G/ l- P import requests
% Z7 @* x! L F& n0 \" s6 ]
3 ?3 _0 B! r/ Z6 k class MainDialog(QDialog):% @. A D, W- G Q& m I) Y- m
3 ^2 Q3 j0 F2 c9 U; g. J, O def __init__(self, parent=None):5 }* o$ X. p: D9 H
- k" s3 C( e) `" @1 l
super(QDialog, self).__init__(parent)
% p, ?8 V8 V2 r3 o2 p( g7 }
) d8 e* W: o- D0 z- ^6 I6 x self.ui = Weather.Ui_Dialog()
8 u$ {* s4 ?/ P( j7 l
- X+ E. y, o! Z' t* x self.ui.setupUi(self)2 h) W1 c! a6 Z3 H1 ]! V% r
9 G$ f7 q6 e% x4 [- J6 }& m9 Y7 I
def queryWeather(self):
' ^$ p h1 t# Z$ `3 j
; _: r6 K# z' w/ ~. c- V \' }2 ] cityName = self.ui.comboBox.currentText()
) t; b" N8 O3 I# x8 O1 m& h
( O- _2 C' S3 R8 }' k3 k5 G0 i cityCode = self.getCode(cityName)
$ w& f! b6 t+ k0 K+ o/ @( o7 b& ~; ^
$ w3 }+ @* T0 n% ~ r = requests.get(3 L4 e/ U! A' ?9 v/ V+ c
" W" _+ ?3 S* c
"https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(7 E) b, j! [$ Y* s$ R! v# D! ~
8 h- O5 K, y6 ?# T! o; g2 U$ q cityCode))7 K% x" U3 {4 W9 N6 y, v( `7 \
2 i7 R* g) T0 z: L2 ?/ u5 ]
if r.status_code == 200:0 T) L- w n$ t0 t
h1 M* T9 r8 e, S" X* }: ~ data = r.json()['lives'][0]$ g9 S, H$ {7 e( Z2 ]. s4 k# `
" N; H9 X: ?9 Z- C/ S% {3 k& \% Q weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(, W# U% F- s- s4 b' q
: ?1 j2 A. ~6 i- }4 m! l& M4 s, K data['city'],5 c( z3 d# }1 |7 c8 l! f
5 [4 k4 A" m& z) e" ]6 s
data['weather'],
& i: a9 J! Z( X) p! ` ( \3 |: C: A* @. B0 X2 d
data['temperature'],
6 d a7 d: e1 M/ ^ " p' e" O9 q6 `3 E' F- Z
data['winddirection'],
8 F( Y% G0 T3 u, ~4 G" |3 h7 N
2 W- S0 Q9 x. m# W, u data['windpower'],
1 o! ~8 o+ G" h; ~5 p 3 X9 S/ w9 L3 S3 Y1 r! E
data['humidity'],
; _1 H# B+ n1 t' |
|6 g& _: H7 c6 s data['reporttime'],1 ~2 \2 Z* w! b7 c: @, o- o. M
! X% ?! r. X. `7 y* J5 O' ?
)
% \" \1 t. V# A" L+ Y4 i- K ; h& |4 L3 p, a4 h8 ]
else:- o- O2 k1 }: i. a5 ]
* O4 g0 c6 o' C0 L+ L. H' D weatherMsg = '天气查询失败,请稍后再试!'
e7 F# g, r9 h8 Y/ a " {2 T1 r4 H, J# m+ ]" I
self.ui.textEdit.setText(weatherMsg)8 @0 Y$ V8 x5 y1 B4 C6 o
4 v* P! X& I* f6 `
def getCode(self, cityName):
2 [, K3 Y. i6 J7 G
; [, Z% q; U- W2 h/ I3 f cityDict = {"北京": "110000",
. y* o& }2 G; e+ N& f/ J/ }& I$ ` " z; A: U$ c! {/ T
"苏州": "320500",
& r7 X" }4 [- w3 H: Z) [2 p
# [- a1 n8 |- o "上海": "310000"}; s( C5 n7 E+ b0 z4 Q9 h& e1 C# D
' T" q' R$ k; G, U) h* k$ I **return** cityDict.get(cityName, '101010100')0 X- h& D: t0 X6 m/ J: B. ~. V
* Z9 U" ~- w1 [1 W- D1 X0 L8 k
def clearText(self):
" x1 x6 }: q; F7 ` 0 N8 T% K4 G- i
self.ui.textEdit.clear()
9 A" @0 g' F0 b+ n 4 L' f) R+ T' Z! A
if __name__ == '__main__':) T9 y2 m0 J4 R( Z! `: `9 M
( [1 }5 R+ X4 J$ G$ B3 k myapp = QApplication(sys.argv)( @, h, Y# X- _! P* \7 S9 C
5 `! p+ p) f, X# t
myDlg = MainDialog()) ?1 W; H- `0 W$ A, w2 c$ ~- x: F6 k
4 g9 O. A( u6 o1 T2 L# A+ J myDlg.show()8 j% b5 |9 a* d! n' j2 x
+ M2 V- Z9 [ Z
sys.exit(myapp.exec_())
/ e# X3 ?* r9 Q. P# | 9 ~! c) Z4 R6 i. n& G
运行demo.py并执行查询后的效果:0 \. A$ D6 _ |
; u( T9 e- o, \1 F( R ]- J, G/ h. S7 N9 x' W' c/ q$ R
3 Q" C- z7 l. R8 H: x2 d' k 4、将代码打包成exe文件1 `+ q* m( Q, o0 G( K7 F# `8 D
# t, I8 k2 r0 G$ @2 x" j
将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:
* r& ]7 H, C1 d) B6 m
: r0 b! J8 n0 ~6 ^. W; b
3 g3 m: w9 L! s8 b " V9 F* g6 ?/ E6 v- `# I) \
py2exe:软件更新已经不活跃,因此也就略过。7 i& s) Y n2 r) E8 k4 M
+ {& ]# q0 G5 l/ B) s+ \2 J pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。7 s1 g; @7 d2 s0 N b0 g! c
) {, \2 j( e% X6 l2 V
fbs:基于PyInstaller,使用起来更加方便+ b5 W s1 H2 {7 E- E' I
5 {& {3 b5 U( V: W7 ^3 A7 Q 这里选择了fbs来打包。fbs的安装方法:
0 Q$ Z# \0 g9 _4 L. _0 r
- E* Y' _% J' G pip install fbs
. w1 h* A$ y. N' J4 Q9 y 使用方法,在命令行中输入:
& U% i8 V, U& g) n5 H4 k " l$ n9 c% i- ^0 J0 V \
fbs startproject
3 @4 d2 a5 l+ ?" K2 _7 Z 执行完成后需要输入一些APP的名称等。完成后会生成如下目录:1 H' [/ H' c) A x( ~( ]
: ^) d; d0 W4 ^, v& j3 s6 B$ h
z/ l; J; e( _% A5 z8 o7 t3 S
5 \! C, s+ A& }5 a8 o& K
将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:
! d' v& O' N5 H9 Y% W$ d + p! l' E. h+ M3 m
from fbs_runtime.application_context.PyQt5 import ApplicationContext. {$ U# R# A0 v, @& w1 \
```1 S* D; u+ i4 F; J; s# H; `+ D0 I
完成后执行:" \6 g3 `. w$ v. V
```' P9 ^, T* j$ G* m; U& p
fbs freeze# a: e$ | c+ G0 E
```8 K+ n2 Z( f, z& F) k+ I
即可实现打包。生成的exe可执行文件在\target\MyApp文件下。
0 D% [7 ?% g( c) F
/ p8 {& i0 |" t% X$ m3 E ————————————————6 o) {( A. U9 p$ {# e: p
版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。- B: I7 V- a* T: ^- r, _, V* y
原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667
_, f; w6 P" f , N$ v z, D% g* t2 u( m
, s# ?% ?& n0 V1 Y- ^' M
& v' \- W5 @# ^: o
zan