QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2232|回复: 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使用指南!
    % f5 f" u3 f2 [" z7 U# r3 v! I7 [7 z9 ?& t$ j
    使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。
    5 o* ?  u6 q3 E! ?% v# l+ {/ |7 j  K/ F: T$ p, y/ t* B
    常见GUI框架
    ' y4 a. R3 }9 D& b: v. a+ m
    ' V5 }+ x+ i, }; M' v, i% aPyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。" x/ _9 U$ T' u8 P5 V' B4 b1 T/ \
    + ^' m% h& k0 d& t6 }: b. `- |. A
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。' S# A) U7 f7 q* T- m# l
    & y( t0 o2 A4 P& j! d
    Tkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。0 x5 l3 C) G  F. u4 n5 D, i
    2 _! b! u" v# M. t* @: O
    PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。
    9 p% k; e$ J' r; f1 }+ [
    8 g' }' O1 Z  h! U) ^" U5 ~4 bWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。
    + t8 s" C4 I# H- z9 M3 V
    6 ?1 {7 h: c" N* }9 C7 I7 s- TWax:基于wxPython ,为克服wxPython的问题而制作的一个包。7 E. }% w# q" I/ u
    1 i$ [& M, p, |3 V5 H! r; x
    Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。
    5 @$ F/ M( H* b+ {. u8 U
    ; e* {# |7 h) z& m. i; k6 d9 wBeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    6 s" [& q& [/ j$ r. s- O& f
    4 T: f- U! {+ j' M+ H) e% tToga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。3 I1 C2 P* e5 {
    1 I3 g, [' [9 x. X
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。$ a4 ^9 J; |/ f, w2 s6 x

    # s- E2 _( E# S3 S/ f4 mFlexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。
    ! p7 Z! |) \! I" u/ z; z( R4 ~- |+ }8 D! d8 p8 c
    pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。
    * ~; t) Q* P6 A. G% ?
    ) n) Y6 k6 q4 P  Menaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。% N( Q( E+ L+ I1 u
    1 V+ Y7 _0 f' g% S) O
    个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。+ Z4 g1 j/ [4 |% V1 [, W

    + |! W, x$ U# s7 R/ e/ bPyQt5简介/ L, t: W/ F$ R3 p( N: I3 ]& Z

    3 U0 `  m: t6 ]! X0 PPyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。
    0 s+ m2 U, ^; w+ Z0 {* N, U* k. v, \* m
    PyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。& _. @& |' D9 h5 P; \( b

    7 C  U0 R6 Y* X1 ^$ a) N9 h& DPyQt5特性如下:
    # r3 o2 Y0 G; I  G
    9 I! Z1 s5 J1 n0 D* K基于高性能的Qt的GUI控件集。) q6 ]" G+ H1 P) P) J$ Z
    + O2 ^& t2 `4 E* Q; w& B# A7 ^
    能够跨平台运行在Linux、Window和Mac OS系统上。( G) B& C- [/ ]6 r$ k

    * P3 f5 s# y) \# ?- M$ y使用信号槽机制进行通信。
    . I& M& o0 V3 u& L* b
    4 Y3 P% m* K3 ^! Q对Qt库进行完全封装。& K) y% E! H' L, N

      R* l2 v( u' q# E# Y, E* c可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。
    : c" w4 j2 f3 F1 h9 u" u; z  I) h6 ~- ?( R6 H' a
    提供一整套种类齐全的窗口控件。2 F5 ^, q4 M( k1 Y* S8 k) k; v
    * f. K, r8 @- [' I
    PyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:+ m7 b. k* K0 g3 Y  d' I
    4 u2 I7 [3 k% w& A% c7 K
    QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。
    * x8 H+ l# {8 [( ?7 ~: `5 N1 J, }, G* g3 G
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。
    7 B5 P) B) K  ]* i$ ]' C
    0 W4 B" j6 ]/ i; n. rQtWidgets:包含了一系列创建桌面应用的 UI 元素。
    . L0 v( q7 L; l
    0 m9 R9 g. d9 M2 {& u; V  ^8 `QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    4 U. j! F( X1 o2 Q- i
    , F( ]$ e/ t5 Z! LQtBluetooth:包含了查找和连接蓝牙的类。
    ( h6 L1 X$ q3 u# |
    + a3 q% R9 B  l) H% z8 IQtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。
    6 [, h$ X, T, M
    . C5 K: U! d; \' C; |6 w% bQtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。
    ! x8 [1 l. B, C0 Y# ]1 ~: P6 F" W+ c1 d+ V8 S4 D# l
    Enginio:包含了通过客户端进入和管理 Qt Cloud 的类。* y- @! _! z4 V4 |' H1 G+ ?, ^4 z

      X  x8 \$ r/ F' }$ a3 uQtWebSockets:包含了 WebSocket 协议的类。
    % g' b& M; p6 K+ ?( n* v/ s, H' ~. W" p% x8 ~
    QtWebKit:包含了一个基 WebKit2 的 web 浏览器。
    . K; a/ h% e% M0 R& j
    3 `# ]7 c8 ]& H& O: MQtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。
    $ }* |. e  Y  A$ l, `9 m# l6 V
    % J, P/ n1 x8 z1 t3 k5 P2 sQtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。- o7 Q7 N% o% V4 {: @! O8 D

    / R% L- _2 b6 h$ d5 i3 v) DQtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。
    5 ?+ H! l$ Q9 J7 U4 ]5 \2 y1 q
    1 F2 ]& U6 p3 h# ]! w  f* n, sQtSql:提供了处理数据库的工具。
    + z" s) h% d, T2 Y5 F6 Z$ [( }0 D" k# b$ N
    QtTest:提供了测试 PyQt5 应用的工具。. z' j7 l- G' k' L. b# D! Z

    4 m7 [: `" n; \. I* r( a, SPyQt5的安装
    ) L& M% ^/ I9 M( y3 E
    : g! _# Q( s- M; Z2 @* q* N由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5
    # [0 F9 q3 V( {% Y+ r) I! Q$ K; ?& T9 v4 A3 ~6 ^
    安装PyQt5
    / l# V' Q$ \# D3 E& F% W& ~# ]4 J
    & X2 l4 {6 X$ n* ^( E7 i( W2 Q+ Hpip install pyqt5
    # P/ j& j, `" x( s! z( n* S* G; d6 n
    ' S. c9 z9 X# S; p* Ypip install pyqt5-tools# N6 w$ J2 ?( @1 b1 c$ f; r
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    , K* o8 l9 t7 U% A" f; ~4 M
    5 i& _/ q4 w: j* a6 Eqt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
    , m7 ?( ^- B+ r0 U解决方案:
    9 A/ [: b6 Q1 v+ f/ z/ p: A7 K) H& t: M1 E" P
    pip install click~=7.0
    8 ?6 }( X  V( i* N/ h' U8 T: bQt Designer的配置! T, [/ O+ ~- h6 N

    + n! Y" W4 |. J; }Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。8 z3 w  p4 m3 g) M

    ; x2 k1 K! U  Q! k' Q. Q: ^
    + t6 N1 E/ y2 e$ U+ `0 B. ~$ K) q5 _" u
    整个画面的构成:
    + v9 N2 o0 G+ z
    # r: U) Q5 m7 V1 Y; W4 U左侧的“Widget Box”就是各种可以自由拖动的组件$ t8 [) D. z, L9 h1 B7 p- u
    8 a7 ]1 T  R# D6 v8 }
    中间的“MainWindow – untitled”窗体就是画布
    : H4 t/ G3 k' F4 W
      @8 R# s: l( j( z右上方的”Object Inspector”可以查看当前ui的结构% J! j- r# `7 B5 J1 c$ R6 d) ^

    3 H9 f0 Y$ a3 m: j( K8 t, p4 I右侧中部的”Property Editor”可以设置当前选中组件的属性
    ; T  v6 t0 p" L
    4 c9 }+ E6 h  l: ]' \0 w% n9 h右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等
    3 }1 A9 Z7 p! w% g4 r1 F/ \! A5 ]- g* {
    最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。6 c/ D1 ~" ?' B' T3 y& u
    # t& @+ {4 x! q# n; o1 G; a
    QtDisigner配置
    7 P/ }- h2 I5 H3 _: |" t2 p
    . z2 k3 \5 J& N% [在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    9 H: m: v) v) k$ @( F( j% p2 a) w. a  _0 s7 P8 B- x* v
    Name: QtDisigner
    ' N: d, K  i2 H
    8 g8 A# \0 R# ]* Y/ y" C1 i' JProgram : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改
      p$ T0 j2 J" `6 s4 M! v! ^- |& l: k2 @9 M1 x2 f; V+ g
    Working directory: $FileDir$2 l: P* D  F' ~6 `/ q  O
    PyUIC配置5 l: `$ W2 _( t) ?

    : n: J; z+ V8 A& G, e9 t) ?PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。
    9 e$ \7 u! h- {, T# V; Z7 j- \. A, S7 S- N
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:5 T- G3 K( C& f9 O; a% B& ~

    ! q" e' d1 Q. A8 N# r8 i  iName: PyUIC- L2 ?. S5 H5 v* ~# ^& F
    % f) d; \8 h1 T! U8 w
    Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改
    ( }4 w9 D/ L/ I( y; u
    9 o1 [0 e- c, ]% w3 G, w8 B$ |: NArguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py* {) }; ^, d" \

    , _- U5 i. t& P, b: oWorking directory: $FileDir$
    0 t8 O1 u0 y1 y! \PyRCC配置
    . m! i. v, P1 v
      W& @9 F, H' s3 n# N: X# Q8 \# s; QPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:0 e! Z% T+ o" a
    : R" M5 B4 @* Y1 m) j7 X/ A3 [
    Name: PyRCC; x' }/ ]  T1 Q7 ]6 i
    3 Q0 M0 x8 F/ q6 u2 P
    Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改) F0 ?2 Z  b! M2 Z
    8 n) [6 n  f* n$ M2 o# q7 N
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py, W5 i, \  i% ]" J# v' Y8 }
      {- k  C& O: ~
    Working directory: $FileDir$
    % A7 M, ?+ H# t" ~& JPyQt5使用示例
    6 n% ?6 T4 z* l0 ?+ `0 K9 ]) Y# g, ?+ d
    7 w) |4 F0 q6 Q创建一个空白的界面:" d  w2 m9 `/ P" T" s

    4 T" Y0 @, e9 k  w: aimport sys
    # e+ E- u- t  I# z' M4 D# _, X# C% I! `
    0 e: V. a; |1 y5 L2 y, Z# g) w9 R( d9 Zfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel4 @0 D7 D: x5 H% Q. [+ R# v1 W3 C

    # Q' v3 H1 R4 ^0 F/ {app = QApplication(sys.argv)
    ( T2 i: x* ~# a* y/ d3 {) g
    ( d- @+ P* c0 U2 q0 M% [/ c: ^win = QMainWindow()3 m& D4 D+ X+ ^; J2 X
    ( s# G" J5 d. x" C7 L' H0 b) v
    win.setGeometry(400, 400, 400, 300)" b6 L7 l7 b0 V1 q3 D2 i( }% u
    # h: N! ~6 {0 ?, I5 x
    win.setWindowTitle("Pyqt5 Tutorial")
    9 y" o2 M! ^# b, @0 D- I, K" h- Q& {% H6 Z  p
    win.show()
    ' r. W: {+ Y  [% q2 _- s$ [5 G
    5 R1 X' ~: V  P; s  gsys.exit(app.exec_())4 Y7 c! ~5 L2 S( p3 b
      N* g& n7 c0 V, m' O" |; s
    " M, t, N0 C0 q# N: ~  k

    ; p6 V1 g6 D! O. R  f1 Z其中:2 q9 [& T! y: }
    , Z$ O: n  R# g) n5 x
    Qapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。
    8 [6 s( M) {7 V4 }6 H: u$ W& E+ U" ~+ W
    QMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。
      L0 h2 u- n, Z6 R5 b, a
    5 E* O& u5 y1 E5 _SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。/ q5 k5 H# G8 A) f/ m
    ! i0 b. ?4 s; }) p5 j9 B7 M! h) g
    show():用来显示窗口( X+ w( z- p2 h9 r

    ! V! D4 c! E: X- d8 m* x. @2 a6 Dexit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭
    , e4 G" \# y' B- X) l
    : A6 Z9 _; r- U: }* \: e' rPyQt5支持的常见Widgets有:
    8 W7 l$ }- q9 B2 m1 B7 D$ ]3 I" D, q; p) R! H  z( s
    ' r# i4 G2 b3 f( a

    : k0 ?# V# T0 G% T: z7 k从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar
    ) l1 b  L- p; O) ~$ V) i/ F; i* B2 s" ]
    对于使用Pyqt5设置文本内容,我们使用Qlabel:$ \' n) r; v1 p  W# |) H! O4 S
    ( {# Z3 b7 l, X0 }( L# s
    import sys! D0 @# y" E4 |# Z* i# Y1 D0 d4 Q
    - E- j" J- R9 e8 E
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    1 B  Z7 K9 W+ l% Z% M6 X& `1 ~8 l- Y. L7 e6 V* B' w+ g
    app = QApplication(sys.argv)
    4 Q0 \, J# l+ [" y6 i* X4 I+ Z5 S' l* a; o; Q! c9 b: C2 w7 X
    win = QMainWindow()- H% O) j( G$ L, h# y& K8 R

    . K7 w& k; M1 N3 L7 wwin.setGeometry(400, 400, 400, 300)
    4 K) h$ U0 X9 u) L# A
    ! ?5 v2 {" A1 r1 Bwin.setWindowTitle("Pyqt5 Tutorial")
    & h* E( z% W, {9 V2 m4 _6 R
    0 X3 E% ]( ~4 I9 g6 x- h\# Label Text
    2 X& t+ S2 S; z1 `9 k% {" [( z& X- E! U7 q: B
    label = QLabel(win); O5 P9 d) M: g" Y+ t4 S

    ! ^4 _$ n' P4 L& B0 V; Jlabel.resize(200, 100)" K9 A9 N: c( j. k
    9 @1 h+ t  R) I/ s0 W- l2 H8 t; T
    label.setText("Hi this is Pyqt5"); ?$ p) Q7 h6 o8 K: y
      R/ w/ K! o" ~' M5 o
    label.move(100, 100), x, u. B" I) m- [1 M
    * r) ^4 x# W, N, |# G
    win.show()
    ! q/ b, B. S7 @+ x5 W/ V
    ! j" r7 W& {4 x- t7 F- g% u/ f; Xsys.exit(app.exec_())0 `- C3 v( J4 c4 L' e
    ; K" L/ y+ q) D. H# X$ ]" A3 t

    , b4 ^- y9 J6 Z
    2 ]. }9 L- ]; ^; [8 p. M8 x按钮与事件:
    * k/ ~7 K' g/ X4 M0 T1 ?7 M
    $ n. `% m) q7 v, [0 \/ J8 K5 F! uimport sys7 w8 |7 A& n8 W7 a, o0 u

    1 ^7 N( R2 \; Q! V  K( Lfrom PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton3 p( w7 m1 o3 n1 v/ `- j( C' ]

    9 i7 G  X% ~! X9 w" {/ ~def click():
    9 r/ ?6 \, u; z* s& x6 D: ~4 _4 X( Y! m# L
        print("Hy Button is clicked!"), }- n! W6 ^) s' T7 }
    6 f' Q1 b7 ]/ B& Z! y2 k# q  j4 {
    app = QApplication(sys.argv)2 K) W) W# g. m% w

    # E! y9 X1 I( W9 M' vwin = QMainWindow()
    , ]. W( b( N( h6 Z( K  U4 x* [3 {2 d) z+ j
    win.setGeometry(400, 400, 400, 300)
    6 `' X  |# F) o) H: N, O' @1 K- N# ]5 d1 ?
    win.setWindowTitle("Pyqt5 Tutorial")
    + K! {- k. f, Q7 ?5 i  L2 H8 {
    " }3 n, p. J- j! _5 _\# Button
    % B, s# F) X- _  z6 m& q# p! N; N" T9 }' h0 k
    button = QPushButton(win)
    6 U, \# W  G) K( b( S
    + u; t3 V1 G( a2 k9 r' Ubutton.resize(200, 100)
    ; f7 Q0 H3 L. E% V5 {1 F6 A2 R$ s8 R$ y1 }
    button.setText("Hi! Click Me")
    * R/ d) u1 b0 l
    $ h2 H* U) [9 S# \& ibutton.move(100, 100)+ e+ U; g- V0 y5 g; s) r( c3 A
    + D( ?1 Z; x$ {5 h( u8 q2 _( l
    button.clicked.connect(click)
      b/ m4 ~, F4 V+ m$ l5 H
    / |; B2 o) i  j2 U8 L$ t  Mwin.show()
      ~) E1 C2 ?5 W; N* r  K
    ) a- ?  r+ N8 ysys.exit(app.exec_())
    ) D; V4 W8 H* U1 G3 L" Q3 d' }  ?7 V3 F" L1 [

    / Z$ [4 h) o! K4 }; L  ?
    ( C  {; x& z4 obutton.clicked.connect() 在按钮点击后执行特定的事件。
    - H: W6 d  T( [! i( W  ]7 w  Y& D6 H3 _0 X2 Q
    PyQt5实战  F' S6 k4 k9 \5 X& Q
    7 }: }7 p) G8 x, E
    实战项目:简易的天气查询软件, W8 @- k8 Q% v7 f- ^2 l( W9 M

    " @7 V' c) x) Z+ j1、使用Qt Designer设计一个界面& q( n- E7 ~0 i. c+ Q2 W

    + z$ O6 ?  j/ I3 f
    - w" B) |6 Q9 f! }9 \
    : |1 ~1 d5 }  V0 Q用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:
    4 F5 U6 o$ h0 r% ~2 D, X
    2 Z0 ]1 Z' r5 Z在Qt Designer右下角选择 信号/槽编辑器,点击+号新增
    - T; K0 G$ S# y
    / u5 a7 s; q; t9 Q$ d分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    * {3 ~6 m+ F2 i# y  v. k  d& U# ~; n) O
    以上完成后保存为Weather.ui文件。
    . ]- ^5 a8 N& {! q; P5 Y
    ) o0 E' o/ C8 t# e) q; ?& Z2、转换.ui文件为.py文件8 E( x" }  W5 ^

      N6 J$ d( b+ k# E: \1 ~5 jPyQt5支持直接使用.ui文件:% n+ b' i+ y$ N. ?, T4 A
    8 j9 ?4 f* H9 ?5 L; T0 F
    import sys
    * B* V: P4 E! j/ K9 ?
    2 r( n% f1 ]+ M4 }! Mfrom PyQt5 import QtWidgets, uic7 T5 u4 T0 A" h) s
    6 B# w; {( c6 u( t2 \9 Z
    app = QtWidgets.QApplication(sys.argv)
    1 T" }3 ~  X9 X! V0 [
    7 K+ s9 n5 v4 W* Q. [7 qwindow = uic.loadUi("mainwindow.ui")# a" ^# p: ?4 b. Y; j
    . ~8 R# |9 |  z' {
    window.show()
    / v0 C, Z& R. K' {* p
    # H- e( {( O/ I" i6 ]" Fapp.exec()
    : c8 F/ t3 R. t" J. A4 t: v, @但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:
    2 Q2 c  ^. c* U7 v/ g7 J# J: V1 ~" n* u  h; Y
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py' C1 @4 N1 {- U+ G' f0 B, i
    其中,我们需要把两个按钮绑定的槽函数:
    ( l/ W, {7 f' V( Z4 u% `' Z& {% g% h5 A) I* X
    \# self.queryBtn.clicked.connect(Dialog.accept)
    9 a3 f- K! X& Y
    4 K8 e1 O3 A% A; m\# self.clearBtn.clicked.connect(Dialog.accept)' v  b; E; b3 k. l

    + O1 K, v8 @7 L8 G1 x/ N\# 修改为:9 s5 e% }: l3 f4 [5 s: V+ v
    0 K/ @9 \: [% W& I/ r9 Y9 G4 j
    self.queryBtn.clicked.connect(Dialog.queryWeather)
    ; G! y/ W) z( K4 z# o. d7 B/ u  G- P3 C
    self.clearBtn.clicked.connect(Dialog.clearText)
    : T3 O$ p4 X  c6 Y2 X' \' }! B最终的Weather.py内容如下:( g: z2 z4 P5 w

    3 \3 t7 z' X2 `. [$ b2 F- f! _) P\# -*- coding: utf-8 -*-% n3 \( \# ~  g9 ]8 W1 i- n4 ?

    4 \: h, |: G) |1 T& E' d2 @% I5 a\# Form implementation generated from reading ui file 'Weather.ui', e5 \" N/ ]0 p$ l% `! I
    % T/ F' f% A% x
    \#
    , Z* b: u) m! {& B. Q: x+ _8 m( }# a3 D% s
    \# Created by: PyQt5 UI code generator 5.15.49 m+ `/ V9 K5 z. ^- ]

    * v( U$ i8 \0 P* t' X' W- S, B\#: d  {- ]/ r3 W
    1 F3 }2 r) Y+ T; a- C
    \# WARNING: Any manual changes made to this file will be lost when pyuic5 is
    9 F# g$ y4 r' o7 z0 V3 V$ V8 I
    \# run again.  Do not edit this file unless you know what you are doing.0 e0 p* L, H/ \

      }0 E! l( N7 Q" z( H& I3 K% k& [from PyQt5 import QtCore, QtGui, QtWidgets& v& \' S0 q# T3 u: n! r/ i

    - G9 F3 ~$ v, G2 m8 b# j. Zclass Ui_Dialog(object):) n  p# b9 v% r* [9 F/ k6 v
    * M& e8 h/ m" i
        def setupUi(self, Dialog):8 @' L  p2 x. k

    2 p3 s; m( w% t        Dialog.setObjectName("Dialog"). s: a2 P/ @7 Y& b0 J7 }

    9 L: e7 e2 f$ O( N; t) T        Dialog.resize(600, 600)
    + S' r* P3 |( |. {. e
    % K, J9 g0 C" k1 m( Y        self.groupBox = QtWidgets.QGroupBox(Dialog)1 V/ K& }$ f" G
    . n( T& S% U! ]0 n6 [3 z+ d
            self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))0 L3 Z# L) i  a3 {( ?

    : N$ K0 ^0 _; v' ?4 K- }( B        self.groupBox.setObjectName("groupBox")$ I' s# P+ x+ E+ @3 P( R5 [

    5 B- k* O! m  @( l        self.label_2 = QtWidgets.QLabel(self.groupBox)
    . a& U* S. {7 i; J; w% E" _- H: ^5 E* J+ k( Y+ A2 i, \
            self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
    / Q) t# }& ]' g( J7 S  i1 w0 u8 _, L/ e; @0 E
            self.label_2.setObjectName("label_2")8 `4 `' }; G6 Q$ z( X: }" U
    4 o/ W7 V- H' M* l9 A# E+ x
            self.comboBox = QtWidgets.QComboBox(self.groupBox)
    ; M$ e2 c& P% I; d5 S! d) l9 l- Q0 I5 e" |7 N3 i7 ^! ^
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))
    # T+ w  ?; z. E! W; m
    ; H; A6 _# a3 u" e: F1 J( ^        self.comboBox.setObjectName("comboBox")
    # e# P! H3 @+ J/ J$ s  A6 Y& ]* L2 ^# W0 w; Z! G0 L: c
            self.comboBox.addItem("")% K3 M% Y/ Q2 |8 L: J, Z, b1 Y

    ) ]% e4 G7 D/ ]' ^0 p/ ]: q4 Y( F        self.comboBox.addItem("")/ r. K* Y& G- J5 P* |, p
    6 n5 d: F+ h8 M6 i1 i
            self.comboBox.addItem("")# `# |5 {# B1 I4 a3 C6 v
    4 u* S9 E/ _7 O" [, U# g6 z
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)9 s0 P+ b1 N9 N/ H% g
    & z( L( [4 C% e; A
            self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))
    6 O2 ^6 j1 k+ l' v3 ^, ~% Y! ^" W
            self.textEdit.setObjectName("textEdit")
    9 C" F9 `' l  x7 B
    3 _4 H! G* ]1 ^! G, q5 [1 e) z6 v) `        self.queryBtn = QtWidgets.QPushButton(Dialog)
    * J) w' L6 T' t1 Z5 v
    . l6 ^' \  ^6 A+ ?3 R8 F        self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))! m! f4 v. Y+ w
    8 x1 D( k& Y6 u) r: @. P! j
            self.queryBtn.setObjectName("queryBtn")
    ; {1 d* U+ b$ y9 T6 d$ p5 [+ i: z6 V( j# C% e) w
            self.clearBtn = QtWidgets.QPushButton(Dialog)' Q1 Y4 U; @* Z! R

    9 G  S. j4 y" Z        self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))6 k6 m( l$ y1 X6 I) W

    0 @+ L& t, }; c: u- C( N* U        self.clearBtn.setObjectName("clearBtn")& O' T- t: P9 y
    + L8 h, l3 N: i% G/ f8 [4 g
            self.retranslateUi(Dialog)4 p0 m7 T' I! f; U

    ) l% ~3 k* \% i! K) p9 W* c        self.clearBtn.clicked.connect(Dialog.clearText)9 y8 e' m9 Y  s6 b( }, ?" f1 m9 t
    % z7 n( Z' W1 A3 g' B
            self.queryBtn.clicked.connect(Dialog.queryWeather)
    " A" T7 y' x, q7 f  u  n6 c+ y! i8 r. P, S
            QtCore.QMetaObject.connectSlotsByName(Dialog)3 M3 s7 p$ T# [
    + Q6 f2 W* u8 y" B% @- q
        def retranslateUi(self, Dialog):8 l& N: R7 l1 K2 R% M, b$ {: W! m
    : R. N. @) W/ s3 r" v
            _translate = QtCore.QCoreApplication.translate+ |  |4 Y; Z. C2 d

    1 c9 ^. ?* Q& {, t        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
    5 U; h0 ?" Z" B5 |! u9 Y! v9 |3 p( I8 L! U2 g  \$ i& r
            self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))
    0 Q+ ]0 O7 M3 X6 i
    ; K, h, U3 C8 k3 b) o1 `: _. s        self.label_2.setText(_translate("Dialog", "城市"))2 s5 J0 D- E0 ]3 D2 @
    5 l' h) D: W2 O' x; r3 T$ e
            self.comboBox.setItemText(0, _translate("Dialog", "北京"))! G3 ?* [. d6 E6 A# N* ^
    5 h; @# A2 M& L# }7 p' o
            self.comboBox.setItemText(1, _translate("Dialog", "苏州"))
    + c# a) f' c* ~8 R- e9 i7 U+ o6 R4 {  `. ^! ]. G& z
            self.comboBox.setItemText(2, _translate("Dialog", "上海"))& @* z) F( @9 ~; s
    7 _5 L; ^7 m% J% ^0 K& U6 G
            self.queryBtn.setText(_translate("Dialog", "查询"))& a* f5 |; b2 ^% |$ L
    : A  a" t0 C+ m2 k8 ]4 q+ ~
            self.clearBtn.setText(_translate("Dialog", "清空"))
    9 R! U- Q% v4 [1 R4 r  W- v# e
    ! ]3 O% j  [; s$ K+ t. B, L  w3、调用MainDialog
    4 {" k  K9 B7 ?! v1 [" n! L6 Z  H3 T+ d2 F0 M
    在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
    7 T0 I3 G; y) X
    & B% ?6 U, N) A6 {" e' c7 e& t+ }完整代码如下:* u2 c6 ?! r) m( `5 r: n' Q
    4 n. i- f2 _+ S: N% X
    import sys3 w- O! l1 C4 j5 u2 ]/ Q

    . d. M/ O8 n' S: ximport Weather% Y# `0 r1 z% t; s5 ]

    + ^9 e0 N- A6 L, l+ t5 xfrom PyQt5.QtWidgets import QApplication, QDialog& @2 w+ X  ]. K7 f9 u7 T$ M- {
    5 }! q- @8 B5 j& t% ]  E9 q' c
    import requests% E/ ^5 E5 |2 f! o; [  M5 n; @

    5 A5 n- e" c& j, L" hclass MainDialog(QDialog):
    4 t" J' n, i) y. A+ y$ `* u
    8 S- V) P! |8 l) G; R0 w    def __init__(self, parent=None):" d5 Y9 ?5 G0 k4 p" W0 G' W! d

    4 v$ R7 s! c3 W4 C& y2 C/ o        super(QDialog, self).__init__(parent)
    ! i  s! O; U1 Q% k1 `9 K  m" L. Z
    4 G& k* j4 R: Q, k, I/ ^        self.ui = Weather.Ui_Dialog()
    ' U' S4 M+ o( o( _  R. E) {5 }, s9 {6 q9 r
            self.ui.setupUi(self)
    + c$ p$ v' t* C- M
    2 `# i7 Z3 y; X& c- m6 r    def queryWeather(self):
    # Z3 N5 S; h- c
    ( A6 H$ `# r/ m  {0 Y        cityName = self.ui.comboBox.currentText()
    , X5 L6 X) ~) C& l- Z. A6 j/ U1 y* [
            cityCode = self.getCode(cityName)4 I$ T! _+ b. E8 C
    , e/ P; R9 g5 Z2 a! ^3 w" w
            r = requests.get(
    % T6 ~$ H$ z, q- o$ z0 o  H. r
    9 E9 I4 }5 r2 o' Q' j* h; l0 o            "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(
    " \. l! O8 U1 n% T1 t/ ]( s. p) H6 c% J: H$ Y0 N: x
                    cityCode))0 C1 l" g. x% C! f7 ^
    ) P* D2 b, x6 X- e) J% e! a7 [7 T
            if r.status_code == 200:
    7 ]" ?: h4 Z# L3 a/ r1 s( Q8 V! d' j3 _+ {, H9 O
                data = r.json()['lives'][0], }9 O7 R5 L( t( G) G
    4 u7 [, c. ^2 Y9 t! e
                weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    : T2 ~( L1 t. @  J1 v  X$ e! ]0 P( U0 L9 r! G' ^8 N
                    data['city'],
    ) J$ i; q1 q0 E' l( g% e% Y
    2 C9 a3 W3 [2 |+ A5 R                data['weather'],
    & A1 c6 _' D& h: L$ X6 `  y9 @8 u6 M* S+ X0 r7 b! R0 w
                    data['temperature'],
    - j% Q8 t" ]4 r) L' h- O9 S6 U9 U. B
                    data['winddirection'],
    ; w0 ~7 s; R# N( D& L& `* `
    ) G: L& i" X6 _7 }8 f                data['windpower'],& ^5 a6 x7 Q- N1 F* A
    % |0 Q# k+ p( e" X5 S/ n/ q
                    data['humidity'],
    9 Z0 F; r- D9 A1 H+ Q/ i6 O4 Q4 t, L1 A/ G! C9 [* a) M2 Z
                    data['reporttime'],
    3 N0 d8 i$ l6 j  X9 @# {+ f  E; J# ]3 A: ^3 [: S8 I1 D
                )6 E% \  U- g6 i9 S* x
    * l. X# N2 _+ I( g. }. D
            else:# N2 J# n# T0 t. U, V% k; l
    , ]5 g. [' g$ V
                weatherMsg = '天气查询失败,请稍后再试!'. F1 I  O7 g- z5 s8 B  g7 e0 f0 s
    " }+ V! w) _" a6 Y5 L6 j  j1 T1 ^
            self.ui.textEdit.setText(weatherMsg)
    8 S0 [0 D9 g7 K; s, A7 S/ |- o: A/ k  I* m
        def getCode(self, cityName):
    % g, c) }( A; R4 o2 Y  \
    . D& h# l7 B7 _3 b! S. L        cityDict = {"北京": "110000",' I& C6 C3 L; l

    5 S( \1 I% v6 F8 r+ G, y) ]                    "苏州": "320500",
    ) f* s  e: [" {: M% Y! P* @  _. i0 X- c) e0 ?4 E$ m
                        "上海": "310000"}
    ' Q2 S' L. D' T
    9 O! C( t! E8 K# a' h2 c+ X        **return** cityDict.get(cityName, '101010100')5 S0 N( }5 u' g" o
    , K. x6 a% d1 N& a1 H$ ~
        def clearText(self):
    3 H4 C) F4 v2 B+ S
    3 a8 P( [) q( D9 T        self.ui.textEdit.clear(), K: |% ~$ k7 S
    3 m% u5 Z3 H7 Y0 M7 o
    if __name__ == '__main__':
    9 b1 o8 ?: u7 i4 [( v5 ]- i) z# j' G4 \5 g
        myapp = QApplication(sys.argv)
    + p0 F9 ]0 c6 o/ s$ o! K
    / u9 D6 \  w7 r) ^    myDlg = MainDialog()  ]+ L0 W. ~/ s. m

    1 t; a2 P. P1 w; w" f1 x    myDlg.show()
    ! I& P# I% k2 y+ |2 u/ W. c: E1 O1 n* [# m8 b
        sys.exit(myapp.exec_())
    8 E; F2 c# n/ K8 v+ m, e( F. q
    9 `7 @6 K: X9 O0 i( `$ [! o运行demo.py并执行查询后的效果:
    9 T2 w. J# f; b+ Q
    + N; Z2 {# h7 @) k) c. t' h! [5 j8 a+ l

    2 |3 J( W2 H4 Y$ C: x4、将代码打包成exe文件
    % a) o, R- j, [0 F1 f$ k! d2 v# A. n+ M3 I8 d. z+ [. H
    将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:
    . X0 a$ N3 A. n
    + ^: j1 a) n3 ~8 H5 y
    9 z! q6 D2 U6 Q- }8 B7 D& m+ Q' K8 g. D& p
    py2exe:软件更新已经不活跃,因此也就略过。' U5 P' l9 |6 B5 G0 O

    ! K9 r9 }5 i0 m6 Y8 |7 zpyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。5 q2 S6 m% a/ s1 G7 U0 e
    8 D+ G0 X. q0 f
    fbs:基于PyInstaller,使用起来更加方便
    $ c( O2 m  w: n3 e% O& i5 M* E& u4 G$ o# Z0 {# ~7 s: K" D0 p& Q
    这里选择了fbs来打包。fbs的安装方法:
    - n5 `0 F  L% g; ^
    1 }$ ~% ]; l; z4 Cpip install fbs. E6 o- `6 ~) M; O6 |* k" ?
    使用方法,在命令行中输入:$ n8 |/ x2 Z' E, X/ D

    2 _& C) B8 _+ p- y! @( |3 |. Ofbs startproject
    2 V% ]' y4 b% R* y# w执行完成后需要输入一些APP的名称等。完成后会生成如下目录:8 \: y8 c& r$ Z8 p2 d5 m

    3 }. A8 r1 r) S9 {
    + ?) F0 n( J+ ?- X" x9 c4 k
    8 S% o# G9 c9 g( L: O将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:! _2 Z; K1 Y  M5 [. H$ R
    3 H- Z$ c. g% s2 \. t! w% Y
    from fbs_runtime.application_context.PyQt5 import ApplicationContext$ H6 e- T9 |/ ]! B6 a
    ```6 e1 x3 {4 k0 M1 M7 T! a! A* K
    完成后执行:
    ) U* a( t( }: K```- a* x; k- C6 r6 p+ P# U6 i
    fbs freeze# V5 A% Q. Q7 _. F. Z. g; r( U) f
    ```( m4 n; w; T: d8 x; M$ z
    即可实现打包。生成的exe可执行文件在\target\MyApp文件下。0 x( }0 N) d/ ?5 D

    ; Q( r9 J% O, }* Z: l————————————————& ~" G' l: u% ~3 j
    版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。; N3 ]( X3 a, L  _9 p" e% ^5 J: e$ y
    原文链接:https://blog.csdn.net/qiqi1220/article/details/1262896679 N) t- o7 |7 O+ t' e' Z
    ! l" M( _; n  K( B+ x( Y

    1 v; G0 s8 B: V# g& W' I' X0 Y: g9 e
    & x8 d# p  M9 Y+ p+ q; Y: R! e
    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-26 13:10 , Processed in 0.431372 second(s), 50 queries .

    回顶部