QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2226|回复: 0
打印 上一主题 下一主题

超全!Python图形界面框架PyQt5使用指南!

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

82

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组2018美赛大象算法课程

    群组2018美赛护航培训课程

    群组2019年 数学中国站长建

    群组2019年数据分析师课程

    群组2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2022-9-15 12:26 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    超全!Python图形界面框架PyQt5使用指南!
    % s' I& I, Q% A
    + ~7 {: G; A* o! d, H使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。
    6 s) f5 b0 |3 \; ~9 Y
      O! P- O/ s7 Y- o/ {: [/ u' |$ ?常见GUI框架
    2 K% a  R) {  \' s3 S; H. X
    + s" k7 ~) I6 Y9 v5 `6 GPyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。& E5 Q; U9 g: a0 C* _
      f( I6 T, k% n( H: T5 A
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。
    + j% B/ V% _, u: X& b( }8 j4 c5 I6 z! e
    Tkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。7 q& O3 i2 T! G% B( e7 k
    ; J& ]8 {% Q+ m
    PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。
    * A8 @1 Y4 H5 @0 ?& f4 [- y
    3 z5 _/ H) q% H5 F! EWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。
    * R" Z& \* v' m' Z4 f
    / Y3 M$ L& k& e7 }2 z6 DWax:基于wxPython ,为克服wxPython的问题而制作的一个包。1 }: }* J. q$ t

    - a1 u* f4 n) A3 E  z3 c" UKivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。! L8 P' T& `8 a4 v
    ; O" H* R9 X$ p* B
    BeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。, ?) k" r% m* j
    9 L- \* E" Q, r( ]/ @% i. m' B
    Toga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。& m+ |/ {. F* l. d1 d' B
    ; I" S7 N3 f' n2 y/ D' K
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。# P% |# w: r' y1 ^* D$ A

    1 Q) c& v% w. f. O. @9 g3 J( kFlexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。$ n; l# c* _$ o8 C+ [

    5 T% K4 \" s7 n( @pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。
    + p; D' \7 W, |
    ; m; Y9 f& g8 ~, O2 eenaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。* R" k2 i$ k9 r' N
    8 o3 I2 q# \* q$ \$ h8 Q
    个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。
    5 F. T# }0 d# R6 [0 ~) d1 e5 m# f8 B5 C" g
    PyQt5简介: Q& O) u2 x3 {8 K
    * D! |: v9 _1 i' ?& T
    PyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。- |7 W& n% V9 {) S  C+ Q! s

    : Z) P  D8 S1 y/ n. z) W. s8 s$ XPyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。
    ) `1 h5 n1 Q) q/ E1 G. t3 Q! H0 A+ \& i0 h( z0 c- u
    PyQt5特性如下:" A3 t  R% d( K% Z# U( Y

    & i0 p. J/ L4 x基于高性能的Qt的GUI控件集。
    : Q$ K( ^4 d# Q* O# G# x# K2 w. Q7 Z+ e5 W0 L1 d
    能够跨平台运行在Linux、Window和Mac OS系统上。9 Z/ N" t: `1 A+ [9 Z" J: o- g
    5 d6 |/ ], J6 B3 V" `3 p% U/ a
    使用信号槽机制进行通信。( ?* d9 l8 G+ L4 i7 @4 c- t
    # m+ ?' }# @  V2 r1 |6 k- l9 |
    对Qt库进行完全封装。6 G% B! l# M  A/ d) I& Q
    * |- F4 b& Q. y
    可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。
      c" a. N( s8 S  L/ v3 d+ a/ Y  j4 h
    提供一整套种类齐全的窗口控件。, A. P% L3 V1 m4 E( X* d
    . z! P8 y7 F/ r' n  o4 ^
    PyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:# @4 Z7 }9 N5 d% x

    $ d: i' g  z+ h" @7 p1 uQtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。6 R0 _1 F( C& h
    3 t6 h& ^- K' {9 ]8 ]6 @
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。7 a/ N+ u: A0 B/ t$ C4 u' A

    6 C" T! K" o* U/ m, iQtWidgets:包含了一系列创建桌面应用的 UI 元素。
    ! h( _1 X, j/ P) X; D2 u( H4 Q& N9 Q$ I' u. P1 j' i
    QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    / a1 r1 G+ i3 x" }* \. c1 S/ Q/ U3 M! }# y! f  {
    QtBluetooth:包含了查找和连接蓝牙的类。
    - E$ u  V1 J& [7 A. F6 w; P( a8 E( n! c- [9 T
    QtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。
    5 v9 g; j, W% C  f! [, S5 I) r3 m3 ~5 E) B8 q8 b
    QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。2 V8 F! n  Q. _% Z3 H1 I

    8 O* ^: k2 M$ g# Y2 r7 h- o: mEnginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    9 i! O- a; r5 m, g! d: v2 @; `1 |
    QtWebSockets:包含了 WebSocket 协议的类。
    8 O/ v; _. _$ s; }3 Y6 Q9 A
    ' l; A, G- R* K6 y" R+ uQtWebKit:包含了一个基 WebKit2 的 web 浏览器。3 {/ @$ Z2 U& D% ]5 m
    0 ^9 H5 s3 l1 L. g4 B7 _4 `
    QtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。$ q9 r7 }& K5 a  @  r; f4 M2 O1 m

    + x; x! Y( d  X0 nQtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。% Q) ~" {# I3 H8 m- v

    9 \7 l+ Z  Z# l) |$ C' H8 V! lQtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。
    - p' _( f: S) d3 z6 j* Y! P' S/ a2 B! h
    QtSql:提供了处理数据库的工具。6 T+ m( f3 h. [5 c. Y! z

    % Q+ C4 `* S+ \! ~( aQtTest:提供了测试 PyQt5 应用的工具。
    5 c$ r' a1 P2 u
    * t) A0 b2 _" QPyQt5的安装
    * W; M6 J& Q* _* S0 \  J. W  d
    0 A" D4 _2 M2 w# A- c3 C1 x由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5 9 {. k/ s& h  J4 A) |$ x6 @! J( M% z

    - l( f3 x5 K6 T% E/ `* |安装PyQt57 B9 V" U$ X$ F" c: c) y

    $ e/ X0 e# i% b* V. j/ k: ^1 D; e! Vpip install pyqt5( `4 R: Z" D: f$ R7 E7 ^
    - v- p- T1 _& j7 Q% E0 T( B1 T
    pip install pyqt5-tools6 M, G# Y3 c9 H. h9 Q$ D. Y+ `5 H
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:" U1 t1 x4 v: T; c; z3 U
    - W) Q5 j- G- g2 V/ k- m" w% u
    qt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.' r1 B* ?% p. r$ S7 O% N5 _5 m
    解决方案:: f/ S- K2 T6 h, Z# g" b
    + ]' h- \2 \0 |" |, z
    pip install click~=7.0
    , a) M! @: I- W+ J: ^Qt Designer的配置
      _* V  D+ U) {; m8 y/ e
    1 Z- B. @, Q% [# S& N5 ZQt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。$ ]. Q6 ?/ W! G; B4 O

    3 M% ?. I! L/ H+ U- D* [2 g7 X; C: E$ p/ y) k4 T, i; G7 ]

    6 X# y7 I  a) D$ P2 [整个画面的构成:+ M4 d5 e) |% v1 F4 R. |2 L

    / D! e  a/ X' m- B% T. {* M左侧的“Widget Box”就是各种可以自由拖动的组件8 }7 k+ ~# P/ Y: \) r

    ! X) t& C. g$ Z  B  h中间的“MainWindow – untitled”窗体就是画布
    . J8 H2 g: M9 k  B' |) G( D$ t, ^* @; i
    右上方的”Object Inspector”可以查看当前ui的结构6 ^9 N8 m- D8 g9 d
    * u  o* Y. h% f
    右侧中部的”Property Editor”可以设置当前选中组件的属性
    0 g  f, ^6 j+ |! ~: z' Q2 k
    8 q6 R" r5 n8 @+ z右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等7 [4 n( P( Y& G: K" v

    : l9 n4 D- U- `7 e  ~! P2 A- N最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。
      C5 `7 H6 D! B' s% e# P) A, V6 @0 D" M
    QtDisigner配置
    3 K8 k0 K# F% T4 [5 B3 W1 {4 a* J9 O
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    7 ]& V; h0 q  E& m
    $ l: V4 m! K# R8 q0 c- [$ xName: QtDisigner
    - [5 v: y! N3 F- e; E' \3 d0 R9 C  G& P1 t
    Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改
    ) a! x$ R0 j. m  m; Q+ p5 z& Z( H. W
    Working directory: $FileDir$
    " [( S, l. `* S: k& ^% _. bPyUIC配置, R4 N5 H8 M2 F+ l

    7 S' H/ P  W6 g- M( X7 ?1 HPyUIC主要是把Qt Designer生成的.ui文件换成.py文件。
    ) ?% K9 K$ i% y. E& f7 y
    " i8 V/ N3 }1 `, v在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    ) N$ }! g+ @) X, }& ]3 P. ^8 e7 X1 [* L1 f
    Name: PyUIC
    - A  p! D% `' U7 f  G- J
      |  y) L% [( ^Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改) ?& D2 k% r3 f4 F( s) D
    + [: x# V6 G0 L" O
    Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py( S) }' C1 L. v" e9 B
    # y% M2 z% _6 L2 |# U( P: Y! V
    Working directory: $FileDir$
    8 H2 P. |5 O- D- G3 v+ {PyRCC配置# k5 D0 r! k  j$ t6 k
    ( r* {4 `8 G+ ]! R  f9 E
    PyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    9 c3 J/ _6 \6 F- {  x" m# g" a( j# i
    Name: PyRCC/ Z& o- ]* _/ U9 C5 a: T+ t

    9 d1 [5 Z, w' D; N! eProgram: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改# C3 I  f9 W4 F7 Q' i, d: s" t# @

    / K& S" B1 a  z$ U0 N. H6 L& S* _Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py% c# D: a! O' M' \7 Z# K& a

    4 I1 i7 g5 W' P( u2 j3 p9 cWorking directory: $FileDir$
    1 Y$ ?0 I0 a7 n2 g! B  Q3 o4 h* VPyQt5使用示例
    1 S# _. ]4 D, R5 s4 V2 B
    1 _/ O; y: E* O+ ^7 O  S" d创建一个空白的界面:  {! o) {3 {9 ~* o

    ; u" S+ |1 H) F: h* ]import sys6 j; D8 N. d3 C9 o7 `( O
    ; ~( l6 g6 H2 B$ Y
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    1 s+ C+ g! S5 J- b7 I; O" X$ }$ @
    ) j6 o( n9 C/ rapp = QApplication(sys.argv)
    7 D: y5 e- L8 A+ A* r- q' }3 z$ [" U9 k; E
    win = QMainWindow(); D) Y6 s) a) }. e/ L4 N+ g
    $ j. A, p4 c2 H0 e
    win.setGeometry(400, 400, 400, 300). x+ b6 x' p+ W4 i$ t! H" w
    * e$ k  A2 h3 B2 ]( Q
    win.setWindowTitle("Pyqt5 Tutorial")
    5 G6 j- C# P1 |) J# D
    - A1 ^9 `/ X1 ^, i8 `; y% O2 xwin.show()
    0 s# a; }, N8 D3 F0 k* m
    0 X+ W8 ]! l$ _4 H5 @1 c1 P+ \6 Asys.exit(app.exec_())
    & e. [2 ]: E# I3 Z; f7 L/ n4 E/ A7 B( N* U( u. o

    0 w) Q' ]) ~/ f5 F- s8 X4 H! u. h% S, y4 j- W: @) S* _
    其中:
    5 _! S/ y0 k1 |; |/ L1 L
    # H& W$ m$ \* [- mQapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。3 [) r0 I5 P7 v# u
    + G: z  H0 ]6 Z, i; o$ O
    QMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。; [; T8 j8 Q8 c) @

    ! f0 l- t" G+ s) hSetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。
    0 m0 J: C% E! _8 W  ?2 W$ B
    $ i- N: \5 D7 E6 H. tshow():用来显示窗口* w6 G" _" Q, x7 ]( W* ^$ @  o
    ! r" d& O9 T9 g( y
    exit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭
    0 u( ?3 \& J+ o
    2 D, Q3 v& g, ZPyQt5支持的常见Widgets有:
    " D+ `1 O+ ^! J3 g0 \( ], L8 Z9 p! |1 E. }

    $ c9 z) `* q3 _/ X2 e
    9 w% D3 O1 l# \, F从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar- W  T7 M% ~, n0 h* G$ H

    + N" e0 [4 {4 A2 j/ e& A对于使用Pyqt5设置文本内容,我们使用Qlabel:
    7 j2 q0 t* S# }- j. }  U  E
    5 ~. B4 Y# L9 qimport sys1 y( a& b! `% k: c1 l

    ' K4 q% J% N5 e: i) tfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    7 a2 v- m* i6 n; Y3 j4 {
    2 N8 Z0 r% ?/ zapp = QApplication(sys.argv)
    7 g( \6 ?, r7 H; Q1 s
    ; Y. P2 |' H" P. _/ kwin = QMainWindow()
    ; n  G# G! |* h9 K* f2 Q2 O9 W7 T+ T2 d3 i! V4 d$ x- P0 O, @$ O* U
    win.setGeometry(400, 400, 400, 300)
    6 I. z3 H& E' A+ P% Y. M& k/ G; D2 s4 R& c: u8 A( A! r8 j
    win.setWindowTitle("Pyqt5 Tutorial")
    ! @# }2 q8 ?! ]4 b. n2 B2 a4 I) V# K
    \# Label Text, E' Y6 k  F5 W/ l
    8 }' d- S/ X4 q. l; ^
    label = QLabel(win)
    . U) j8 @+ B8 _: E2 Q' x9 q$ \: V* Q3 Q: P9 m
    label.resize(200, 100)
    # v" Y& a- ?8 `! L
    . n: t% b' g5 @8 glabel.setText("Hi this is Pyqt5")
    $ v+ `- ]" @8 d7 x
    8 w: H8 G7 i5 s% O- Nlabel.move(100, 100)
    # r* }5 ]3 \, Q8 O0 @
    3 S3 i  O4 n7 w" V* y: O3 u5 E+ @win.show()$ u$ D$ ]: V' g! Q0 |) H) w0 z" o

    , L' j5 A' Q* n. ^4 q5 ?sys.exit(app.exec_())
    8 l+ z3 E* Z( ?* e
    : x* J) O& O1 d0 {( M) O
    7 C6 o7 ~5 |: z6 B1 h' _2 m6 e& X$ ?! o
    按钮与事件:: R5 D, @0 w" W( U0 ?  `
    ( |$ |' ^* C" Q$ z! B
    import sys
    6 [3 ^( Z0 B* x& s4 ~' U4 G6 f) t0 [4 S. }. ^$ _
    from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton5 R/ Q. a1 Y" }$ a) d, l  d

    : F3 S9 n* a3 H/ w, ]4 adef click():
    , ^* j; Y2 }6 ~- B; e+ N
    3 p+ E3 B/ E  f( X! W" F8 U' s    print("Hy Button is clicked!")
    0 s6 N4 B. y- v+ k( z# H
    ( g8 |8 f3 c9 T6 _9 j5 [+ W) ]* c! ^app = QApplication(sys.argv)' O6 X8 T+ D# H+ F. g/ s7 a

    / W* r/ X% P6 Q4 R8 Q5 @win = QMainWindow()
    8 s$ U- [9 G6 c6 D) H8 [8 ~, ]3 v0 J: S8 e; m
    win.setGeometry(400, 400, 400, 300)
    4 P* b/ X) r% _7 t: v2 ~" _$ `3 }, C- l% r8 a3 C  W! A1 W2 b
    win.setWindowTitle("Pyqt5 Tutorial")' k' S9 v  K$ I6 [! D6 Y

    " w, ?8 C; A2 G. [3 H( L& u5 x; Y\# Button0 Y6 o- p: R" ^$ ~+ G. p: w, H

    . t' v, r+ ^6 i0 y9 Ibutton = QPushButton(win)
    - A( J- Y6 v1 ?% x) \4 H! J: c: g5 g
    button.resize(200, 100)
    , d/ {7 Q+ I  }" ]8 S2 M% V# F
    $ V9 q9 w- @. Mbutton.setText("Hi! Click Me")$ C8 w6 X) [2 w- t6 R# V
      s+ S( J6 o: H" @
    button.move(100, 100)
    $ ?6 _5 B0 {" Y2 ?
    . A" o8 s: W6 F' |8 Wbutton.clicked.connect(click)
      s8 B! S+ K) x5 J: N- W2 q) c" A5 H
    6 t+ _1 q1 G. cwin.show(), q. `# j" G" x+ v  Y! L

    " N' `8 {, a* L% G/ \4 P; w" usys.exit(app.exec_())6 ]% P  D+ A3 m) z2 k1 M4 W% M

    5 |! ?2 F! {/ y) ~8 n7 y/ U, U2 D0 U/ m3 h  n9 B3 Y& [

    0 b' ~+ N& ]* Nbutton.clicked.connect() 在按钮点击后执行特定的事件。4 U" I$ R  F2 u+ j5 B" P& R$ [
    / E( f& O' J! W6 i" P- v- r
    PyQt5实战( Y, d) }0 k% a$ C* X, }3 m+ y9 s4 u
    $ ~' c/ p- `& V6 _
    实战项目:简易的天气查询软件2 e1 F. p  K2 |) W7 O+ F" W
    9 l" n# I7 S  q! n- o
    1、使用Qt Designer设计一个界面% B; g+ ^( c$ I+ X0 X
    * ]$ \; }" B+ m# e, r
    1 C7 x( O- V, ?6 W/ e# q6 I

    ! Y9 H! i1 Z( K- }% c8 j( x用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:
    ( I+ q1 q1 \. a$ d' E( D! k" b
    . n& h) N$ H% u, O在Qt Designer右下角选择 信号/槽编辑器,点击+号新增9 d2 [* N6 K2 ~' l, r# t
    4 ]: y; q+ U5 j7 j
    分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改), V1 V6 \% g$ ^9 t" d5 H3 \' ?( y

    2 T+ n% _7 l- A以上完成后保存为Weather.ui文件。
    $ |, W; Z7 U% I- A8 v9 A1 {6 j+ O8 Z7 \% O% Z1 w: r3 A; [
    2、转换.ui文件为.py文件
      I$ h7 k: e- o2 p5 x( n9 c7 R  t0 C; M4 ]! p
    PyQt5支持直接使用.ui文件:
    & W7 w! |& K' A/ u  U
    - Y4 F1 m4 N4 a. p0 Z8 Wimport sys
    " g! n: I( d& F3 q* w2 \1 I4 j  S
    7 `4 q+ ^, }: V7 Xfrom PyQt5 import QtWidgets, uic
      V5 j  H: P  a( ^- p' g
    ( S8 m; Y" y0 t7 D+ B# Wapp = QtWidgets.QApplication(sys.argv)
    " @& _* L& |4 P3 x% a
      d$ Y. G0 Z5 {* p5 X8 Hwindow = uic.loadUi("mainwindow.ui")5 o% g5 x# V! j2 P/ I2 |9 }8 q

    ) Q- Y7 J" h+ A% c/ pwindow.show()
      K/ g( F  N5 y0 V) A3 n, D' q1 k. O
    app.exec()4 M: ?' G* M! r5 M
    但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:
    + a  f! m' ?& m: C/ `" l5 J8 g- T
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py
    5 W, v! N# c! R, h' m其中,我们需要把两个按钮绑定的槽函数:# t- s3 B; C$ P4 i5 {9 l, n

    % O. ?7 `. l9 _7 {2 b. d\# self.queryBtn.clicked.connect(Dialog.accept)- L% h5 U  p9 {6 j2 Z) I$ W3 y

    5 l) ?8 S5 U9 C# h/ r5 V9 U\# self.clearBtn.clicked.connect(Dialog.accept)
    ( o6 u8 F) v. i$ R7 |4 J% Y3 Z
    ( K+ ^* U0 R2 ^\# 修改为:; g- i7 \1 e3 U: v

    : E9 h# n" G+ K: vself.queryBtn.clicked.connect(Dialog.queryWeather)2 l( C$ e4 O% E( `5 P2 G

    % N# Z" O) D# Kself.clearBtn.clicked.connect(Dialog.clearText)
    # {# p6 n' _& ]8 e+ ]5 X+ w* T最终的Weather.py内容如下:
    : g/ W$ S1 s4 ]3 M% Q
    ; j+ `+ P& @! J* s8 t\# -*- coding: utf-8 -*-
    3 _" o- A# ?- E, i" j4 t% r3 Y% M( ~2 v$ m" z6 b$ E
    \# Form implementation generated from reading ui file 'Weather.ui'
    ) P! s6 w5 g; |5 X
    1 n" h* Y0 J: X# M7 t" I# r* R\#
    + |& ^# H; C6 ~
    ' i  Y$ C+ X3 n* M2 O# g. C& }9 `\# Created by: PyQt5 UI code generator 5.15.4. ]+ V( _- s  a$ ~* s; o: \2 k8 I

    * O! z  \0 J7 M. }6 l\#" i/ R) ~7 |$ {" }

    0 B5 k$ d1 T6 R7 j  }* S/ v\# WARNING: Any manual changes made to this file will be lost when pyuic5 is
    $ }$ g, ~. i, ~4 Y- T$ d+ {7 R' V2 L6 h
    \# run again.  Do not edit this file unless you know what you are doing.
    5 t8 m2 {9 q+ }4 s2 \3 S4 C) G/ I+ v5 w. a# ]4 `( R
    from PyQt5 import QtCore, QtGui, QtWidgets
    - `4 ~+ Z: [0 r: H# w
    , L3 ^9 k8 m. M6 u( d, p3 K" vclass Ui_Dialog(object):! R" \9 k  y2 o

    " b9 r! G! d5 f/ E; s    def setupUi(self, Dialog):) }. K1 Q! S- q. H% W
    3 s9 P2 P3 d% i7 y6 a0 d" g
            Dialog.setObjectName("Dialog")
      Y4 \3 p0 J. }( L2 d
    : i& w! A* ~& }, W+ ~! E        Dialog.resize(600, 600)- O; @5 m" {; @( p4 }6 f

    / M( S% k0 r) d( C7 g        self.groupBox = QtWidgets.QGroupBox(Dialog)
    . _( O0 a% k; T" T: V0 x/ B6 ~/ x6 Z( p4 O! v8 C" r( l8 {3 F! F* B
            self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511)). h9 i. y" T5 v7 j3 E) f4 h

    ( {7 h: E% d1 l) |        self.groupBox.setObjectName("groupBox")
    0 T' {$ @' a2 o4 r# K8 W  V! d3 }8 X4 R; N7 |( I5 i' k+ s
            self.label_2 = QtWidgets.QLabel(self.groupBox)4 Y! R9 Z4 a* p4 }6 s

    5 k- {2 W# Y( P+ v) S8 ?        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
    8 \( u2 B. b* p# m9 ]2 e" E
    : z! N3 C. u" ^1 ]) ^$ m) e- _7 L        self.label_2.setObjectName("label_2")6 E& `' ]/ X9 x7 X' S1 F* \( C6 _" e

    % Q5 O, e9 h! ?; H3 B& P        self.comboBox = QtWidgets.QComboBox(self.groupBox)
    : a2 p& k' Y8 R3 P% t6 R% f( v/ N: S. F+ J# H) |( ~. o3 e! j
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))
    4 a& a% @+ t! ]5 ~. f; V; X8 p+ o% K; P
            self.comboBox.setObjectName("comboBox")0 z$ ~9 {# k4 Q5 w" g+ Y$ `$ K$ Y
    . x4 a$ Z' T+ r- l( H: X6 X8 s& R
            self.comboBox.addItem("")
    . Y! i* C8 k! \8 f7 D' _) I$ ^+ f
            self.comboBox.addItem("")
      o9 r7 }. r9 M4 Z  B2 M) z: @
    ( K, R8 N8 C1 |' O8 D        self.comboBox.addItem("")9 \2 S# Z: A, e6 Y
    $ a9 F! R. l9 I8 ~* F, h1 u
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)# [. H+ i  Y+ Z) ]  O& B, K' h7 h
    + M) x6 Y+ p6 t( A! i6 q3 y
            self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))
    ' y8 C5 l1 M% e, x, n  t; k
    / K  v- K/ G' q        self.textEdit.setObjectName("textEdit")% N& Y0 h9 K6 I0 L

    ) m( \6 j/ N& Z$ v# C        self.queryBtn = QtWidgets.QPushButton(Dialog)* J' @4 _0 [2 e7 e8 Q9 ~

    5 z  E+ S$ |* ^/ K; _; q& r& X        self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))
    2 v0 ?6 i" b, t7 V/ P( j
      r% W, q. G( K) `! s& V* D        self.queryBtn.setObjectName("queryBtn")
    . U$ j" q% D. d! {) X% u& Q9 s/ Q; D
            self.clearBtn = QtWidgets.QPushButton(Dialog)
    6 |4 q; {7 F3 z$ X8 ], `* u7 I; A4 A5 k/ h- f5 s* f# R
            self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    ' ^, D0 |% e+ Z1 m; v
    " F; l& `1 C, a5 e6 d        self.clearBtn.setObjectName("clearBtn")
    ; `- ~# E& s# J: d% e5 k  O$ v
    - B8 r4 n  l5 c( `+ n  d2 W        self.retranslateUi(Dialog)" n: @! T- ]  ~) q+ I
    + J2 e( P/ a$ O1 r5 n
            self.clearBtn.clicked.connect(Dialog.clearText)& D$ l& T% E+ T% Z" f8 u, W

    $ G) |' Q3 p3 M9 M: Z8 X! z        self.queryBtn.clicked.connect(Dialog.queryWeather)
    : o, Y/ R  {/ Q5 z, H
    : H8 g4 \. a8 C2 R& r$ ^& e" S& F/ r% Q        QtCore.QMetaObject.connectSlotsByName(Dialog)
    6 `: b$ i$ \7 [; E7 e; i6 N! h* P5 _4 F" M+ x- [
        def retranslateUi(self, Dialog):
    ! f; v4 O6 i* O2 W: j
    0 z2 }3 p, y: x  q        _translate = QtCore.QCoreApplication.translate9 O; _5 r! F3 Y0 q

    ( X% Q/ R# W1 @5 O: Q; I- S        Dialog.setWindowTitle(_translate("Dialog", "Dialog")). o6 c7 O9 f: V: M, o2 R' v* p
    - l6 X) M9 {) Y$ @, i
            self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))5 }0 b  O( a3 I* ]
    # f2 z5 }  [% r+ [# S; D+ o3 m) X3 T
            self.label_2.setText(_translate("Dialog", "城市"))
    : V! O0 O* c0 E0 N8 p
    1 C/ G& u& M7 Y7 V- N8 i        self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    & q9 J" U' I6 v8 X# R0 a0 a( s) {- Z5 u" D4 ~6 `
            self.comboBox.setItemText(1, _translate("Dialog", "苏州"))
    ! ^. y) E' S9 c2 _7 d/ U
    $ ~. j7 R9 y. z0 ~        self.comboBox.setItemText(2, _translate("Dialog", "上海"))3 P/ y- h' X, D

    0 M! o, ?+ E# h$ m4 V        self.queryBtn.setText(_translate("Dialog", "查询"))
    " G9 V9 C8 G  F# }1 c* q, a; y( |
    , J5 ^3 e0 ~3 \        self.clearBtn.setText(_translate("Dialog", "清空"))" {5 c% |9 _( d( h" m
    ! E3 o# t# A8 f/ J9 E/ v
    3、调用MainDialog
    % C1 {+ E) G" h* k5 c8 e: n0 t3 d  y) r$ w) ^: w
    在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。- K0 f6 \5 F4 |8 ?$ q& T

    ( d8 |9 b' n1 Q2 j完整代码如下:
    * e5 h! L6 J3 {9 ]7 G( y* o* I* l8 e, [$ y" h. e2 Y1 P
    import sys
    3 d( t: [: E* ]+ y
    + O* f# J: p) M& r- |import Weather  m2 r) m4 R1 k0 Q4 b
    6 x0 r: U) M7 Y: F; _* ]$ ~! W( j
    from PyQt5.QtWidgets import QApplication, QDialog
    2 G1 g" b9 F  o! q' c( z" Z: w" E. e7 N7 q$ t3 f
    import requests
      L# P1 Q8 e1 L! O2 Q0 ?! ]- K5 w( s7 Y1 K7 y: z- G6 M# Q
    class MainDialog(QDialog):- R$ L/ B7 L! `/ F/ r
    2 h" N+ Q; k" n
        def __init__(self, parent=None):  y+ X5 _" X$ i" G/ j% W9 u

    0 ?& |$ I; `5 \) H, @1 k        super(QDialog, self).__init__(parent)
    8 g, Q3 H/ y) X  L8 X; m8 d( m  @1 D9 e! U' W% x
            self.ui = Weather.Ui_Dialog()
      p5 \6 C0 Y" i+ A, A2 \6 l% h* o: h9 Y) n) r6 m+ d: w/ ?3 R
            self.ui.setupUi(self)2 g/ y, x5 ]) W& Y% H

    : m1 e6 k; }% N. X8 a4 G4 p    def queryWeather(self):
    9 t1 L0 ^- R0 I1 j) H+ h
    2 K8 Y, u" @' @; y        cityName = self.ui.comboBox.currentText()
    6 j" C1 \5 l) m* z' ^
    8 R+ T1 O9 I) l& s* v        cityCode = self.getCode(cityName): V! @2 V2 I2 f0 J

    ! s! W7 E1 F( @* ], s  z/ Q5 d        r = requests.get(
    1 c% E* S1 d' m/ F
    % i; P/ I% k5 f! P% m            "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(
    / A* k% C1 z4 x1 ?3 j4 z2 {" l8 X
                    cityCode))- `5 \& A5 @% P6 u( g
    $ l! H0 v* k$ X' [
            if r.status_code == 200:
    + o: {: {2 C( v- o$ ]; G4 Q) U6 a4 B, e; y" V5 \- A/ k, v
                data = r.json()['lives'][0]
    4 _7 i7 F: o: s5 u, g3 N% x+ J
    & Q$ v- L* ~. z# e! H% m* p            weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    & X0 O4 l: C* \* J4 p3 u1 L/ Q! R# e
                    data['city'],
    ; A! u/ R. `4 M& I3 ]# i
    * {6 Y" _5 w+ S6 N# F9 Q                data['weather'],
    + ?0 l! V$ G- y  _: i3 t
    + p8 w' @2 T" }* o                data['temperature'],9 T1 @2 C1 ~! z/ F3 G& S9 n, Q

    0 n8 }& e3 w! |9 c                data['winddirection'],
    ; K0 ?0 E0 m- Z
    # L# a; g, J( N& U, M                data['windpower'],
    ) y1 i8 W2 o/ [8 u. T0 P
    9 r2 `+ z: c- H% x2 b                data['humidity'],5 T6 l- a5 ~& Q! f+ f9 Z

    & c- Y# A7 D! K$ x; `4 T                data['reporttime'],
    " ?6 I1 c8 i: H" m4 Q' r6 `) q" I/ n$ v' b. V+ t
                )
    6 j4 W1 n( k: C; J6 f0 x  ?* \# x1 M9 @$ j, h
            else:
    ' w) d! K" [4 o! D
    $ ]1 t; `; O( s% b, q6 c            weatherMsg = '天气查询失败,请稍后再试!'- F; H- f2 A8 G) }

    1 c2 ^7 {+ Y; A; p, S" b        self.ui.textEdit.setText(weatherMsg)
    3 ~; @& x5 f7 _$ X/ [' \9 s9 k$ n1 v* B5 r9 z7 n! ~  L
        def getCode(self, cityName):
    * `0 [) O4 c. s  Y4 C  D& i9 V* c3 }+ W, {8 w" u) d) V" J
            cityDict = {"北京": "110000",
    5 q1 L+ u" d1 F9 t- Z( y$ C* P
    & ^7 k0 m9 v% p# O% [# P                    "苏州": "320500"," B# t! E2 K* `

    - \; @) y& u6 ]6 U1 e                    "上海": "310000"}7 \7 f2 N' R8 C4 f. G! A5 o3 h8 `) U; t
    ! u% k+ ~& Z! S# d/ T2 z
            **return** cityDict.get(cityName, '101010100')
    5 g& N7 u. A$ H% d& {$ d+ }8 L% V# c3 ^; G
        def clearText(self):4 o: O; p: U* }3 F. S7 b

    & d# ~7 y% B; j' o' V! k4 N2 C        self.ui.textEdit.clear()0 ^- ^, G. A( ]4 `" y
    % V& G% S* c1 p1 y
    if __name__ == '__main__':
      _, x9 x, E/ `
    ; M2 f$ E0 w( [% q0 `* o( _( X# W    myapp = QApplication(sys.argv)
    % }( k. h3 Y$ I
    $ Y. `1 F1 B% L- [: i- n    myDlg = MainDialog()
    1 t# _; [2 R" r# n, x( Q' r/ `* _3 v4 i8 p
        myDlg.show()
    3 J' |8 O3 @6 j$ F7 Y( ^2 n8 x/ \' l$ ^- `8 H8 Z
        sys.exit(myapp.exec_())& m- ^1 N8 H8 R7 p* A2 W+ p$ x1 q6 P
    " }" I6 T+ z: o) \& T
    运行demo.py并执行查询后的效果:
    * g) T2 s3 p+ H
    . e% U- J1 p1 G3 M
    ( ^1 v( z; ~0 j$ T! ~1 ?
    + t: r/ U. j. o; C, V; G4、将代码打包成exe文件
    # D  [8 l' S) \: Q% w  |
    8 _$ r4 c# x' @% z; \; \将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:
    " S( O# L: b& {5 I6 X  ]" e+ ?0 T( t; i; q
    9 g/ Y" M1 D! I! O

    5 V5 \- ^5 R8 F3 ^! N1 X* e1 L% Wpy2exe:软件更新已经不活跃,因此也就略过。3 R4 ]' L  i5 k) f  c8 W
    5 o5 j3 N2 s1 n1 u  N/ D
    pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
    4 P0 _# i0 Y' L$ c6 P5 d# i2 v3 ?4 ]/ o( _
    fbs:基于PyInstaller,使用起来更加方便' Z& |1 n+ Y) ]1 j1 @0 @4 W( Q

    ' a' }- I( a- j4 }$ t& m这里选择了fbs来打包。fbs的安装方法:
    6 S7 j7 P# `! F/ r0 {" J/ c& A$ J$ x- t% O
    pip install fbs$ w& p; K% L0 S1 M. X" E5 {
    使用方法,在命令行中输入:4 h9 }8 [! i! P. ?0 L9 T

    3 k* J( D, ~% }5 s5 ifbs startproject
    9 T3 t: i" p9 I. [- q- h执行完成后需要输入一些APP的名称等。完成后会生成如下目录:
    ) v$ ~9 r7 u2 y$ m4 N/ Z/ {1 p$ b( U' P. F, t- J3 J

    ' T2 T- J' R3 @# z9 S# m' p' z& d. V. W- S, B) b
    将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:
    9 M4 [& k" n# o
    + O4 i. X( _9 s  Gfrom fbs_runtime.application_context.PyQt5 import ApplicationContext
    5 }: g- R; w3 z1 \3 G```
    ( a- P) p7 u* p8 i完成后执行:
    - _% N% H0 y* S7 L  [" V! `( K9 V```
    7 P- e% f- `9 h4 }% ^fbs freeze
    ' T3 d6 T% e# O9 l* z& B```- U2 j, k6 n' v% e6 p
    即可实现打包。生成的exe可执行文件在\target\MyApp文件下。
    0 o# b8 n% o4 C: `  N% i, C+ R& f' V' h/ Q
    ————————————————
    6 p5 P- p9 @  ?版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。6 W0 @7 a  _9 ^2 }6 v$ D- @
    原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667/ R! E0 H3 ]: V

    6 y6 c2 X: C* F; N4 d% ~' M
    5 {* O% g4 J0 D: B1 w; d* f! ^+ c4 E5 I
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-8-7 02:21 , Processed in 1.805549 second(s), 51 queries .

    回顶部