QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2224|回复: 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使用指南!
    2 l8 k3 v' |, T7 k  I1 E
    * N. t# e( k" M0 J2 {- Y" z* P使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。
    7 N* @! U0 o' F) {
    1 }7 f  X+ _0 k* U$ q. X# }常见GUI框架
    1 \  A* y% N0 J, ]5 k6 |+ e
      u$ |( o: p& f& ?  Q$ ePyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。. s- A7 v$ @7 G" k# {: C1 w/ F

    1 m- [) c/ b4 e, o* r& V. RPyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。; T- q7 J9 v5 ?3 L' y+ F* i* I/ U

    ; x  G0 E* a" k, I+ ]* f/ ZTkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。5 X5 S+ t; ^' A( M1 h$ ]
    + g# P- V7 P$ e7 N. U' z8 L
    PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。. {  }; O: p  ]6 O, Y" x

    2 X: L# ?- j6 ]! E8 ?/ SWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。
    . r: T7 \$ A7 q! z
    " r& C8 o# y( n4 x! M) S' ]$ kWax:基于wxPython ,为克服wxPython的问题而制作的一个包。
    3 y7 F- j+ F# m7 @- G- ~) B. T2 F7 N
    . [  ?+ q/ c2 S+ [, yKivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。
    4 y1 Q5 e# @" g0 ?* I' l: D1 Q8 ^3 j9 b: j9 `
    BeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    4 A' Y8 f2 ^  U% e5 k* Q& J# j, w; {$ s/ w8 e$ R
    Toga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。
    1 E4 D0 h( q9 A# w9 G3 i5 P" D1 O8 F# I2 J
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    3 b* U; \1 s5 V7 B& j0 A, q9 c& k1 }' ?! e$ [/ b+ ~
    Flexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。
    7 V; G0 c9 i2 D- {" E# D& @5 l4 U) O. N6 q* e" q, f! t
    pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。7 b; K) d9 S( R9 P, L

    # H0 o1 s6 R, Benaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。
    3 E2 i& g4 x+ d8 ]8 t' E6 i6 q
    * q1 c9 A" t* d+ p4 w' i5 q  _个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。
    7 W% Y  K3 [; i8 N7 H
    ; |; w0 t/ t, QPyQt5简介
    . f- z: k( q4 D
    # [: G* b" |  a* U/ tPyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。
      F* s5 T6 {. S0 s7 J) P
    3 W# i# X" J4 u7 N( zPyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。
    8 q9 p) _/ {# x+ a8 z) m( s; E6 S& g# c
    PyQt5特性如下:' t4 K) R8 r4 }" D' @$ E; F5 H

    " m  b+ y+ ^) Z% X: E2 r基于高性能的Qt的GUI控件集。' Z- M2 b8 ?% L) _

    3 y( o, g4 s# l能够跨平台运行在Linux、Window和Mac OS系统上。8 Y% G, r5 L( q
    : A$ h) `6 }1 e' t1 K, Z5 K, O
    使用信号槽机制进行通信。+ T* t. t) U* K" ~5 f1 R* B7 r

    7 r) ?& _5 ~. J+ W" I4 ^0 O: m, o- Z( b对Qt库进行完全封装。
    ( T- B: p) y0 m6 ~; y& Y: C
    ; L; I7 H: b7 m4 t: W, z) U可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。; ]4 V$ E' Y& j. ^2 L/ @
    $ a0 b) F6 [( Z' C: ~# v, ?
    提供一整套种类齐全的窗口控件。2 ^3 m; b2 h/ n

    3 |( ~" d- i* ?6 a+ p7 T1 b; rPyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:
    9 |+ V3 j4 d/ Z3 J* ]5 {4 u4 ]  H: B" q8 x
    QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。% |% [6 i* P& Z9 H. J: h5 N
    ! C: `& B. ?! X% T
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。: ^3 L8 a$ x4 a* \' C" n

    2 \' o* g1 h  o$ I8 XQtWidgets:包含了一系列创建桌面应用的 UI 元素。, r0 o3 i. l' V! Z; J* w$ B. S

    # I2 s+ K* s) ]1 o! vQtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    ; o8 I5 u! t: A+ e5 ?& T5 ~3 a7 E
    ; ?4 r! c* D, W8 ~7 d1 fQtBluetooth:包含了查找和连接蓝牙的类。3 \9 `% M7 M9 u; A7 R
    . W! b1 z' W5 G: T& ?* Y2 T4 B
    QtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。
    4 i( H( C$ C) V* G% H- [: O# o3 Z& g0 s) _7 ~
    QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。+ t# K; p/ q0 s
    ( G+ }4 H( w0 f7 ?
    Enginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    ; L: P- t: U" n+ R) k
    2 e9 Q% c0 `; O0 n+ xQtWebSockets:包含了 WebSocket 协议的类。. s1 `( X2 Q/ Q; i
    ( k1 |* v  d" ^6 J) i7 [$ @
    QtWebKit:包含了一个基 WebKit2 的 web 浏览器。
    ! C8 ?4 o, u- n* a! |
    3 C: I! I# E7 }9 f3 \- ]" lQtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。# _8 o4 Z2 }: F8 b/ S/ w: l
    : Z' |8 H: `. }, {+ R" g5 F
    QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。
    & R# N4 C# ^+ [, m( E7 J2 l* j# n
    QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。- b9 I; s9 M! s: |. |- m! ]- K4 b

    - J# X! y: V$ o1 r( M+ uQtSql:提供了处理数据库的工具。6 H( }! J" s7 Q2 t8 M+ Q4 n, H

    ; G: \* \7 J1 L" j+ EQtTest:提供了测试 PyQt5 应用的工具。% k9 y1 R  z# C- ]  x5 z* C

    ' a: O8 D9 r1 ^6 L" C% B& XPyQt5的安装
    : {1 r4 j& u3 v4 E. e; l* R: S& T# O. O+ L; o
    由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5 4 e& z. R) D' p$ R0 _2 r
    - f7 i) S2 l3 p6 ~/ Z) A* S
    安装PyQt5
    8 ~5 |2 V; v  |
    ) ^( a6 i6 _- |: L7 ~0 M6 x1 tpip install pyqt5
    ( r2 X: o3 Z3 m, t7 W0 ^
    ; c$ v& Y% k! Ypip install pyqt5-tools* j1 j2 k% p( Z5 ^' P
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    5 ]) @* P$ J/ J7 A; g+ I4 E; x7 ^. L
    qt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
    " {  T& H2 G1 d8 Z. _3 |8 N解决方案:! ]: k7 A* F3 ?( K! o

    ; Y8 m% w# X  \' G$ O) d$ O+ D. hpip install click~=7.0: f' N: m; ?) s: h% ?$ Z. `1 P
    Qt Designer的配置6 F7 n6 K7 n% b3 n

    6 ]- q( W8 y9 J! UQt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。
    $ e6 y/ E$ f$ `- [% a: R- V7 O1 t, a9 F& @9 i% N+ d
    3 x5 g; i, p$ x6 \
    / K9 ?6 `0 z& Z3 f- e- A3 v
    整个画面的构成:
    " z+ ~2 o$ i% S4 O4 v. o+ g% {" `+ H5 h9 |! |
    左侧的“Widget Box”就是各种可以自由拖动的组件: J, L% j1 o5 ?+ K: t8 Z! V
    $ ?. }7 m' t0 |0 @+ e
    中间的“MainWindow – untitled”窗体就是画布
    , P+ Y% n& @' s1 Y7 z' N& D( `: Z. ]' y% K1 V
    右上方的”Object Inspector”可以查看当前ui的结构
    9 h4 P7 T0 W2 M$ l; z' j9 p! q$ E; l/ I! r- F
    右侧中部的”Property Editor”可以设置当前选中组件的属性+ M& |* n' s$ L) S0 n

    1 E, {) }6 x* e右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等+ Q5 O8 \+ F  j( V$ Z$ ~  W

    6 {( A; W5 o7 [) m2 ?最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。+ G  L- \. P3 J9 _% c3 M

    5 h  D4 \6 B# v( m4 r) ZQtDisigner配置% L7 P- {* m, f1 h1 }3 d

    2 Z1 j7 [5 N) W. Z在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:9 Z  }/ O1 H* }) v4 o
    1 \0 R# i& H  ^1 x) \; h0 z) |- ^
    Name: QtDisigner: c0 Z" N5 a+ h. M+ h# ]
    9 L! n7 M; S; K
    Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改
    ) t5 F3 i) S' b+ F! e# {3 e1 G5 h! Q8 z9 V, E5 ]* X# V1 S7 k
    Working directory: $FileDir$
    $ z. N- |) Y3 q9 f/ LPyUIC配置
    / _, Q8 F4 `1 k& ?" a* ^; g( b4 q& _
    , j" p1 o  A5 k( i: w0 C' }5 |9 x: s8 ?PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。! B5 }) a* g' S

    + f$ M# e4 {6 U在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    * t% |- ]- F" P% t4 u* o9 M* E9 _9 k! f- R0 ~
    Name: PyUIC1 q4 D( H3 \3 k+ G0 M) c
    , _6 ~+ B3 N+ w9 {/ E$ ^# T# [- Y& L
    Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改
    % T3 I  K( q' R% t7 e0 N" G- X
    6 Z5 r4 F" M. i7 N+ S. D: [Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
    # [2 C& K  q9 k, {3 P1 G4 X' \0 D/ [2 d1 V, p8 d4 q9 e5 G
    Working directory: $FileDir$* R% _% g8 b; Y: y  U
    PyRCC配置; }" c2 h; g" H: h

    % c7 m' K; Y' C: z6 ?& t- vPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    ' v; c5 P. T4 \1 h) M  k7 n+ X5 K3 E  S- r  n( `# h$ p0 f
    Name: PyRCC6 C4 ]1 c5 Q# F9 k! c; a

    5 r7 y( I7 U; G" Z* QProgram: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改- n( Y0 ^. V  m
    ) `* A! y% @. s1 o- C
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py2 }7 _9 l" K; L

    : G" G- N% Z4 ]/ f9 gWorking directory: $FileDir$
    + @& n* R6 g& G& U9 X+ vPyQt5使用示例, W# S; T9 j. Z2 d( x9 K: o) a
    " v7 g! H% ?7 f& u
    创建一个空白的界面:
    , x9 ]8 W+ |* d5 f) f8 z8 j; T& b4 O' v0 f
    import sys
    $ C* A1 N* z  `. Q; Y0 I2 _  W& R! d) a! w) K& I
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    * K9 D; @$ w* @1 C! j% n7 ]) f# \
    app = QApplication(sys.argv)
    , E& t( R: |1 y+ F, h1 E9 U
    3 E% k9 ^2 Z4 u4 Hwin = QMainWindow()
    3 q( _: y9 p  n4 I  P
    8 V/ c: ^: M$ J; O* i3 C7 Fwin.setGeometry(400, 400, 400, 300)$ X  M% h7 d0 ^1 M. T3 I1 I

    " r' N# D/ Y5 X* _win.setWindowTitle("Pyqt5 Tutorial")
    ' s% i9 I) Q& R2 o; f2 `
    8 j8 N- b+ M$ e6 J2 Twin.show()/ p$ D1 Z% Y$ W. q1 G
    9 g* D9 Q  _& m+ R
    sys.exit(app.exec_())  y9 `) G! y" |& c, o$ D

    ' k6 K& ^0 D0 d8 z
    5 t9 P- N7 v- a$ _8 E5 q- L. G. J' x0 m4 _
    其中:
    5 k3 j9 C# {# r( N* b, E
    * G/ J+ E7 t- CQapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。
    ) x/ j# {; i1 A$ d) Q
    2 b5 H! l  I1 _" r2 U, H% _QMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。0 w  H  {7 Z: e" a- b
    * z% t/ z* G# O9 u* }
    SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。
    ' Z+ c5 N* B2 H3 J" h, O& e6 V/ g' y% S2 O* {4 f! I
    show():用来显示窗口
    & Y5 @& g' v8 \4 `& n" ~  ?
    ! S2 Q# a% ?7 ^8 n# j- gexit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭
    / F% `7 x* ~8 I5 T( |! R  \/ |1 q6 ^+ ~
    PyQt5支持的常见Widgets有:
    8 l  e0 ]0 s' u1 b6 F# i+ |
      J: z$ U8 A' @: m, j2 h; M( W, j% }* t/ V; i+ W5 y' x
    9 V5 ^5 T/ K* i( e4 v6 u
    从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar1 P3 X- {7 ]6 T

    8 H; }9 [5 |3 L# ]9 k5 x% L( M对于使用Pyqt5设置文本内容,我们使用Qlabel:
    6 Z7 V1 j. q+ r) F1 g, f4 L( o  c, K) Z) j
    import sys- p9 z$ \, s( |, {
    ; M6 Q% _( C% n
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, g/ ^6 `3 I/ M/ b2 g( V  }) o
    3 \4 b- C7 _7 J4 U. p( N
    app = QApplication(sys.argv)
    7 P; s; m' e9 F/ B) {
    0 _. d( U) L- Y+ i7 Mwin = QMainWindow()
    ) {! |+ d' V3 j9 ?. J7 J& J  g/ K* v8 y- I
    win.setGeometry(400, 400, 400, 300)' W% R4 X$ j: L! ~
      V2 |% T/ a# K; R2 }* C7 n, X) v& B
    win.setWindowTitle("Pyqt5 Tutorial")) l+ ]0 I0 H- `) A% `5 m% o
    3 T. Y7 g0 y6 F5 E& z, A
    \# Label Text
    8 M, r' F( T# C  F7 l
    , J7 ~# n. H  r- z8 K0 tlabel = QLabel(win)/ \! `/ ~: r' j- ]

    3 a/ V5 ^$ }+ f' Plabel.resize(200, 100)( [$ b0 `9 B4 U/ m

    3 H; V! }! o; l) _7 C8 O0 Plabel.setText("Hi this is Pyqt5"), D: u: `$ B. X
    + ], V2 o" q: J  u' i# o
    label.move(100, 100)
    / R! Y2 U  J% x, u; [( V
    : _# _' v3 o" r, W* i9 n% l* owin.show()
    * T( i+ I  Y7 [, B; X) Z* C
    0 A% l' m6 f) `  I1 ~, R9 z1 D8 W3 Csys.exit(app.exec_())/ Y/ \: M4 O  X/ u- l6 m" i8 T

    5 n1 q7 h7 p$ F' T; ?
    % J/ s- f: h) V2 v1 l5 c2 r2 o
    # u, Q' E: E0 f7 k: |) S按钮与事件:
    4 D1 R0 m( f7 M- k# \  Q( m- Y7 x- @7 ]- C
    import sys& {, F! z- h7 t: k

    ! u! o+ }/ d$ y; t  }from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton3 T- o* L# ^4 v& _

    ! W1 j* J1 e. R& {, Udef click():
    : K" N0 G# f+ F: F& X' {; ]
    3 }- P' {4 C" n. _4 W    print("Hy Button is clicked!")
    1 m+ N1 x# q2 X6 E5 \1 ]* M
    / T- Q7 c& w, Dapp = QApplication(sys.argv)3 @. Z6 M' g3 G; U. M: @& c! ]
    # b3 ~3 F$ z1 z" A4 m8 a
    win = QMainWindow()
    0 p# ^3 q- ]) O
    / {0 a/ h: s8 Z! Mwin.setGeometry(400, 400, 400, 300)" m5 x- r, P9 ]7 [9 G3 n: u! {
    ( w3 e/ r, o. n  {
    win.setWindowTitle("Pyqt5 Tutorial")" m: i- a/ M, s, n0 O8 W* W0 r: U

    - {( S; k1 c& n/ H7 C\# Button9 o) z" c+ t: k3 M: L, x+ B: `" v9 x
    6 b7 c- }! e, Z1 {
    button = QPushButton(win)
    ) A/ `$ M6 S! w8 X: ^
    3 [7 Y$ q" z+ H! A6 nbutton.resize(200, 100)- \' L+ D$ S: N8 B0 {: G3 W
    " }$ G$ Q3 H( s" G
    button.setText("Hi! Click Me")$ ^3 K5 ?, U; W8 q

    / A  w9 E5 @3 y# Y  m+ a6 kbutton.move(100, 100)
    ( i& X5 F) D8 e5 j5 a0 r
    3 S3 W% d9 f9 D' gbutton.clicked.connect(click)
    , ?! P) Y5 c; |$ U' Y9 i5 ]7 R
    : i# ^9 K8 w* `' ?win.show()- _: W/ D/ `, _' ]  `, Y( K/ r
    / W  |$ s2 C, S% J& H: n
    sys.exit(app.exec_())
    - i# l9 I/ l2 r3 l
      j! ^5 O- W# L: w6 q( p0 g& c$ y6 z
    # I" b! y6 m. x0 y$ u
    button.clicked.connect() 在按钮点击后执行特定的事件。- x1 G* _, X* x3 F; P. g& j

    / V: Y+ z/ g6 _3 @' u9 X5 a- nPyQt5实战
      p  n- H6 t& L5 D+ ]' t) o/ T/ @& r/ [$ d
    实战项目:简易的天气查询软件0 `3 {- {4 y8 v! n! X
    & O5 {. J7 m4 M7 R
    1、使用Qt Designer设计一个界面
    1 @3 y$ c- ]. }6 |0 i0 e  v( @
    . _. s; s. D) Z( D6 O
      l. E# w) q+ b
    . v# R: }9 W8 m9 ~4 T2 u9 L用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:- m6 i* W% n3 m, O  j

    - V' F+ `3 m+ I, j% B在Qt Designer右下角选择 信号/槽编辑器,点击+号新增
      E; S1 ^3 c/ G) w# E
    ( y& u: J3 Q# P0 ?分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)3 ?3 n! ^! P1 _5 Y& ^6 g; F# E
    & c; W  X1 S7 @% L' u
    以上完成后保存为Weather.ui文件。+ P' h2 v; w  B& S" S# {

    , P; D7 i* f; F1 z' V' o- A2、转换.ui文件为.py文件
    8 L9 `8 E4 Z% \: V; O4 i% T9 W$ Z* `: I/ n* s9 f
    PyQt5支持直接使用.ui文件:7 E& h: j, w- P( N6 ~# @& B

    . d7 J+ ]- R8 u: s5 b2 C8 W2 [import sys
    0 }' o/ c7 @# x3 ?" q
    5 B9 z6 _& \2 Q- n3 A# Z" L& ]& ?. zfrom PyQt5 import QtWidgets, uic7 w! ^+ a3 V$ L" ]
    6 m1 Z& H9 T( f& P! A; X  {
    app = QtWidgets.QApplication(sys.argv)
    3 A1 ^4 b8 F1 ?; B7 C0 q0 E8 v' I6 Z4 d0 B2 a5 H
    window = uic.loadUi("mainwindow.ui")
    0 o5 H* w) V& Z" l9 ^$ c/ |
    2 u  R- f- N! o" l- t( M4 t6 ?& xwindow.show()
    5 z9 b4 @) F5 t1 A2 N+ s% a, c" W  x, D% O
    app.exec()* }7 f0 A& C' G2 N) b
    但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:# H+ J. g! E9 H( U. @
    ) Y* ^0 H2 v% z- O/ E% Y
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py& E! o0 H( b% b0 \; Y
    其中,我们需要把两个按钮绑定的槽函数:7 [" ~# y$ O' S! K6 o+ J3 h

    % Z1 U0 O# j  V' C( L- ?/ R5 G\# self.queryBtn.clicked.connect(Dialog.accept)
    : \; W! |& U& E1 o" A' v1 u  G, O
    , s) g8 h3 j; v+ R\# self.clearBtn.clicked.connect(Dialog.accept)
    4 r. H5 P! [8 i# V- E- {9 b# n  N- B* a1 h+ \' @
    \# 修改为:9 U8 p1 ?( c! a* E
    4 J7 N( h6 k8 Z6 F1 z' s
    self.queryBtn.clicked.connect(Dialog.queryWeather)& l9 Y/ K9 N- W! P' G
    3 b+ o8 Z) G0 y- [
    self.clearBtn.clicked.connect(Dialog.clearText)
    2 c5 R3 g. S% x+ X: f" i/ F最终的Weather.py内容如下:
    8 n1 O+ A% w* G! A! Y2 W( g6 T
    ' Z- b9 B/ h4 s( Y0 ~\# -*- coding: utf-8 -*-+ R; d3 O# T; z; ?7 r1 B  ]! v8 }! a! r

    6 n: I- R* e' M- k9 F/ }# S\# Form implementation generated from reading ui file 'Weather.ui'
    5 L/ |+ Q8 M- ^# Y6 \+ \* [9 l# M! {; q9 |
    \#
    " @1 K+ z& Q5 ?+ u- O7 x" M) |* r% t2 |2 S
    \# Created by: PyQt5 UI code generator 5.15.4
    : k! ], J- P4 W; i' L; F) A( t' o
    1 K4 l/ D/ w/ ^1 U$ V/ A  L\#
    ' e2 Y( e" T6 @, ]/ g9 |+ @- d, G9 t' p! b- i) f
    \# WARNING: Any manual changes made to this file will be lost when pyuic5 is) p- Q# Z9 L- q" I

    9 t0 p1 n  W, M4 q0 |4 _\# run again.  Do not edit this file unless you know what you are doing.' f  ~8 l6 n  R) h( t1 w! p8 q
    + O2 r3 n& j; u. U+ [" ~- I6 N
    from PyQt5 import QtCore, QtGui, QtWidgets
    5 ~) t( x; K% |' D
    7 r: \! N8 F2 V( Xclass Ui_Dialog(object):
    ' q5 O+ e; c1 z( ?3 q1 l# _1 V! _8 ^7 W5 }5 z# H7 k
        def setupUi(self, Dialog):
    2 q/ Y/ Q2 p/ A; I/ l. Q( k) ^6 ^8 {5 L9 s' p' M0 H# l
            Dialog.setObjectName("Dialog")
    # p1 |2 \& A/ a8 v0 b9 Z
    : A1 v3 @- X  r9 g" M! Y2 `# J/ h        Dialog.resize(600, 600)/ \' x8 N, t- @: a' {5 H2 u
    / I5 U+ W( ]+ g1 ]4 [4 Y6 s/ B
            self.groupBox = QtWidgets.QGroupBox(Dialog)) Y6 {& S) _7 C, M, ?9 ]5 S
    / \5 j+ @/ ?) l+ A* v; U
            self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))
    0 r7 @: Q: y6 ^3 i% \' B4 g. Y$ i; `$ b, ]$ X& W4 M, I
            self.groupBox.setObjectName("groupBox")
    , k: V+ ~" q' C( m, s7 z
    5 u; u9 S7 B' ^. a% h        self.label_2 = QtWidgets.QLabel(self.groupBox)
    4 Q& j* t# Z9 V* ^% E: t8 ^
    * a) J/ F4 P4 A/ z1 R        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))+ P- Z" y; v# [: I3 w$ E

    $ F1 Z; m7 }0 O7 K: z- n! U% C" U8 L        self.label_2.setObjectName("label_2")
    8 A/ h8 X9 x# B" O6 [2 H; ^& P4 z/ Q2 A- V
            self.comboBox = QtWidgets.QComboBox(self.groupBox), Q0 S0 C8 b  e3 s1 n# [
    8 W; F. z# H# a# N1 Q: ?6 |1 X
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))' a/ Q  U3 z' h2 @) l

    * B( V) |- ?1 n" S0 ~3 M/ F        self.comboBox.setObjectName("comboBox"); o& I7 n. f( x) v  P; s

    . z  S2 x& M, z4 K, ?        self.comboBox.addItem("")
    2 O9 K$ A7 G. h+ D9 h% }
    5 m8 W; H2 d: T; \! S- R        self.comboBox.addItem("")
    1 Q. q& ^' G, a$ `! l5 s4 F
    # G9 Z1 t& j; t0 F: M4 S        self.comboBox.addItem("")
    2 v7 [) G3 ?6 y, P& ~
    + O' q2 g+ s) c" j7 a: I        self.textEdit = QtWidgets.QTextEdit(self.groupBox): ^7 |+ T3 Y( z9 J1 ?5 U

      a4 ~0 f, G) x( W& J7 i0 }( G        self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411)); j. H3 p3 s  C
    0 r4 W" j3 y+ z0 b
            self.textEdit.setObjectName("textEdit")5 A7 Z0 v- Y# ~4 A7 n8 B& U

    ( j- n  ~4 e6 S; Z# }& j# P        self.queryBtn = QtWidgets.QPushButton(Dialog); ]" `# K  b5 J

    & e$ d3 _5 e7 o* L, s        self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))" ]$ l$ I1 L* ]0 a2 Z

    ) Z3 m) K* t$ E: d1 p& ?        self.queryBtn.setObjectName("queryBtn")1 @  u3 U$ Z4 _7 c1 E5 \
    ! w, A- q' i2 F7 s7 h
            self.clearBtn = QtWidgets.QPushButton(Dialog)
    $ m6 z8 L1 z$ E( {. \) U3 N6 K* v: _' i$ g  T7 f* P
            self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    & @6 u! Y8 f; B" u, X# k0 n* u9 G  k4 m  ?& O9 X8 ]1 P
            self.clearBtn.setObjectName("clearBtn")
    0 a9 |3 V' w. g
    " P3 \6 T" H9 k1 [        self.retranslateUi(Dialog)
    + m" R* }( H# g1 _: @% x
    , k  Q2 l$ n6 J6 O' H& g  Y5 Q+ ^        self.clearBtn.clicked.connect(Dialog.clearText)
    ' w: d: I) ?: m4 x% G
    3 Y5 }) |) p" M4 c* f! O        self.queryBtn.clicked.connect(Dialog.queryWeather)+ ]  a/ i. ]% ~0 j7 @- {0 D! U
    + s% ]8 w- E# X( G* e+ u) k
            QtCore.QMetaObject.connectSlotsByName(Dialog)
    % Y: @; d7 F2 j* Y
    ! T/ e8 D/ Q6 U1 A: C; z; v    def retranslateUi(self, Dialog):( K1 m! f" n9 Y# B( c1 r5 E
    * Z+ B5 e5 _  e, c
            _translate = QtCore.QCoreApplication.translate, x2 E1 h( e& l( ^1 }9 O  W

      y2 _7 T; W1 E! Y6 v8 D' Q        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
    + B; b" M% d9 |/ u+ n  P
    7 ?* @4 E  M1 r9 B6 Y        self.groupBox.setTitle(_translate("Dialog", "城市天气预报")). W0 m" }- x( z9 S5 W+ s2 A/ ?+ |

    7 r3 [* }# S) E# g* F        self.label_2.setText(_translate("Dialog", "城市")): F9 B4 `* i/ m+ Q, p$ w+ V
    : p) u1 r. c' l2 y6 ?1 ?
            self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    " C4 N" n+ }  P" i- l$ p
    1 D3 D7 B6 r) c4 z& H/ R& k        self.comboBox.setItemText(1, _translate("Dialog", "苏州")). K! t/ }. k$ _

    ' f1 g7 a, N9 W$ N- f: J        self.comboBox.setItemText(2, _translate("Dialog", "上海"))
    ) a: x' x/ L% y
    1 [0 N6 y. A2 ?0 P4 n        self.queryBtn.setText(_translate("Dialog", "查询"))+ t( l8 k6 c' r1 |6 g
    % |* B2 G+ ^3 @7 a1 C2 z
            self.clearBtn.setText(_translate("Dialog", "清空"))4 \% ?4 V" e, b5 W9 l

    ) {, k& U$ D6 ^1 M( T2 b3、调用MainDialog, f: Q7 W, b& W$ n. K8 F4 F
    : ^  p' _# J  X- ]
    在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
      v5 I6 f/ s4 i, R6 s& D  e
    2 D2 E, S5 v& l% ]6 M完整代码如下:5 ]# P' r/ Q' A  e3 e

    / x3 V2 F2 U% t+ h+ y/ zimport sys/ D% W# M4 }$ u

      w: ]! ?1 H1 S9 y% ~import Weather9 z, g4 q5 Q; c7 j8 u3 b  @
    ' p. F- M6 G8 v8 Z
    from PyQt5.QtWidgets import QApplication, QDialog
    6 u2 W0 D, Y1 v  r, V' ^( z. m+ S& m0 ?; S; D, p7 r, g
    import requests
    % W3 f, v8 G- w  K8 j7 Q, y
    2 H. O# S. J+ Lclass MainDialog(QDialog):
    ) O$ V! |; r; Z! [1 @5 }+ [
    ) I" R( O2 C% }5 H4 ^- k4 T' H' p0 E    def __init__(self, parent=None):" M! B* l: m8 `9 t5 W  `
    . r4 {9 K4 `5 J. w+ N+ ?/ [
            super(QDialog, self).__init__(parent)
      F" B) r# M6 R% u- w3 N/ K: q: s+ r% d5 D
            self.ui = Weather.Ui_Dialog()" K$ N! o: h: L, @2 R
    0 k7 j+ |( _. @" e3 B& a+ o* v
            self.ui.setupUi(self)* T$ \: ~  A& j* ~
    ; g% `; `1 L- j' A' y+ }; D
        def queryWeather(self):
    8 d; R/ C+ P. G
    2 y8 O1 D' O) o. I9 K        cityName = self.ui.comboBox.currentText()
    1 b" p( y, X5 Q8 |4 J9 c+ G! S# b* }
            cityCode = self.getCode(cityName)
    ' x5 `, p" o( G3 e) }3 h& d$ @
    : d' E! t2 F3 c        r = requests.get(% U: E$ a6 `8 d% S

    $ \: B6 a- N: ?& V( `            "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(
    + A6 B$ D- M- A, ~7 U
    8 ~4 x& [5 Z2 E) i$ n                cityCode))8 t/ v1 V; n5 j, ], p

    5 |. {& n9 l) A1 X+ L% |        if r.status_code == 200:
    : l1 [2 t' [1 a( ~( j8 S
    ; k% z$ J  i9 c6 q6 B! O* e' i) T            data = r.json()['lives'][0]% ?0 n: Z9 M0 ^5 r  ]/ F# F

    # b) h7 f  F- F) q9 q+ L            weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    $ f  l6 c6 g4 z* M5 }4 F/ s6 G% n+ M2 W9 s* E$ y( u/ f
                    data['city'],
    9 P+ Z$ c% b! c( d1 x* z$ _
    0 s8 h2 q6 l; P3 ]                data['weather'],
    / t/ u& |" j! o4 h+ S1 y& H7 @
    9 f( |, f( ~9 h( F- P                data['temperature'],
    6 g8 H; d* H& E- n2 x! C" A. B. E* ]" x% F% m  |, p) b. r8 H
                    data['winddirection'],! }; I) s4 d& R
    5 l, n; X9 ^, `4 Y+ L0 H8 c
                    data['windpower']," w+ b4 e4 G3 H1 ^) R: b
    * l/ N, S5 {. m# |) [1 B! U
                    data['humidity'],
      P( K  U- m4 a- C2 H5 B* N. A' K* P9 {4 s4 G8 J' R
                    data['reporttime'],+ g, C2 f4 w" T1 @
      v9 [. ?0 Y$ @5 K% q
                )
    4 X3 u+ R7 J  D% m- V
    4 [  B: c; C9 ?: U7 S        else:( X0 {5 F' e# b) m. B* Y) F/ e
    . \1 K/ \! N& p
                weatherMsg = '天气查询失败,请稍后再试!'
    . S6 ?6 t+ o9 T8 x" i) ^5 q1 s$ |. Z! w0 C$ \* K
            self.ui.textEdit.setText(weatherMsg)
    ( N. N% y3 x$ E" q9 ^1 m4 t* U2 V; I. j" N6 }5 ]
        def getCode(self, cityName):0 O. J/ i- h8 g. T& a

    8 D+ H0 p7 Q4 y: Y7 d1 K        cityDict = {"北京": "110000",6 L$ s/ k, Z& H' G5 Y4 j

    : q" e7 Q/ O: X5 I1 n9 w5 m                    "苏州": "320500",
    # \& H( }" z6 s) s" l$ ~/ h: A5 C! n5 ~
    " I3 _+ P8 o' I. ^                    "上海": "310000"}. @( S2 C; I8 f* a2 _; e( y

    : N' [1 ?' D0 X, g4 ?* Z5 K) Z3 n        **return** cityDict.get(cityName, '101010100')
    , q; {9 J3 b' N+ c
    ( a: E% E5 c' I+ U$ `    def clearText(self):
    6 I4 Q+ X  B/ ]8 K% \) \9 t9 h/ k, }6 g/ o. Z+ E1 z% P4 F
            self.ui.textEdit.clear()
      {$ Y; @2 L3 h$ }0 s4 \; M8 j, E* @8 z
    if __name__ == '__main__':
    4 R& e  t9 C5 @! Y
    ( y: w: E+ ~- N7 _  j1 d* A    myapp = QApplication(sys.argv)7 j9 [) A" A! m+ |8 R6 P( J6 O
    ; r0 s0 q, U8 H% ?+ R' Y
        myDlg = MainDialog()
    5 B4 G6 U4 h1 S+ K7 F. k7 ?& M" R7 |9 e# T, Y
        myDlg.show()4 s7 L8 M' H& k0 B) l

    5 r0 _: g3 h) h. E# ^! ^+ o    sys.exit(myapp.exec_())
    6 k9 U7 y# z3 D4 T/ A
    ' Z2 e: H- d* a/ M* H; d6 p运行demo.py并执行查询后的效果:
    ) q. F1 Z: |" S2 [/ `# M& F( S4 d( r( {7 K

    - k; l2 X7 A2 H; i' }* m! X+ D3 `5 u
    & Z' P- @! G& ~: r  u' ^4、将代码打包成exe文件5 j0 H7 ~3 N" u, G5 |
    : ^) }5 \' J1 g$ B' `3 r+ k" F# u
    将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:1 l% s! @* L. ]2 X5 [

    ) V& O  c/ z7 n1 e4 i  D  t" `6 d+ e$ [* S" J( W' q
    4 d  e9 i1 R* i2 `+ k
    py2exe:软件更新已经不活跃,因此也就略过。
    4 p9 \% l) M( R6 z( W$ c9 d
    . m/ Z4 B% v, W/ {0 }; Xpyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
    % |; f+ v' e5 U6 e. x9 q7 ^2 L2 }- e0 ~4 `) e2 `) }. q
    fbs:基于PyInstaller,使用起来更加方便& U  v2 t9 p, t2 L  @# e0 C

    " [, B* X8 T" o3 d6 K6 }1 F$ Z( m  m这里选择了fbs来打包。fbs的安装方法:9 t8 g; N: T  W* N1 n) W! U

    " C2 s$ j, Y1 J5 lpip install fbs
    7 }& L( M* W  N1 }. N: ?, M& [/ g1 y使用方法,在命令行中输入:0 C7 W5 S: s6 r% \9 Y
    + d( T) c, Q# M3 W- T
    fbs startproject
    9 e2 ?$ o- }) ?, j, j执行完成后需要输入一些APP的名称等。完成后会生成如下目录:9 D' O8 s! v9 Z5 K0 x
    3 K1 t7 N8 c. E( q
    6 `' |, U8 p8 ]. @  R" P

    * x3 q& r: R, S将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:
    0 P5 H& B% O+ U* u- f# k
    6 i5 a6 y% w! {* E, M4 G. gfrom fbs_runtime.application_context.PyQt5 import ApplicationContext2 k: Q  p! f. N9 [/ ~# d! H
    ```
    ; M) }/ r% v5 k7 r: m& ]完成后执行:
    9 g6 Z2 L3 P0 R& ^+ G; G; @. y& v```
    : o$ S! X- v8 }6 ~! K6 bfbs freeze
    & _  ^8 x6 U  \* |* T2 a& p3 @! |```) K7 E- r- p# W9 G
    即可实现打包。生成的exe可执行文件在\target\MyApp文件下。
    8 j, m: o, \$ F' [& |2 b# h2 z! ]6 D. f& ?: t5 q5 x8 u7 C9 K# p
    ————————————————
    : }+ H; ^" m% g版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    # i3 A4 c: o' m( c1 _2 p原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667
    * t/ f/ v" g( ]& s5 Z
    7 @4 M$ J, a8 r, K. a8 s: n+ V- ?

    7 f2 _( I" i1 E$ W4 a2 J; d" ^8 X
    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-6 22:17 , Processed in 0.417122 second(s), 52 queries .

    回顶部