QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2209|回复: 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使用指南!5 H7 e7 h0 u$ v, f' z! J
    % J5 m) L" u; P! y0 B8 d* M
    使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。
    9 y& q' v- K8 _+ @$ b4 M; k. z0 k: Z1 \
    常见GUI框架
      z9 P1 {8 l4 G  g0 ]7 R1 O3 U& C" n7 Y
    PyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。4 Q$ b, q. \" d
    + ?/ U( x" ?; _! K  S5 g
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。4 p$ Q1 h8 M& F; t, X7 b

    8 U% E1 W$ {+ K1 r8 p& pTkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。
    ( W- i- m7 c7 n% o5 ]* m- V" v2 b8 N! p+ Y
    PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。
      Z* j* `8 z" V$ \  i% `4 W; h/ A/ X) p, v. j) h. f$ h2 M$ ^
    WxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。2 j5 K4 e) S, O' n

    ; d# K: }& b. i$ JWax:基于wxPython ,为克服wxPython的问题而制作的一个包。
    ) H+ L" W# L- |2 [- ?' G; ?. o. c6 K" G8 Y) J" R$ `  I
    Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。
    * T% B# |/ Z) r. j# k- W" Y3 c2 d$ B* Q) ^! @& G' }
    BeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    $ x6 S; g: K$ ~0 e
    ) o. a0 @' r: t. S. W" DToga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。9 m' S- t$ N( X4 a
    3 W" [: Q" f  `' q5 ~, l2 m
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    * _* a3 w1 y3 Y! _  N- }5 d- f
    . ^/ J- Q( d8 sFlexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。
    ! L% |% g/ _9 M# }# u$ _. @) \6 J, m; B$ @7 U- d3 B9 z
    pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。2 Z: n$ Q' b# t

    ' l) |+ e& @6 p5 B& b" {( t" aenaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。) S+ G. T) ?( C$ I1 n; Z: w$ ^

    , B( W4 b( J6 }( G. n/ F8 M个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。
    ! }% U: k$ `! w# I2 ^' {* D1 [2 I4 j7 X9 \  H# I& f! M+ c( z
    PyQt5简介- O; C* \  ^; x0 `/ I9 ~

    2 T, p- t- `. x, L; n' YPyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。# m9 y! U8 z4 h1 b
    4 ?6 C8 k' `/ a" k) I
    PyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。" w4 E6 L/ y: p. L5 d0 P. \
    ; x; a7 A) A  V" M2 F9 n& E; w
    PyQt5特性如下:
    ) [  J+ ~. h0 q, c6 Y
    ! q5 f- x1 {0 v. ~基于高性能的Qt的GUI控件集。" N2 N" O, W# e/ W
    ; J+ B: [& N  A6 R  C
    能够跨平台运行在Linux、Window和Mac OS系统上。
    . D! D/ |" F( ~$ K/ N) X3 N: W4 c, C9 R& z
    使用信号槽机制进行通信。
    7 X' r$ G# K! H$ j7 y: ?* |8 E8 R9 N" E( C8 x
    对Qt库进行完全封装。" V- j6 u  b, r1 ~" i# P+ \

    ! d' P0 I/ }2 c9 S可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。& e  h; P6 I; o7 O

    * I7 h- S* H1 Y7 Z0 c  V! ]提供一整套种类齐全的窗口控件。) c5 G. U. f% s: l3 c% C, X" H+ S2 b! }+ y

      t' ]9 S. O2 L( a3 Y4 _1 ^, {& MPyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:% n3 O* Z# w% z! ?

    & L/ r8 o# Z5 Y) t6 O9 ?% v+ nQtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。  _& Y: w% V4 ~7 E6 A! U
    + f! @1 i/ i0 b$ b  S: X! m5 {: J: R
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。) e  P/ F1 s* j; \! j3 i# `

    2 ?3 @7 V4 o3 S5 M6 \QtWidgets:包含了一系列创建桌面应用的 UI 元素。
    5 S4 n# Y7 x* p- g8 [1 K
      _1 u2 r5 f, z& @: y! k1 fQtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。3 d# |, \2 e0 ]* C  ?

    : Q) I/ k+ R5 G0 _6 {6 q; dQtBluetooth:包含了查找和连接蓝牙的类。! V2 F& E  D8 b) x) I$ ]2 [& N

    * g- S; V4 o2 V7 s9 T' zQtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。( Z. @! M, D8 Z

    6 @& g5 U  ~( Z; o+ QQtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。
    5 W2 g- o, M5 L( x2 V2 e
    ! w+ Q" i( w& @% R1 y8 t" uEnginio:包含了通过客户端进入和管理 Qt Cloud 的类。$ L* u4 b; e8 K$ h+ K. c* d9 o

    & N: T  a) E& I: U7 P1 s6 `& |QtWebSockets:包含了 WebSocket 协议的类。4 B0 u1 h5 p% l
    ' G' m% `  ~- ^* j+ w
    QtWebKit:包含了一个基 WebKit2 的 web 浏览器。% O+ I' A/ O+ Y5 q3 S
    1 c( k, q8 b& r
    QtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。
    . R/ s- U& E$ ]& F6 V
    ; N" c$ e. B- r  P$ Q+ Y9 \* _$ |QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。! y6 C" o$ e5 Y6 J& i6 Y
    / k4 M# E- l& i' m# q
    QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。
    ' ]* Q8 S2 @# R' Y; v
    0 G5 f$ U. `1 [2 L! qQtSql:提供了处理数据库的工具。
    , b2 M2 j& L1 T# s% _3 m  K& P- o  Q. o6 F8 `% s
    QtTest:提供了测试 PyQt5 应用的工具。
    2 `7 l  T( P* j# Q, N
    ; ]: c2 i; A/ S9 H0 W0 Z2 u& \, S3 nPyQt5的安装' m5 Q  D" }9 [7 P

    1 [) u2 ?, @& \/ r由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5 " r% f2 ]" c7 c. T; I7 G4 O

    ) o$ d! ^$ D$ y安装PyQt5  ^1 F  I0 w. ]1 _* k0 m3 R

    7 h6 p+ J3 e1 d) @3 u- s) Rpip install pyqt55 D' k! p+ Z4 k& S/ c1 v, |% w

    ' R) z4 d  L8 l, J8 gpip install pyqt5-tools- s, a/ O6 O4 i# E' Z" v/ y9 c
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    ! B+ H+ K2 I8 @' ^$ \5 p% Y4 v* v+ ?$ n
    qt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.  S! j3 [2 w$ R3 d6 j+ g( _
    解决方案:
    # U$ @, Z/ C  J. z$ y4 n& w- E$ H) H% ^/ x  ~3 y: d; n
    pip install click~=7.0$ d2 `4 c/ @, O/ K. h! y' v3 z
    Qt Designer的配置
      F" S( q! ~7 K3 k& D
    2 [6 n9 ?# _: k) I6 `  pQt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。
    & L+ t" g- A* t% E! Z; ~1 i3 `7 {
    2 w6 K; G. }* M0 c# F: ~
    ' K$ g' y" i8 O7 Z
    * a3 c# b; U& Q) z整个画面的构成:
      o2 Q+ w& i8 N$ P4 U3 N9 T! H0 X5 M3 G/ X
    - t- |# ~! }1 J& m% O& S% y* u左侧的“Widget Box”就是各种可以自由拖动的组件
    2 b" H1 \4 H' D+ M2 j
    + l) Q1 ?: s5 t' V/ b! f1 y5 K中间的“MainWindow – untitled”窗体就是画布
    4 J! c  m4 F% E* S' v& R" s6 r  M& t3 Y3 Q! ~  T" R( O
    右上方的”Object Inspector”可以查看当前ui的结构
    * ]/ z6 Y& r. M+ W+ V  {  Z
    " V5 p% A' T" [, G5 b: Z右侧中部的”Property Editor”可以设置当前选中组件的属性
    / w: z$ q: u+ Y+ @# k
    6 A# w( U4 z7 ?% [% ]+ x右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等
    3 u2 S  _2 B$ q9 J) k* V8 b: W; b- ?7 O6 C
    最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。6 U" B7 i4 \3 }- q
    8 ~) s, {( _# ?1 J- c1 j0 w' `
    QtDisigner配置9 q' x) ^5 t/ i6 O* a# W+ f, c8 J
    0 @* I- l/ o8 [7 U( T6 h  L
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    , }7 t2 C0 G; C. E! i4 U, d# ?9 P6 B. c- s3 O1 d2 O9 o  C
    Name: QtDisigner
    + l' [0 E* B  |$ C/ P" ^6 i8 R
    ) k& r3 B" i$ t" L  K, s0 s" dProgram : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改; v( m5 a( Q; v$ l. k9 D. V/ @

    ! g: \5 J0 M( F2 Q" E8 {Working directory: $FileDir$& m1 _0 _' Y7 A3 O/ ~
    PyUIC配置
    5 g6 E5 D! w4 G: m
    ! m* ]4 n, P  V" \- G1 i  a( @PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。5 p- o" [# ?* b2 O, h
    ' l1 l8 h0 ?$ d2 {' R: w5 O
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    5 C8 D' ^8 W% X5 @- u$ Q; Q- P' [+ j0 A! f( `$ _1 [0 m+ q& b
    Name: PyUIC8 P; n4 R3 P* y& H3 h

      X# u& M3 P0 @5 _& ~( iProgram : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改  N) Y4 n+ c. L1 W* m
    ; d9 R# U/ m# E9 y
    Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
    0 T$ q: x: R9 V7 f9 h7 f% t, W
    ) F' D8 q3 ]7 \- y' ]$ ~0 y3 YWorking directory: $FileDir$
    0 R! V+ Y: M0 G- A& @: ]& F" O2 FPyRCC配置7 j2 u* f# z* G, D

    ( i* l' G# G) T) R5 ZPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:3 }7 l) u4 G* J- T# f1 }, A& c+ a
    + E3 T8 B3 g" D  \" d1 d9 \. P5 s7 ^
    Name: PyRCC" V# Q% m; t2 A4 O' v6 c
    / s  M0 u& i9 A3 f, B
    Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改
    6 g9 T! C. n. t* m* }$ ~; w6 [+ P% |: r; t# z6 H1 ?
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py
    - r/ A' J& F% |8 e
    7 x2 H& B* q. W& ^* MWorking directory: $FileDir$. W9 i! c+ D, o: `# s1 t
    PyQt5使用示例
    1 o" X, G5 k) ]. w2 D' v
    5 f4 e- t; N1 ^8 J5 K+ B+ \- B! `% B创建一个空白的界面:
    2 a- P. u$ ^0 O8 I; K( N: J; \* k7 |
    import sys
    0 E9 u4 ?0 |0 y
      v7 [% j8 H7 \8 {7 hfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    : q. A0 A4 k- H1 j0 J5 a
    4 @( s( w/ {5 R: ?' Papp = QApplication(sys.argv)4 H8 ^0 O) s/ v0 N! z

    , Q/ L" W4 p- M% J  Dwin = QMainWindow()( n( B0 m/ V9 }& s8 Y

    % x$ ~8 _. H' B4 p7 Nwin.setGeometry(400, 400, 400, 300)- C* D6 G5 I6 w- T8 B% a

      T8 K- u8 j8 e4 b4 A5 hwin.setWindowTitle("Pyqt5 Tutorial")
    ; \( A0 L' i; u+ k7 G) c8 a4 m; r$ q3 `- X5 k
    win.show(); ~, z% o5 ~% T( u7 B5 n
    . E, M- \! B3 D" c- {
    sys.exit(app.exec_())$ _% }% f+ R; T: K3 O" g6 [

    3 |! f3 N8 H" i  g% A7 D7 K' V% \) g5 N# \1 M

    4 ?  w& I" E) d( T6 _. ?/ `; R其中:
    4 N9 D0 b# l8 r" H
    3 m3 b5 ^4 ?: q8 J' q& N, i3 o# ]& }Qapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。
    & Y; G3 T. j3 ?/ j) b1 Q
    7 a8 A' E; d+ ]/ r5 q3 X7 D: EQMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。
    " X5 K5 w. e# y0 _% H) w4 [2 c# E6 H& c% E  w6 ^
    SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。& \2 ^, e' v& o" O* y2 S

    3 ^$ q5 ?1 G! m, k9 u' Jshow():用来显示窗口
      c2 U) v/ o" f
    4 R7 q& M4 ]; U  B' \) Kexit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭: g1 h" s/ t% |! B/ |, b0 m
    " r! e# F& ~+ Z. O
    PyQt5支持的常见Widgets有:
    9 K* z& f( a. L' N
    * q# V! s3 S8 E+ K1 n
    7 h+ b. {) f! P2 r, O: d$ b: N" G0 S7 z
    从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar
    - D/ h" N0 d7 V
    7 @% l) A6 O) \8 |对于使用Pyqt5设置文本内容,我们使用Qlabel:8 |, U! |" E" H* T# U7 E
    / R7 s) y* _! u
    import sys
    6 G, g3 S5 i$ T  G7 o+ w7 n( W7 v6 b5 P4 @( J: y0 Q
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    - Y# X5 j4 Z" c4 ?
    % p0 L# S; k1 X; z4 _app = QApplication(sys.argv)
    ( k+ x" F* v8 B1 x; u& a
    # c9 Y/ e: e( g( mwin = QMainWindow()1 E7 C' {) j0 ^) D; y
    9 u# d& w5 X* e& n( y* n
    win.setGeometry(400, 400, 400, 300)6 _* q8 ?5 \' w8 Q

    & k: a( ?3 u( Qwin.setWindowTitle("Pyqt5 Tutorial"); c, I% g! v8 U: ^; U0 M7 }$ N6 d
    4 A9 X+ d2 o, M- S
    \# Label Text
    * N. O- P) G; C9 e- R4 b) Z
    1 g7 J' x' g- W! _5 llabel = QLabel(win)
    4 M7 A+ M" B4 J3 n  ?1 A
      t8 {' F% j/ N' j' Ylabel.resize(200, 100)
    2 t# `5 R! ?: @+ H
    " x1 q' n. d, o$ C: W1 ^7 B" Plabel.setText("Hi this is Pyqt5")* t2 ]$ X- B- }& Q. p9 D: R: f

    ) f: o7 z2 i% o3 [' klabel.move(100, 100)
    ( Y5 b' ?/ c1 `* h. E, c7 F+ g8 B* C5 ]! a
    win.show()
    # E( X0 M' u. T: h! s2 P6 ~7 l; o1 w
    sys.exit(app.exec_())' d) S& j' r9 `& [/ \

    7 {2 X# V; o8 f4 B  A
    & E4 m; {, q0 G; x( m  B1 |# Z/ ~# F$ s! p
    按钮与事件:
    " v4 i8 `0 y. _% P1 v7 }6 r; M* i7 q1 F1 l& T3 v
    import sys. E& O& U4 x; i* {7 `% j
    ! J2 m1 Q* |9 Q% |  O
    from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton- I, ?/ h7 i4 e7 {$ T+ Z; l
    5 t& C& p! m  }2 N2 N0 }: W6 u3 g3 ~
    def click():
    / A# C1 s8 M4 {/ z8 r
    . w# V8 [- {. N    print("Hy Button is clicked!")( G( ~. F2 f1 d; \

    . A3 B8 t, ^" N8 h; _" lapp = QApplication(sys.argv)
    - j  \$ ?* c# K% J$ f
    , `/ z: b# y6 S" o0 O, V" Twin = QMainWindow()% o+ s( _- c4 O8 q, s+ F" A
    : l# }0 ]5 d4 ]& \; c  a
    win.setGeometry(400, 400, 400, 300)9 ?% u7 Z+ I! @
    . j0 a/ X0 {+ Z5 {
    win.setWindowTitle("Pyqt5 Tutorial")
    7 _( `: t) }) j1 S; l3 W8 H- x/ d5 ]4 E$ {5 B
    \# Button
    , j) A, [* y0 M* H  d: G# n/ O! c/ N& V; |! N) l# y, i" P  f- Z8 I
    button = QPushButton(win)
    2 @1 b8 L! E. ^8 E: v2 [# M% J, F" N/ i# K, k  q& z1 ~6 ]. W
    button.resize(200, 100)
    / K7 y+ S1 h: r3 q/ s" h& ~; f! N& y4 N# }
    button.setText("Hi! Click Me")6 U7 A5 b6 v* g8 o- \
    3 x% m' ?% v- L9 A4 _
    button.move(100, 100)
    " X) ^5 B7 c  C) d4 U- G
    ( c# L+ B+ s+ g5 r! v( r! x: D  G% s) Lbutton.clicked.connect(click)
    ) H. v+ A: m% o; q4 I( A
    7 y* C& _* ^& d$ V% e$ \win.show()+ M# b& D- U! d2 B
    * N* |. e) K! a, V) m, b% ]
    sys.exit(app.exec_())
    + Z1 c: j& l+ o, T4 H+ ~  S4 C2 i0 w: q
    0 V' C6 f3 B+ i# M- K2 O' A2 g; O5 h( S( }, y/ S) K# @, B2 U/ G

    - V$ ]4 q7 i' ?- ]  Ybutton.clicked.connect() 在按钮点击后执行特定的事件。
    * j$ A  j- P6 c' n7 O
    0 _7 \; E: a* A! ^. w! SPyQt5实战5 Z) Z& L( v0 H) D

      o7 z- L& P% p4 U2 L实战项目:简易的天气查询软件5 I6 g5 s# s& f9 f& u" h9 C7 u9 M

    ( ~7 C. d& t9 D5 Q1、使用Qt Designer设计一个界面& U, Y- N3 |! n  T+ J+ G  g3 ^, [/ |

    + S# r" A( T% F. ]% F- d8 R) ~# M( a% G1 X! J2 P7 R
    8 _/ p8 N$ J7 Z+ d; Y7 E/ }$ K3 \- D
    用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:
    ! W. U4 w; B* b: S9 _
    ; Y( L; U9 {3 Y3 _在Qt Designer右下角选择 信号/槽编辑器,点击+号新增
    6 y! x# P3 [* g. l: S8 ~1 b* ~! {( {3 W. B9 I7 Z
    分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    & i% X0 u! M1 V' ^8 y
    2 M& p/ @: g9 q& \0 h, N以上完成后保存为Weather.ui文件。
    & F0 J% v& g2 X) y
    # z1 w1 C) K5 `& L- m: m2、转换.ui文件为.py文件
    7 u% @% }" ?7 z  {( `7 S
    . t. u1 N# m' T. P* c5 kPyQt5支持直接使用.ui文件:
    ' X* I. k, [; e6 v8 C* i% m5 M$ Z; @( s7 l# K( |% ^
    import sys' _$ t( g  t  l  ^0 K( ~0 C

    ; W- {& j0 t- Sfrom PyQt5 import QtWidgets, uic
    % z/ E+ A. P+ f  F
    ) F# L$ v) b+ w8 Z0 X$ Capp = QtWidgets.QApplication(sys.argv)
    0 G  V9 e8 s9 b5 w+ I/ r( W# @3 A+ z
    window = uic.loadUi("mainwindow.ui")
    ) r. Q: Z& l0 L" a' ^+ t0 L% Y
    ( P, t* p; n2 a8 Iwindow.show()
    ! B* o- R$ H  r" {) [' I; U- o; b' H% l. |# m5 C. h0 T
    app.exec()
    - r* [8 A# ~; O3 ]" J1 h( F但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:" b$ T. b! ?! _% F
    % L9 s# ]3 o* ]' l3 b! d
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py
    ' n  }$ n) L1 _  s4 b其中,我们需要把两个按钮绑定的槽函数:$ r4 ?) W# |. K2 Y
    0 J! v6 m4 N0 P( E* w
    \# self.queryBtn.clicked.connect(Dialog.accept)
    8 x+ Y2 {% n  C# g9 v1 Q
    * Z* h7 c8 [/ z; N& G" h\# self.clearBtn.clicked.connect(Dialog.accept)  {& y5 X' H3 ?/ |2 q

    ' [, V+ U2 {& ], `! T" F! M\# 修改为:
    ' v& \9 Q- H$ ]1 g+ h
    2 b0 m$ o, G5 ~self.queryBtn.clicked.connect(Dialog.queryWeather)
    ; y; H+ E! x% r/ @5 i; I. c( U" f6 ?; f
    self.clearBtn.clicked.connect(Dialog.clearText)
    & L7 P7 ~3 h5 k" ~- O4 e+ I; x; K0 Q最终的Weather.py内容如下:5 ]- Q/ X; J/ M
    2 x$ W( t5 e5 ]9 ]7 [
    \# -*- coding: utf-8 -*-
    + N' W! G2 ]3 _0 Q2 u: s5 k  o& e8 z3 Z% @+ u) F3 Y8 x2 G' [/ h
    \# Form implementation generated from reading ui file 'Weather.ui'
    ! m" \* `: f, x3 W1 S" U6 Y
    ; i) F* y9 H4 O8 F6 w0 o" J\#
    ' x- ^" z3 s% A% k; ?5 m& o6 V3 T
    8 U9 p& }& c9 S  a, \+ I* ?2 E: Z# ^\# Created by: PyQt5 UI code generator 5.15.4
    ! l4 f* U" ?# B. v: L* y. ^) x' W' t
    , F0 [: ]% c4 y- d: O$ y/ z  e\#, r; v/ p! b: x7 I

    $ Q5 E' K. P/ G\# WARNING: Any manual changes made to this file will be lost when pyuic5 is6 o4 ^0 F$ G0 Q+ g: g/ g- h" M# m
    2 v8 a3 {6 Z1 c: l6 O! V$ n0 @/ N
    \# run again.  Do not edit this file unless you know what you are doing.
    . q! R2 ^/ Q/ o( V8 ~
    1 v, z( r6 V, D) Z( I& d' V7 j* gfrom PyQt5 import QtCore, QtGui, QtWidgets3 t; D8 k6 f) s2 J; `# S
    ) a- k- w3 V- h$ d2 s/ Y
    class Ui_Dialog(object):. i/ H1 `+ a( }8 j

    ) F; S* t% l% s- y! Z0 g( ]2 w7 B0 ]    def setupUi(self, Dialog):
    , j6 t" L2 D) Q2 e3 Z
    + |4 K  h) Q. [% m        Dialog.setObjectName("Dialog")
    & c& o9 c) |; j% f* M! P, D, ^5 y* b; y# B
            Dialog.resize(600, 600)' i2 G* C2 X) L  ?

    " {6 N7 J8 H5 O3 u- {2 t2 M0 |        self.groupBox = QtWidgets.QGroupBox(Dialog)9 U2 d  R* A( r
    4 q; ?& q: H3 ]. `
            self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))
    ; p; G8 B. }. \/ ^+ T0 P6 t
    " O+ U- Y6 F2 h9 l# `& e        self.groupBox.setObjectName("groupBox")7 \( w2 h9 Z9 Q  a1 |% [+ u, i

    ; b2 G! _2 _4 S0 I3 l0 M4 A" o        self.label_2 = QtWidgets.QLabel(self.groupBox)0 Z* U: L6 _/ O5 M: L4 f7 k
    0 U' z( g2 w) ^, ~9 a! \* j  `5 O1 I& R
            self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))4 d! B, s# W- Q$ a5 Z: m% t) ^
    1 ~! c6 C% {. R; T4 r, ^; }5 y
            self.label_2.setObjectName("label_2"); A: t4 w3 K$ t

    + \/ R. z- o+ e3 g7 ?6 e1 Z* U" }        self.comboBox = QtWidgets.QComboBox(self.groupBox)' K; H! w; ~# P

    8 l) t! [) k" U' z, C* X4 J        self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))- A4 o, \: q, _1 x5 ~& w
    - x4 A3 e* Z- g  [1 A
            self.comboBox.setObjectName("comboBox")
    ) ?! b' _: m! X# K, R
    % k  X9 j/ D0 |: ^5 p# j        self.comboBox.addItem("")0 M5 _  T; J( }$ I6 m

    2 m$ w" D! Y1 O* m        self.comboBox.addItem("")
    + R$ n* n& d! }' f0 M2 d
    , z" h6 o7 }! W) ]' X        self.comboBox.addItem("")1 H5 I7 L, Y0 z, h. b# v* ^$ j# W
    5 [5 T% p! E  s( C6 m7 p$ v2 R
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)
    ; Q: h) e! ]1 h& O( A% m  z9 C7 |7 k6 c! N; W4 A
            self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))
    5 H0 B! I9 x# \$ d4 F9 s
    ! i* z7 I) B" V; G) z; I        self.textEdit.setObjectName("textEdit")% p9 V6 {; s* {8 N$ H
    ' J0 p3 U% V5 Y2 w
            self.queryBtn = QtWidgets.QPushButton(Dialog)
    ' n) l! ~6 X0 E+ C5 k% p- ~! }& a% ^$ X& U% w% ^; F6 @5 e
            self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))
      {- Y1 p' u  d; n& c( q6 B8 J5 D; C9 F& Y
            self.queryBtn.setObjectName("queryBtn")
    / r: Q' ?" ^( u  R
    * x$ |5 Z* j* Z% i2 g/ Z        self.clearBtn = QtWidgets.QPushButton(Dialog)
    % Y' f6 t2 z: i. W/ y. h: k; Q  A5 Z1 A2 ]
            self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    8 y$ G$ h! u" q, V( r
    7 N3 t; {' ~. e' v        self.clearBtn.setObjectName("clearBtn")
    1 ?7 T8 f* j0 A) X% x* F$ @! Q: ~8 _9 t* c8 h  O
            self.retranslateUi(Dialog)
    , E- `/ N# y. w) j
    + F1 s3 f. X4 d* P2 [4 ~        self.clearBtn.clicked.connect(Dialog.clearText)
    ' O( d( f( l% d" J/ z
    ' x/ L& q( b8 Z8 v        self.queryBtn.clicked.connect(Dialog.queryWeather)) M& F$ P( z; [2 k8 ~1 Z. r; {
    3 f! e0 ^7 g# G% Z" T8 w
            QtCore.QMetaObject.connectSlotsByName(Dialog)
      n/ }# E; ~- Q8 C& X- U- F4 O# c# S6 m8 x
    3 h, `- C9 N; P& K7 J    def retranslateUi(self, Dialog):# Q1 @1 A+ Z0 E1 Y$ w* N- e

    3 E2 ]/ g2 O4 @# m        _translate = QtCore.QCoreApplication.translate$ x8 P4 a. h6 J" A
    - I& K+ ]" R" J1 Q* s5 u
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))2 S) T% C% A1 }. d  w9 Q

    5 m7 s. a/ W, C1 C/ B' N        self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))8 f6 g* _: d' Q/ n4 T1 }  b

    6 ~* Z! C( v' S0 ]/ n        self.label_2.setText(_translate("Dialog", "城市"))
    $ O8 O# @( H4 w. O- \3 \' x% T. u/ R; m8 o$ |% W+ K3 R2 f
            self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    1 U% i+ B+ V9 P% w- |: Y1 ?, k
    " W; x7 B$ ?$ b3 f8 F# @, Y/ m        self.comboBox.setItemText(1, _translate("Dialog", "苏州"))& ?4 f- X7 e2 S' \: u- R) u5 D

    0 k; x* l3 t2 `8 Q        self.comboBox.setItemText(2, _translate("Dialog", "上海"))
    5 [0 w, T4 o4 m0 v
    . n* j$ Q8 |/ N        self.queryBtn.setText(_translate("Dialog", "查询"))" k. t( R% ?( p+ U" i1 t/ m

    9 P) X3 H5 i& ]        self.clearBtn.setText(_translate("Dialog", "清空"))
      g6 t, ?  A; i0 ?, b6 a* _3 M* q5 V- Z& ~: K
    3、调用MainDialog9 z6 j, w' W4 L. R
    ; j3 \4 _% ?; t5 e  e6 C8 G! d
    在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。3 R, V, Y( u9 e4 g4 q0 r2 G

    9 E* X/ i$ {$ {; z1 D7 q6 g2 V完整代码如下:
    6 D) O( j9 ^5 P8 I+ U4 Q) A: W! {; [# \. D& P4 t, h# Y" X
    import sys
    $ {  c0 B! d$ }! k% z* V1 D. ^6 r" X- e! K" x+ e+ B
    import Weather8 \$ F* F4 T! U. z% @

    * g8 [7 m7 h  v( }  C: J' _. Sfrom PyQt5.QtWidgets import QApplication, QDialog" r( S1 Q! H. H2 d

    4 a, d1 k. A  \# T$ V8 n# pimport requests3 E) m- [: x, m, v) V' w
    $ N( j: D+ y2 z
    class MainDialog(QDialog):% I$ [0 y/ b- o# `5 w
    ; ^( r/ B4 a* e! g; w; v# o
        def __init__(self, parent=None):
    4 P; `' K! _- a* `  B: C0 s; r! p8 r: g' M8 [
            super(QDialog, self).__init__(parent)
    3 Y% G+ w2 G$ \0 `! Y' I% Y/ Q: t( q$ G% K0 Q+ g' N
            self.ui = Weather.Ui_Dialog()
    % c8 w5 U% R' v, p: y1 ^: k9 A4 |6 C' |) y! s
            self.ui.setupUi(self)" J6 S; h9 y# B8 |0 i+ B: q
    4 I. y& h% p; d. r
        def queryWeather(self):- }& k& h3 @. l" `! w' j$ v; e5 K
    + i/ r9 N4 `) C2 l# u# Q
            cityName = self.ui.comboBox.currentText()$ [% x! G3 x& z

      Y" e1 ?/ b) [3 @: A        cityCode = self.getCode(cityName)
    3 t9 k- ?. Y1 k5 ^; ]' ~" e7 V4 n, ]. D  O% b) ]1 q
            r = requests.get(
    % G) |7 X# J9 t  {' T; r& V4 l0 h( T' p! h
                "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(
    % @9 L' S/ E/ X( G8 L* L
    8 W9 }+ {/ S6 z/ q                cityCode))9 S" y1 `3 Y! {3 Y+ k
    % m9 E0 x& J0 q) {; H3 B8 z
            if r.status_code == 200:7 z7 \5 e+ Y0 P$ }

    - I! f1 V) X. A2 X. p* h1 J            data = r.json()['lives'][0], s5 X; b$ C) ?" }% R* _1 _9 {
      E/ Y. s* H/ e; U
                weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    ' n3 e% c) E0 `' P' C. b3 e% i, W- h# }
                    data['city'],
    6 q, U4 [& i1 e7 R
    # O9 }$ k; ?8 P0 S                data['weather'],, Y" q; n5 U. Y) I4 W; @3 M# i. s- V' E
    + A" O2 }6 `; V' E( D1 f: B
                    data['temperature'],2 d5 u. k- }8 Y- V
    1 r4 S1 e5 `6 e* u1 E
                    data['winddirection'],4 n: w" W+ j  P
    9 I% v) i( ^2 f' \
                    data['windpower'],
    . ^  v7 n; ]; z# k+ e
    6 ]9 \9 k1 G, w+ \) u; h                data['humidity'],+ O# h+ q1 K# M% R

    - y$ \4 }6 E; H; A" P/ ^! L5 {, J                data['reporttime'],
    2 Y* L1 T9 K( _/ k  ?% M/ A) s$ p! M" W2 \8 t
                )! I* _; c8 V! G; ]& C

    * |2 k6 T' S8 ?2 q        else:& L3 J$ i4 ]# c8 Z9 Y
    ; g& f% I+ L- H' Y( R+ ?+ b
                weatherMsg = '天气查询失败,请稍后再试!'
    3 t/ a" l! A& [: Z6 i
    ' P* m  V3 A# R% Z        self.ui.textEdit.setText(weatherMsg)1 t- |" Y; v+ [" R7 L+ L7 b

    * v" X- L- g0 t1 A4 J    def getCode(self, cityName):7 E$ ~3 p! Y) l: @" ~& w+ m. W6 U
    * f0 Q0 [8 V( w) b" x. o  V7 ^
            cityDict = {"北京": "110000",6 ]. [% T; ]7 u- ~, D. R7 k. ^

    # t5 [3 G# w' }" r, j: V4 m' r                    "苏州": "320500",
    ! A( y: M; D3 U  x: v1 W- U$ D. c7 [9 ^
                        "上海": "310000"}
    8 d: {: T' q6 c8 M4 Z! Z+ h1 f- Z& a1 ]* h2 F( X
            **return** cityDict.get(cityName, '101010100'), {6 A7 \$ L, `
    . |, |# y& f1 L4 t; ?
        def clearText(self):
    2 O0 S' s" H6 j/ a8 f3 Z1 R3 t
    % G5 e( T" F3 O& J        self.ui.textEdit.clear()* w  c7 K, p- d2 I! z( w
    ) q/ q4 I$ G' I9 |9 `; M
    if __name__ == '__main__':' }. y" r' H$ c  y# F$ z$ P/ {

    0 g; k% }) x* f$ c/ j9 m7 a    myapp = QApplication(sys.argv)
    2 f) I4 Q; ^/ b' v( d6 P( A4 b5 w: ~8 z' |) N7 }
        myDlg = MainDialog()# X  D4 O5 n- K: ?; a7 O5 D# k

    + [- w5 [$ j7 p  Z: b7 }    myDlg.show()* \2 S& j# @+ R5 i$ |' s

    9 [" t: l! t  b( j5 l( n    sys.exit(myapp.exec_())/ C/ o! o/ b' `( t. r. Y; O  }

    & |" O+ h2 |: h" P运行demo.py并执行查询后的效果:
    * E, Q8 A% o# o* t8 u
    9 I" v# M; {3 d0 S' e# D; m+ Q8 R5 }; O) z9 n" _. m) [

    5 y% C4 v0 H' j, j5 t3 k* a2 d7 Q; a4、将代码打包成exe文件" f/ q; z/ I: `: V$ t4 D' G8 @) Q8 s

    $ [! m0 p6 R2 S( s将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:& u$ i( ]- K/ B/ f  g
    6 {- A) `* ~, H4 o& }9 R
    1 \4 F( L( q- l5 E; u. m

    % o9 F! a0 ]& {. ipy2exe:软件更新已经不活跃,因此也就略过。
    $ R& m- Z) u) G' e5 C( l6 B) {$ N" o+ {$ B- l
    pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
    ) I8 f6 W" N- ]5 h1 j* u' c- I" I' |' Q, g8 r0 F% L# O
    fbs:基于PyInstaller,使用起来更加方便
    : h; q$ F& ~4 D" k( Q" Y2 _1 Z9 }. L/ n  [
    这里选择了fbs来打包。fbs的安装方法:/ f- ?: c' Z' ], M2 W( ?9 ]

      g# [( M, t2 I# ^( Npip install fbs4 G# t3 R' i0 o9 o. y! g  H
    使用方法,在命令行中输入:6 S  C' U0 i) D, u) ?, j6 A

    8 U* D5 R6 N0 S- E1 x, ~fbs startproject& j' q1 L4 m9 D- n
    执行完成后需要输入一些APP的名称等。完成后会生成如下目录:
    3 Y, s5 _7 I! g/ G: y8 @5 u6 z6 h# g# p" j
    " u+ E: X; x* A
    : n3 N" Y/ J# L8 H2 T+ d5 R4 p; s
    将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:
    ) D$ p! z2 a# f! u# k) w9 Z/ k- |) i4 F  N% f
    from fbs_runtime.application_context.PyQt5 import ApplicationContext4 z1 e/ B/ a" x$ t
    ```
    / j6 O" Z9 _' p9 ~完成后执行:
    2 c2 \$ W  p" _# S" X```2 @) D/ G! ]  X+ z0 N
    fbs freeze
    % i3 Z$ c7 x: t  P$ D```
    3 g! d$ g% o" K1 M即可实现打包。生成的exe可执行文件在\target\MyApp文件下。2 }! U6 H/ B$ B2 F% k/ F9 F- W
    ) x) P6 f# e+ @" C) ?9 A2 i
    ————————————————& B- W' t$ p1 `1 ^: h+ z
    版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。7 q" R' C  i4 w1 G
    原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667
      ]1 L& Q0 K0 k8 _; I2 D
    $ l: K$ u: I8 ^" l
    4 C% N% R4 v" m5 E
    3 U  c) K. h5 [4 o6 _
    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-6-14 05:04 , Processed in 0.840803 second(s), 54 queries .

    回顶部