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