QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2188|回复: 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 }, B' P0 L: _" R+ Q

    $ f( ~  c, o, u5 z8 D使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。2 p* n5 G8 K- Q% L% h1 E

    " R5 w- H+ _, k常见GUI框架" o, ?3 \/ w5 `: N, d* `  v
    8 w  d9 x2 o/ C/ p2 _
    PyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。* `3 M4 y0 K# X0 h
    # h0 z$ Q# J" `9 C
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。
    ! L. K& r. @, I" X0 H- L
    ( m" i  S3 Y1 c* `5 A+ m! M. \/ RTkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。3 \( O" y4 m7 ]9 i
    4 G* P/ u" Z) [
    PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。
    * b; f: g0 H% F6 J
    $ I% A; r* H! a0 e, _WxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。+ k5 W  Z/ j( H. J$ e

    8 M5 G; r1 w9 r3 q, _Wax:基于wxPython ,为克服wxPython的问题而制作的一个包。. x9 q8 \: U7 s2 j# }; H2 G

    " K' C& B1 W# j8 [% _8 m% Q+ {Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。
    7 N& Z2 R' `- k  D  a* s! _& @7 O* n# n+ c/ f% I- T& \
    BeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    % }7 {6 Y+ b  s& o# a- J
      F3 ~% q" O8 u: p6 l  z& ZToga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。+ n$ v# p. T6 Z8 r0 u- o% ^: z
    , j( e8 M% p3 \8 X* a( o; q
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    9 `" a% M) G( Z5 A0 Q
      |/ r' U9 D8 o$ h4 K- j; tFlexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。
      V1 Q# o4 T( N- a. R: }1 f: N
      i( J$ Q, {/ P" `5 Tpywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。
      t# O4 r+ o2 {: p/ O4 p3 F7 T/ n% _5 u3 `7 u! ~9 t# ?
    enaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。
    - q4 k' ?  {( z2 v9 J# i( M8 T0 x' I5 z8 w6 p9 d
    个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。
      C. h- q1 Q# r) j. j5 y3 v! [& o3 B% D* T4 _: Q2 `. R& I
    PyQt5简介
    0 h) P  F1 |4 }: ^! K1 S: N3 k; C" h: r7 b0 w9 s6 Y6 i
    PyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。
    9 Q$ N% S: h9 X, ~, K' g2 x7 E+ m# s
    PyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。
    / V1 t4 K- X4 c5 s5 `. C
    + n0 z! _0 p1 @) d3 w+ m; zPyQt5特性如下:
    : ]/ j8 V+ W9 W$ ?" `4 k! K- j' n  ^7 \# D0 Z
    基于高性能的Qt的GUI控件集。
    1 O5 [7 O8 |* ^
    8 d) K8 @- U# b! P8 C9 z能够跨平台运行在Linux、Window和Mac OS系统上。* Y+ {6 A, j" \( J# V2 }

    9 v! @2 J/ Y* B' l0 s/ \  ?0 Q- O使用信号槽机制进行通信。/ g3 L1 h; h9 E1 a; I

    9 Q( m" b7 s9 H8 M! h- k" K6 |4 ]2 B对Qt库进行完全封装。2 [5 D9 z+ D1 G6 R
    , ]. j: `) B& v
    可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。9 X5 i1 s7 u( V" k8 z( `

    1 L# b4 I3 o. E提供一整套种类齐全的窗口控件。
    & C( y# U; X( U! m6 T6 q+ n7 a4 t4 h/ _3 P+ ]/ W0 [' [. Y
    PyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:
    1 f$ t* e, k, J! V) l# ]# D2 Q4 B3 f2 a5 e" b/ T. [6 e9 C
    QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。" |+ G1 f7 q+ L0 b

    3 W: G8 F, Y/ a* r. @) fQtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。
    ; c3 B, P" n& u! U
    - c$ Z" ]5 s3 s3 fQtWidgets:包含了一系列创建桌面应用的 UI 元素。  d& w* Q+ j' C3 Z( F& i. S! [' A
    ! M- j# M2 B. Z- d: l; }* {
    QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    + ?3 x3 M0 a3 A/ `* t5 u2 D7 }# ~( t, T7 c* v/ w1 ?; v2 ~4 v7 h
    QtBluetooth:包含了查找和连接蓝牙的类。0 k0 n+ O1 C  a4 A9 a$ T
    4 z' {* v5 Q6 `
    QtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。2 s+ c% H4 v# b* Q- i
    3 V! Y) l7 ]: m/ E
    QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。
    8 C' f/ R9 B% B& i: w( Z/ p, D0 A- _/ h. O' ]% R/ D3 c
    Enginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    ( N4 X. A' f; F2 |5 M8 [) Z4 a. m/ T2 r. N, b9 \* F
    QtWebSockets:包含了 WebSocket 协议的类。* T) I. |3 B( Z5 N& M

    ' Z; W! X2 y1 O. u6 s: xQtWebKit:包含了一个基 WebKit2 的 web 浏览器。5 `. s; y* R: [$ ]0 h/ R) M6 D
    - j* j7 D3 X+ E% K) x# @1 [' J  I
    QtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。- v1 z4 O$ [/ V& a. f% q- f
    : j# f3 P, Z7 g0 l0 a. w
    QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。
      P$ |, ~8 ~- C2 i9 }
      D+ e' J3 O% x1 e+ Q$ Y# AQtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。$ E& T( w' {( H  z% ]  l

    ! l; Y9 G) [. \- Y: D8 LQtSql:提供了处理数据库的工具。& G! Z1 M9 X8 @3 L) X& }6 q
    , ~" V# R( i2 n
    QtTest:提供了测试 PyQt5 应用的工具。
    0 R; |, \9 v3 ^% U( \- V0 z6 f- Q, \
    PyQt5的安装
    / D6 S  P5 O( o5 u" x* w$ v+ p  O% R$ ]% e5 Q
    由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5
    . [0 R" `" E& a3 E! D
    4 s# J" ~, `7 y5 `2 t, M. o安装PyQt5& I  _  M2 W  ?9 M' a3 e! P; C
    # G- c+ h+ q% @$ V" [( d/ ^' p
    pip install pyqt5
    7 g/ C  A- i$ ~$ o, J
    : N. U4 ], h+ U/ D; J) ipip install pyqt5-tools
    $ G' |2 P) \" G0 {其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    ) B' t" F& H9 `, a+ z' v* m) t- ?* B) t) s, Y7 i
    qt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
    1 q( L: E! S. B解决方案:2 _/ p9 V7 a3 c" M, G( ^! N
    + N+ w# G# l- Z! @+ o+ U( I- {
    pip install click~=7.08 J8 w+ ~+ {$ ^$ K# x
    Qt Designer的配置
    & }# s# z, {2 H: ]8 c# k
    1 l( g! y& f$ u8 `; R3 A$ L6 x; ~# aQt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。, E2 A! x2 H0 v) b8 o  e9 V' N
    5 ]# F) A3 r1 u3 n

    3 J2 D6 V8 r+ [+ r2 ~  e* h) u4 A& `9 c# w
    整个画面的构成:
    5 s6 @, ?0 e- j
    , ~# K8 u) U( J( f' P8 I' n- t左侧的“Widget Box”就是各种可以自由拖动的组件
    8 g9 C9 V% v( \* [1 {+ ^2 K
      e; t: ?( j/ @! A. @中间的“MainWindow – untitled”窗体就是画布
    : ^# W$ q  n& Q" s
    $ W8 e+ d. Z+ N右上方的”Object Inspector”可以查看当前ui的结构
    $ ?7 E: y6 C- i  q4 M
    * u, ?+ Y2 j$ s3 m# t& m, L6 T右侧中部的”Property Editor”可以设置当前选中组件的属性
    8 q0 T9 e2 ]. V; w. A6 Q* ^. X- U- h
    右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等
    8 M& k! m' X; o3 s, U4 X' V
    4 G+ h  `8 g' P7 K最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。
    & p8 }; D2 ]0 k2 t. |
    7 e5 V0 E. P# q3 r& qQtDisigner配置
    / @; r( g- a) a4 ]/ C& C4 Q, w1 Q% l; U+ t  g
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:* P" n7 _/ t7 H6 X
    * p2 q3 L$ W& E' T
    Name: QtDisigner
    ) e8 t# A! b( E1 r5 v' R, Q7 W2 r2 Y
    Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改, H1 o5 R/ g8 I1 P+ _: q6 f  f

    . U' `+ }" i2 r9 o! h- Y1 R5 QWorking directory: $FileDir$8 R0 w) x9 E" ?1 }: t. s8 ~' z' c
    PyUIC配置
    , G4 J- y" x4 `" K' t9 F, B5 ~/ W+ G% i, N
    PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。0 n8 {1 T8 q9 L. _( [2 g

    4 n+ c- ^4 A1 ?2 c3 f, `在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    % A4 J) o3 ]8 f8 x. k8 j
      i( S3 b: B- w2 hName: PyUIC5 A1 U: i8 a. @5 X" x9 i' I/ ?; _

    % V% {+ B5 d- v2 P/ @& p9 {( tProgram : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改+ ^! Z3 K% Y7 O4 e7 K0 i1 b1 D* C" i
    # `0 B& H+ [5 u: C3 ^; b$ ^; ^
    Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
    5 j" a9 H: n" Y8 b1 z+ s$ ?: q! d! a" Z2 t! r& ?! l
    Working directory: $FileDir$; K: t9 L  ]- M+ P7 e4 a
    PyRCC配置. [% a/ C$ J0 k- V

    & t. ?; ^# \5 A( i, r* oPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    2 N( A7 w* @/ \* B; Z& p/ n% I; v$ ]- V8 L
    Name: PyRCC
    ( s, K5 @. l0 d' U4 t# ^# k. B& a! y4 p' c/ K  [/ Z  f# V
    Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改
    6 a. h; t9 T+ ?  c6 U! w' l! _3 r" z# X: x* u2 V
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py% R! P# d( V' u
    # X! ^/ N+ V5 `) z6 H7 Z# {  V+ E
    Working directory: $FileDir$; [( x  b8 @$ _: N  _- t8 u0 t
    PyQt5使用示例, g9 w6 q3 |8 Q( l, i8 V

    ( P  d: V& i+ O, O* ~. M创建一个空白的界面:
    # x$ C( u2 I; z% c' X: }  `7 a, z4 E
    - M3 Z* a- c/ cimport sys! P# \8 `7 y  Q' l& x; M) i$ y

    6 \; o$ \" i) {. Mfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    6 D& Z% r# c9 c$ u6 s- }3 L* @; ?, \2 x2 b9 J
    app = QApplication(sys.argv)9 T# S/ J9 |: |( h4 l# L# L
    / \% C) A9 C' `7 W4 |" S
    win = QMainWindow(). B! p3 e8 G# g; k
    $ U1 [1 P  d' I% p# _0 a
    win.setGeometry(400, 400, 400, 300)
    9 G$ \& t  D- N$ _' s+ G+ i, C& E/ z6 a# G+ j" z
    win.setWindowTitle("Pyqt5 Tutorial")$ I2 ]$ W# ~$ ]9 u  q
    1 k# [5 m; ?& B1 R  t% Y7 }
    win.show()! Y/ S- E! e6 j1 C4 t& e
    0 [/ ~" S& Z+ V& F- r8 o
    sys.exit(app.exec_())
    " e+ B- T: w+ F
    - ~6 _" e; X# j  r1 Q- G9 h* I! A* M. [/ y! B

    3 f' J# v7 m5 [& K+ C, d. S其中:1 W- V- d. K5 T3 U: V% I3 b

    8 S. v* l5 m8 p5 nQapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。
    6 Z+ f' p8 I; J- r4 Z8 \: h; w' I+ ~
      a6 J1 }7 N8 AQMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。& l5 h( D( m1 f7 }/ S3 `

    5 L, W! N8 a# U$ r% W; W7 ~SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。# w. E# c7 G' w( _0 U9 u+ r
    ; s- u& R( ~& d$ ^! `  J+ G/ z' x
    show():用来显示窗口1 b. D& O6 J7 }' g7 I# J8 P2 w

    ) ^) u& O3 K* N' bexit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭2 {0 \  s' L! m' j
    . s2 q2 `; K: g
    PyQt5支持的常见Widgets有:
    ; H! i4 u% x6 |4 e' O# J' P" `* K& r  K6 }8 y& F
    8 h7 R2 ]& F, k& C8 z
    & X! |: g" I! R
    从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar& i  J% H# A# I' j- L. n

    0 U/ m- [4 P  ^1 o" @: W4 K对于使用Pyqt5设置文本内容,我们使用Qlabel:
    ; M7 ^7 }* i2 A/ l' Q" B5 P
    0 W8 f0 {! a4 L5 V  g/ O) Limport sys2 i5 X/ e5 z7 `0 \* e

    ; P+ V! q  ^" K" k$ O/ }1 Hfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel) |) @: \* I& y9 q2 ?/ r

    2 k) X6 E/ k- Sapp = QApplication(sys.argv)
    / a- @0 _  W' F! y3 S( u% U
    8 v$ c, D7 u; c: {win = QMainWindow()+ e! z5 K2 w9 \% j5 A5 r4 D  d3 k( ?
    , r  U9 ^1 ^8 g! ~5 x4 u, Q
    win.setGeometry(400, 400, 400, 300)
    ; m# J; M3 g! d5 N* B) G9 j' V# L9 }5 a+ b/ K5 |  ~
    win.setWindowTitle("Pyqt5 Tutorial")/ U- m2 m6 g$ w
    ( P7 Q# d. y* c2 N, T  q
    \# Label Text
    7 B0 z2 F0 w3 T. K+ G3 I+ q+ T" k3 o: r0 ~+ @" `7 J
    label = QLabel(win)
    ) x( d0 y, {0 z5 o* C6 C8 C9 t) u8 l4 p& y
    label.resize(200, 100)
    6 `3 ^% J3 o( I) e: A3 \4 C* ~) ^' H# ]) y
    label.setText("Hi this is Pyqt5")
    * w. a% P8 e) I$ m( D1 A8 e, z% T, ]# l( O8 M
    label.move(100, 100)
    + d  T: j0 ^' s/ D' H9 E# Q. h8 U7 e! |& z
    win.show()
    / D! L  \& ]7 t/ n- G; v
      \4 n3 l1 \' b3 Z* Csys.exit(app.exec_())
    % |- Z* y9 h4 X# \: e: {) |8 u
    6 _. d' F) U" ~% [5 G& B9 M
    " o9 c0 V. @" ]/ [8 D& @
    6 h2 t+ k1 L  o按钮与事件:
    4 ]- c; K# X- O+ E5 W
    % `- I  `, Q2 U. O) Limport sys
    6 h; f7 C% f4 n( @% G# u* Z( H1 i3 e7 f7 J
    from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton; h# D# w0 j' ~
    3 P0 R/ \9 l, I1 E, v8 G: B% K
    def click():* m7 E9 x+ F  l* T$ w# p/ N) e
    * ]  {4 c" r& x8 s
        print("Hy Button is clicked!")
    3 Z3 P( d+ v; x
    5 q. ]- u( A- _8 t+ m' v$ Gapp = QApplication(sys.argv)5 [7 x4 Z2 k& A

    * ]2 \- r/ k( g7 H6 u8 D; awin = QMainWindow()
    * y& f4 S8 |6 H% @- W4 A+ g2 u# A$ R$ [7 t/ ?' t- i
    win.setGeometry(400, 400, 400, 300)
    . E5 Q( o$ ]' N2 G$ _6 y8 m+ F! |, v: S& k) b# y& K
    win.setWindowTitle("Pyqt5 Tutorial")& @3 s- t, w0 _5 D7 I4 |

    0 @5 y3 `  N2 w+ ^# K- n\# Button% w# Q! x/ ^+ p8 q
    ( M' j- b, h  y1 L$ x: i# I2 i
    button = QPushButton(win)
    - a! x; A0 `" @" M' K
    ' r' C+ P3 M1 c' X3 ]  Gbutton.resize(200, 100)
    " I* o2 M2 I1 U4 i4 \" t6 d
    ( U+ @* f5 B* C7 N& G# {. G' [button.setText("Hi! Click Me")
    , A9 s' j" X5 V, i8 v
    / k7 J! G* O/ q3 ?& K/ obutton.move(100, 100)
    ' }2 l% w! j5 Q2 t4 ]! d, Z! P  _  Z3 L- W
    button.clicked.connect(click)3 O4 i% r6 j3 y( W4 w3 M# J
    % ^( y( T. @4 _$ n3 |+ }' G
    win.show()
    . a1 U+ b+ c5 p% S8 v3 B  e5 t0 ^* f, H0 L4 f0 k' P- X
    sys.exit(app.exec_())" t" K2 U7 i* {4 o9 I! H7 G- x' F8 a

    ) A. |7 [( H, S1 p: B
    3 ^+ z3 |- b4 {8 g# o5 S' W/ y6 N' T- Z1 @. H
    button.clicked.connect() 在按钮点击后执行特定的事件。+ O& O& P; I1 x- y
    " q' ]# y3 C- T* D' u5 x3 d( G1 z( c
    PyQt5实战9 h: x' i1 c: @

    $ n; M4 S' @$ s* V. }) M- w0 U) S" t" f实战项目:简易的天气查询软件! \) e/ ~# y' [3 D( ~* ]# l- N

    . ]' |3 C# c& u4 O# `; ]6 v1、使用Qt Designer设计一个界面
    " J! W" O+ T  r
    6 r+ e& R$ b; E3 b: Q- \2 q
    % f3 @: W0 k- m& ?; Y$ w4 t2 E! r) r2 ?9 G
    用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:) t$ `6 n# R' Y/ e% A* Y

    ( o* V: X- ~% h3 D7 @" ~在Qt Designer右下角选择 信号/槽编辑器,点击+号新增5 C/ t: S; P, s( i. J+ M

    2 t; E, I; \0 Y4 M# r分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    , }* |: f# r3 y  E% p/ [
    * [3 V7 x7 W3 N: c6 S& x. j+ Q以上完成后保存为Weather.ui文件。
    " ]! R. }9 `# N9 [9 J* o2 w8 j3 O  d& U- ?* }
    2、转换.ui文件为.py文件4 H) w3 L" E: w1 u

    # s( B  h$ ]3 G" e3 c) L$ C% LPyQt5支持直接使用.ui文件:! r! g6 w' f6 n6 B- ?2 J" w+ M

    , G( Y! j  I$ F9 Y, K0 ]; Y( V' himport sys* g. j% v! `" D% X5 B) y7 v. W7 S
    3 r( R6 Q% V4 I* m
    from PyQt5 import QtWidgets, uic
    " }; ?4 Z2 u, b
    3 H( J6 Q  T# [+ m5 v. h4 Wapp = QtWidgets.QApplication(sys.argv)6 p! c! C; c% q, E+ h- g5 h
    ' u7 [# w, o) J
    window = uic.loadUi("mainwindow.ui")
    0 a, K0 z% A' h: h$ r1 V0 j
    . Y$ [5 t$ s9 }2 |3 [; Lwindow.show()
    ) D3 W% `! [& S
    9 Y3 b  H4 s8 H) W) H5 H" qapp.exec()
    $ _$ K( Q# ~, o, w8 f7 q9 Y# ~# @  E但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:
    * j* }0 M/ C) u; i: A* D
    * {$ l: X% Z( x  ?D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py! P- ^! n, c; `) i+ A4 K; w. t8 f0 ^
    其中,我们需要把两个按钮绑定的槽函数:
    , d8 S/ A$ X9 o" p# W) ^5 |3 T6 q. ?3 {# [
    \# self.queryBtn.clicked.connect(Dialog.accept)
    * B" _$ x5 K# G+ |9 W3 T5 T/ F" B" |& R. x4 A
    \# self.clearBtn.clicked.connect(Dialog.accept)
    " K, z5 U; F% e8 e& V9 B
    # @8 x: _; J# X\# 修改为:
    ; K9 ?$ \2 Z- }$ i. N7 e; x
    ; V; |7 n! N* Q% U' fself.queryBtn.clicked.connect(Dialog.queryWeather)
    & y8 x+ ~% g) l# [2 Q6 f0 @* @0 e! i- R$ E& {9 l! I8 q
    self.clearBtn.clicked.connect(Dialog.clearText)) m! d  D: ~$ v! B9 \
    最终的Weather.py内容如下:
    7 ~# w0 d3 `& @) u& U* U% h! C. b5 t. v6 x5 S& Z9 z) _
    \# -*- coding: utf-8 -*-
    6 p( _" R: R' U; [9 [& V! t# N/ ]$ Z
    \# Form implementation generated from reading ui file 'Weather.ui', g) K' }, Q1 [) Z
    7 o4 f" q. S* d' J0 R: r: k  i7 z
    \#
    ) F, G0 X5 V% v& r9 u- {( R2 f8 u1 K5 \( E
    \# Created by: PyQt5 UI code generator 5.15.4. j) e; U2 t! R1 g
    0 P' K0 C& Q# ~2 G. |
    \#, ?7 O/ E( i0 E, `

    1 i. r" I# U  t2 S4 Z; G0 B3 k* Q' B\# WARNING: Any manual changes made to this file will be lost when pyuic5 is6 z% W( Z7 S5 R$ e/ j- O

    ; {/ j1 R8 s6 S" a\# run again.  Do not edit this file unless you know what you are doing.
    1 _5 y' h, D0 T8 T  A! ~- L/ Z( p* k* g
    from PyQt5 import QtCore, QtGui, QtWidgets6 Q+ Y, \/ k3 i! O6 ]" j1 y
    - w2 }$ w7 t2 }( M/ j
    class Ui_Dialog(object):
    2 C; i; g6 V) c( W+ k. L  \5 S
    ' ?0 Q" z/ y  U6 [8 Y    def setupUi(self, Dialog):
    2 ?) h" D% W; I2 V
    7 `5 ^5 `1 d8 E        Dialog.setObjectName("Dialog")/ h: T1 Q' E2 b: i
    # _! U  G" p. P3 e: F4 v  v& i
            Dialog.resize(600, 600)
    4 i2 m6 ^; [. V8 y0 X9 u, {! _0 ^3 N1 }8 \
            self.groupBox = QtWidgets.QGroupBox(Dialog)+ Z( X# Y/ ~: e
    $ d. e( v- K3 P( j; ]
            self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))3 f' ^; }9 Q  ~$ Z
    . s; b* g9 e; q! O# i
            self.groupBox.setObjectName("groupBox")
    , o6 @% c1 F7 V) c' `4 N
      @& l0 o2 |4 |        self.label_2 = QtWidgets.QLabel(self.groupBox)) D3 ?" I* C* u. j: e6 S

      F3 H+ `, H1 g. M& u- D        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16)): W  Q; A  z! A, _
    . Q% b) D5 ?3 r/ V" t9 [6 j; F$ E0 K
            self.label_2.setObjectName("label_2")
    * ^) p8 H4 N7 i1 k* _$ \/ J
    , x  Y" ]: X( a( M  R( q3 o$ A1 M        self.comboBox = QtWidgets.QComboBox(self.groupBox)
    ' I+ j) h2 o( O8 y* K, G4 V, j. q: q+ I0 i6 l7 Y
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))
    6 |  r* y/ t- Y  w) M' g% T& k' M+ C! @6 K. [( E
            self.comboBox.setObjectName("comboBox")7 `2 p3 G/ |7 v6 q
    % |) n: D/ z0 t# n  G5 o
            self.comboBox.addItem("")5 @) D* N, Q- A3 j: |" Z$ A
    : M9 M6 x4 A3 T
            self.comboBox.addItem("")
    ! f, [% o. S( g$ f/ X8 {& V
    % T" j2 `; t# R: b8 F        self.comboBox.addItem(""), {  ]5 |/ [+ l- x* A9 G( i
    9 z0 o3 R  r& R' m) Y
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)
    ; }4 a! Q0 n3 L$ L& m% Z& a
    7 b7 f' W2 V. ^' G) i, r; G        self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))  w4 U: W2 O2 P& Q2 Q0 u
    + v5 f( f4 _3 j3 K  J8 G
            self.textEdit.setObjectName("textEdit")
    . N! _& H$ S" n( e! V0 ]/ O% p' S6 k, @  M
            self.queryBtn = QtWidgets.QPushButton(Dialog)( V4 m- W/ m+ Z, `5 C$ d* `) a7 z& E

    * @6 @" @5 l3 T9 y* q        self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))+ L' H8 ^5 g2 t
    ) ]  F) w% K% k2 _% _
            self.queryBtn.setObjectName("queryBtn")
    + Y. W% O9 [7 L7 K8 ~
    2 @. Z2 a4 C+ M( F; E6 d$ {        self.clearBtn = QtWidgets.QPushButton(Dialog)
    . B6 l% h5 _/ r- L8 T# A, z
    , {% v6 h# C. s/ S- L3 O; ~4 S' r# \2 i; T        self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    7 A( d8 ^" p) h* G! K
    $ O- O6 n3 _1 ^$ g% O: {( u        self.clearBtn.setObjectName("clearBtn")
    * y- Z) f2 s$ b& h
    ) S! I5 ^% y' n& F        self.retranslateUi(Dialog). ~; V/ u: p) N

    ) I0 M6 t5 g  z/ h' c) V  v        self.clearBtn.clicked.connect(Dialog.clearText)" L1 u) v# g+ x/ b9 Z
    % b% [+ T8 v1 Z
            self.queryBtn.clicked.connect(Dialog.queryWeather)" A7 `: K: n8 E
    0 H# @/ T) ~- y. ^; b
            QtCore.QMetaObject.connectSlotsByName(Dialog)
    7 F" |+ P, L( s3 h+ _% z* M- A" {$ ]; y
        def retranslateUi(self, Dialog):
    2 F0 m5 |) {2 J% [* J4 T
    ( {: q4 k8 f0 V( q, p6 W0 a0 T) g        _translate = QtCore.QCoreApplication.translate8 c' N& P! ]# O# L

    ; N$ d; d* M5 W  `2 S        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
    + _4 c/ G' @2 j3 a+ Z/ _# z( N: E2 O" B
            self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))
    ; h- x- Z5 J1 E4 H  b. z+ \6 z  c9 C
    % b" x+ h- q4 v1 s        self.label_2.setText(_translate("Dialog", "城市"))
    3 a9 j& ^/ f' `# ?$ Y( g1 ], Z: c4 l9 R
    - f( O3 {' @: @        self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    8 K* o0 W  U/ o
    ' u. V) w$ |+ U, y        self.comboBox.setItemText(1, _translate("Dialog", "苏州"))
    7 N( z$ y4 L9 E5 P% `8 H9 T) H$ A1 @( D( u( c5 |6 ~
            self.comboBox.setItemText(2, _translate("Dialog", "上海"))
    0 u# l* J/ P  d3 Q' P& a7 \) I9 U. D
            self.queryBtn.setText(_translate("Dialog", "查询"))- z3 O) W4 Q8 c5 t% H  d& e4 m
    * ]3 Q# `% }, L3 L0 D
            self.clearBtn.setText(_translate("Dialog", "清空"))
    , J* Q3 I; l# v3 \6 s7 J4 e8 W# v6 r% D9 U" ?/ w. m" A
    3、调用MainDialog
    . K0 a7 W9 b* a* Q/ R6 d! h6 p3 r' V
    ! v- [# h! A+ l( G/ ~) J在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
    * k5 M3 |5 `$ B2 j1 _/ ~/ Q1 }4 p4 H. o7 r$ d
    完整代码如下:) h; g1 a4 l9 z% f6 t

    2 I1 p# d+ @2 o, e; B' O! Jimport sys! [" q- R! H! d+ F  k2 u+ w6 W

    7 a, I/ m: R9 Jimport Weather! E1 K/ {! @2 Z2 H5 l3 b. }
    8 z9 a$ Z$ d  Y8 ]$ }4 F
    from PyQt5.QtWidgets import QApplication, QDialog  {, ^+ g$ `/ F5 j  b% [' n
    1 u/ L6 L- D1 ^: U% b% i( `
    import requests
    " [2 E. B; C0 H+ N; _" j. r
    6 F4 F% v/ @  Q# f/ J/ A3 Xclass MainDialog(QDialog):4 E5 X% {1 y# @/ r  i7 K* o
    * f  W% p6 n1 S" K$ R& \. v( u
        def __init__(self, parent=None):
    . Z4 Z* j: _. j+ i
    1 {* O% D. Z( O# F0 M3 V        super(QDialog, self).__init__(parent)
    9 L% `! Z& w/ Q: G3 S
    $ Z) p3 ]% y+ w& g        self.ui = Weather.Ui_Dialog()
    3 f( E/ f7 _; d
    / v1 [4 o" Y$ e# }+ z  J        self.ui.setupUi(self)
    6 ^' H# z% w) }
    - z, g3 x( d$ w, c    def queryWeather(self):
    4 x! \6 P. K1 S" X3 p- k( N0 O# Z( `, H8 T; s
            cityName = self.ui.comboBox.currentText()
    . [% Z4 N. O% m" P
    : G  Z5 p/ F. [+ }        cityCode = self.getCode(cityName)
    % K  E1 p/ A: Y5 \8 D3 D6 R% o
    ' i* A) K# A7 p8 ?2 c& m        r = requests.get(2 I( v# \9 m- b$ S5 c8 L. _: I
    $ ^* o* m' h" ]
                "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(- F* f* @; M; i) h, n7 S# H
    ( ~, m0 t! B6 G- G0 {5 ~
                    cityCode))3 F! i- }# g0 F' t( Q
    8 Z' _+ p6 W2 S& R3 G% }
            if r.status_code == 200:6 `+ ]3 L# A+ J9 x- ?' }
    $ |! L/ i7 L+ [6 W8 L4 s4 v
                data = r.json()['lives'][0]
    % z7 Z6 d1 Y! w  B7 n0 G2 S" a1 q( f0 Y* A( O
                weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(2 i. h( e6 k; ~) H1 W- Z) _
    2 Y. H7 H# {2 h- k/ r, r
                    data['city'],
    - t, q4 @1 h9 u: _: [: K% y3 x. a' X2 M9 d: a% `: x+ \
                    data['weather'],
      @* n/ n& G4 f1 @) m  g+ W2 U6 ?" H, M" D# B4 i. T. a! @
                    data['temperature'],3 O* Z5 C! B: W! [- y" I6 j6 Z

    5 h$ p/ x; m& g                data['winddirection'],
    1 w4 ?( w- `. Q+ e' h
    ; e0 l$ @8 E+ C) F                data['windpower'],
    " C' X% p* g. o: b; I
    6 Q1 I3 y2 ^2 s& [2 t8 k                data['humidity'],
    0 ^# V5 b# _5 H! W& _7 L) R3 f9 W' n2 ^
                    data['reporttime'],1 I( U5 w' `) J3 T- r
    . M$ O0 L. E2 l; d8 r
                )1 m) _3 X, }* p
    ; K/ J5 }! ^; r
            else:" W6 v  s* }7 l

    # A1 h" |7 Z8 P- G9 T* C3 W            weatherMsg = '天气查询失败,请稍后再试!'+ N( L1 a% t: w4 _
    & v/ d( p4 o$ Q& P4 y- i8 K
            self.ui.textEdit.setText(weatherMsg)+ f8 ^: v- [3 v5 `* t$ B' g

    + `$ a& v  A# W! B  \    def getCode(self, cityName):
    2 a$ ]- i  H' J9 S. z5 ?8 D1 A9 @
    6 a, U8 F# V6 q8 V! g' c        cityDict = {"北京": "110000",
    $ l- q7 F9 y% M5 W. |1 M3 E" I% H3 S; |9 R. r
                        "苏州": "320500",
    # j( {' W' H& V" c* o1 L: }
    ! o6 x& h' Z6 t; E" V                    "上海": "310000"}) A; r3 W- k( m

    6 J) C* z  J( _9 U1 a) g. C2 k( y        **return** cityDict.get(cityName, '101010100')0 I  R* V7 Z2 D
    4 \5 j9 S* t: l/ J) N' u
        def clearText(self):  g0 ?) M8 X7 m8 N# Q3 _" o1 Z4 t

      B0 ~" I* d# a8 Y        self.ui.textEdit.clear()
      I: _8 j" U3 o
    . h# d6 U4 Z: Z  b" p% jif __name__ == '__main__':. p  [. s) ~- t" _7 _& w

    6 C) w# T0 _, q    myapp = QApplication(sys.argv). X' P' z; B& D, L

    " I$ G5 L  ^! `! @" V- |; e    myDlg = MainDialog()
    ! Y( n: Q: Y2 I3 t1 @% \( `  t
    ! a6 O0 ?& B3 l* K& w7 q2 P' E# X    myDlg.show()
    9 E5 _" O! d! n* ?4 p& q" n
    - n2 N9 B# [" U) G5 j    sys.exit(myapp.exec_())
    - I" i6 g5 Z8 m" H( y2 V1 W4 a  s
    2 R& T9 ~7 E0 |" g% i运行demo.py并执行查询后的效果:9 ~. ~% Q* P) w8 }9 T
    6 B1 t: {1 J3 q4 O" `7 ~
    ; H9 p! N' Y2 Z1 N0 E

    : l. K& E/ g5 C. w4、将代码打包成exe文件
    . i) x8 H0 X/ [5 V. j, a  g$ q
      e9 D' H  a: \; \将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:- h6 v, ]* A+ N

    5 o' l* H1 @# I* h5 X  A
      E  Q4 d2 \7 h2 O! E0 D; p7 g1 ?: b3 A; S& ~: k/ p! t
    py2exe:软件更新已经不活跃,因此也就略过。
    ( K1 S! r- r: z8 B+ G! U3 Z
    " Z, n# _* U8 Ipyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。" i/ H+ q1 V' f/ r# V; W! a
    + V& n- j! j+ k4 i, T2 o+ b5 s
    fbs:基于PyInstaller,使用起来更加方便
    " u1 `9 n. }6 k; `3 _$ j$ j1 y8 |3 ?$ D4 U( Y
    这里选择了fbs来打包。fbs的安装方法:
    - Q8 j- d3 `6 A
    9 ]4 A0 a8 t) h5 |+ E+ F, p/ ^pip install fbs
    1 ?2 ?$ _2 u. U. c使用方法,在命令行中输入:, ^- N8 [/ W2 v8 ?" J' \7 f

    7 x; c1 |8 h: ]8 K# s/ Sfbs startproject
    " e' |# _$ W0 H. D4 P1 V执行完成后需要输入一些APP的名称等。完成后会生成如下目录:. E! P# M' R) b9 L
    1 r/ _0 l& R5 R: h
    + C+ I' S0 w9 G: {) g6 O

    1 F0 z- _" A5 o8 s4 x0 q7 ]6 w将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:# c4 l3 k( f7 Y# X- O9 h+ f
    : v+ k) [4 f; P- `1 z
    from fbs_runtime.application_context.PyQt5 import ApplicationContext# p  M  K7 S- j0 z7 d- V6 L
    ```
    5 B! V; A  R) Y完成后执行:& {$ U% a. N; n/ q* b! [" u$ K( O
    ```
    ) O, P* }9 l6 O3 b6 t* wfbs freeze
    # `7 ~$ ~! I9 N' b( Y```
    : ?3 F" w& f/ X6 f2 B2 \即可实现打包。生成的exe可执行文件在\target\MyApp文件下。! ?' E8 `" \/ f% C' c6 P
    , v1 c6 R7 t. |" s  B
    ————————————————
    0 [" e0 f4 ], F3 s. e4 q版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    + p/ B, c, P% X( Z$ @- K1 X2 r原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667
    $ C: y  @3 {+ D; r" Z
    + O1 m+ g8 q7 ]% c0 K9 h' M. k
    6 ^& `( u  f: z) `+ W1 r: b. G8 _, {9 V1 W& \" q* k0 \! p
    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-4-14 22:03 , Processed in 0.413454 second(s), 51 queries .

    回顶部