QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2234|回复: 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 D/ J* H5 D  ]/ n' \) L6 d

    + i! o2 x: o/ A  o使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。+ q0 c( D+ x1 N% p. i: _* P
    1 ?" |9 o9 I9 @9 A9 @, \; ]6 ]
    常见GUI框架
    0 V/ E% M0 c2 j- @0 \0 Y
    ; O: T: I; z; K! _PyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。
      A( E$ v0 ?- {& O9 ]* C1 B- U! R6 q: V
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。' k/ M# ^. Z) N) J" a% b

    8 ^& a9 U3 a, b' tTkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。
    5 G2 }& n# C: ^& ^$ _6 |( X1 a+ A6 \1 f. W1 ]9 T0 e
    PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。0 e( Q# b3 h  c

    * F' A' m* K  ?9 }$ s; `1 x* e* yWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。. s) m; H: L* o+ `1 a, A
    9 T4 _+ O4 A4 t/ ~$ p
    Wax:基于wxPython ,为克服wxPython的问题而制作的一个包。/ u+ n, v" ?' R' k. _8 R
    1 [6 B( R- ^6 O* i+ @+ o
    Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。' W2 T# Z3 g* [0 d# n
    5 b6 J- m3 c4 w3 G- i4 ?2 h
    BeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    # |: {! r7 b- s% W$ x& S  x4 y1 y2 ?4 D) ^/ [
    Toga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。
    : t! \- _# W9 [- f4 Z  x, B
    4 G9 A' o) G( ]9 w0 }  x" v8 W; IEel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。- V5 I: L1 s/ {: ^+ U% c
    6 L2 T5 g- N& \
    Flexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。
    5 e  ]7 o6 X/ O. Z
    / S# n4 b8 b! Wpywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。
    8 j7 I* g; {& {+ G6 Q' z1 F) e1 I: F& w' t
    enaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。
    2 }& q2 }% m2 R) H0 I& v2 V& G
    # P! W* H( U  q个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。& s8 \8 N. w) v: ~

    0 x( k! z1 o2 ~" i: ?* @* VPyQt5简介
    9 m0 r* Q  R/ m# P& ]9 I- @) J  V, X6 X8 S0 a
    PyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。9 ]& s2 K, f3 |9 I, x

    9 k; Z) m  m) b& j/ p3 \7 wPyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。
    $ f/ J7 ?) _8 y: N" v( C7 }6 k/ }, u: Z0 m& I& S8 ^
    PyQt5特性如下:
    & C- z' a5 [) O& \+ U1 R+ V6 @6 W- B, p
    基于高性能的Qt的GUI控件集。' k$ \1 O! f6 U& F+ ?

    " }2 I( Z( E* l+ [/ U能够跨平台运行在Linux、Window和Mac OS系统上。! K4 F9 v4 e& a  ~5 M# {

    ) x9 `5 R8 x5 J) \使用信号槽机制进行通信。, W/ H$ @9 C- `5 F3 Q! A1 |2 n

    # A! w' T" v6 x* h6 G对Qt库进行完全封装。4 `" ?6 Q; {6 F1 F( G1 Z' e& T, {0 D7 G2 N
    % P: ^! w0 J4 K4 _5 z
    可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。/ X$ N! e1 A  A4 C- M

    . w6 a. {, l, L% c4 Q提供一整套种类齐全的窗口控件。
    7 c4 u, m1 h* j3 L; l
    " r% D' E( R4 f7 N" u+ kPyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:; L5 {# L# Q9 h+ a& e! l$ i$ H! G1 D
      A9 I/ k( o) \2 l6 u: Z
    QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。
      L$ N. N3 D  \* x2 X* r) n  s* A
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。
    ; ~% o1 D* \% l7 d2 H6 u* ?( F6 r& W1 L$ u4 y. w% `
    QtWidgets:包含了一系列创建桌面应用的 UI 元素。
    4 u( |$ k4 C$ r& C- g' y+ q1 e% `0 c* V3 |8 Q0 Z! y
    QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    $ g5 U, W* k9 m5 K
    & L$ {+ s. @4 q9 M+ }0 p& Z4 AQtBluetooth:包含了查找和连接蓝牙的类。8 `$ q6 b* e& x) |5 h
    $ e2 b% T( R$ Q$ X; D, {2 E
    QtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。
    # Z3 s4 H; P' v# p" M. |& `1 E
    ) _' I- Q* @1 I- ~9 O* PQtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。
      u  ~! J# _0 Q, t2 o5 }0 m9 j0 q
    Enginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    & ]% C; q! c# R
    " g* D2 f; J6 V. uQtWebSockets:包含了 WebSocket 协议的类。
    ! D$ W" C6 U. I9 Z8 i+ G: V
    0 j: n/ z4 Q2 W1 t$ k) YQtWebKit:包含了一个基 WebKit2 的 web 浏览器。  h4 m- e1 D/ m

    4 E8 B3 p  ?8 Q  QQtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。
    / ?; q+ E- Q* Z7 }9 @" d* R  g  s* P& ~, [
    QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。1 t! h5 @( X& u, ]4 c" E
    . V5 t6 f8 W# P# H7 k8 b- y. O1 a
    QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。8 a- x5 l, r- _2 u
    ) L- f9 b8 v3 }. @% A
    QtSql:提供了处理数据库的工具。
    3 Z9 _7 j4 \3 p( H$ s. P$ l% c) _: N6 ^
    QtTest:提供了测试 PyQt5 应用的工具。' q; S/ S3 ~+ J9 O& s2 r

    ! }: A) D1 M+ p: BPyQt5的安装
    % k, P5 Y9 X  K, C7 l$ w; F# u, B8 [) p. j
    由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5 9 n+ L8 f4 ?: J) ^/ ?$ Q$ _
    : c0 m+ P7 `: g6 O
    安装PyQt5
    4 c! S: j% x0 \. S: {
    ) L9 V: t2 A6 b1 B7 `pip install pyqt5# r+ W- y5 v6 z2 ~5 f
    3 Z$ Q; _$ V8 m1 l3 D. }
    pip install pyqt5-tools, f( a" [0 s" U; h
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    1 Z  V! Z# c2 y& q) S7 a
    7 A8 [( Z3 ]0 a0 O8 Oqt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
    ( Q% s$ b) e: M+ d  C3 n# j% `解决方案:: l( I% ?. q( i7 [3 Y

      Y, J0 c. V! g& p6 b8 opip install click~=7.01 R' R) B/ M; \2 F8 B
    Qt Designer的配置
    , }2 i) y2 I9 H: o3 \0 ?/ \+ a* S0 [+ Y3 V# h1 C
    Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。
    + B* o9 \, T; L, M$ e: g: @
    ' |& v+ ?1 M0 u+ e6 g/ s  I0 a) t$ I/ L
    # V; h  r- l- K# v
    5 o+ P' i; x# g- v6 @" V, K整个画面的构成:7 ~* c0 }$ V8 ^# C. O

    3 y* ]$ w, r7 J左侧的“Widget Box”就是各种可以自由拖动的组件
    . j4 x! o6 w; J# \5 j5 I
    9 Y& A+ t8 ~, d+ ]9 N0 Y1 D3 `( `中间的“MainWindow – untitled”窗体就是画布: j2 E# `- o) V$ [" ~
    ! e& m! g  O2 Y! P, p/ l: N* _- ]
    右上方的”Object Inspector”可以查看当前ui的结构+ q6 |- q8 a  }: U& k

    + p' `' @1 U6 O右侧中部的”Property Editor”可以设置当前选中组件的属性* ]  f/ o6 u2 v! r. O1 {3 m. v

    ! L1 w5 u: \% @: _3 p右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等
    2 ]  L* W8 G3 {& V
    : n& ^" z# U. X7 s最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。
    & x9 L! Y, b9 m
    ( A1 T/ |" L- I& V* G/ _% ~QtDisigner配置: {6 n" _( G) q, i
    4 h$ y# N! Z9 d' O% M8 i/ ], @
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:* q* A: `. c, ~/ W5 m

    . r' |  A+ g; c) ~Name: QtDisigner/ r) H) v( a3 b/ L( K
    2 n' r6 U" f; L0 `' L: b, k: h
    Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改1 |: ^9 A, d' Y& F4 p
    " A$ k: n0 S0 d* g4 F
    Working directory: $FileDir$& h' }8 y( b4 J% Z5 U
    PyUIC配置( i/ J& S1 _( r- N4 R. P
    4 t& ^; q3 K" u. K+ o, x
    PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。
    2 G* f# P/ V+ H9 L( K# T. S
    9 K* E8 b7 C( Z1 ]在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    ! @* d$ }! e, K5 V7 r7 Z2 W) v% A1 g3 Q( Y6 @
    Name: PyUIC( @) V' T* Q: d; W- k% [1 U

    3 r6 `- K0 z0 ~Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改2 `  r/ y2 N0 o
    , x- o! P7 r9 F7 c
    Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py, s' V4 f+ M# n* w" v

    $ ~/ }8 S7 y- J" w( y1 QWorking directory: $FileDir$
    % s4 V2 l' c/ c4 `8 \: oPyRCC配置
    ( _8 ~4 k) @7 [4 l$ |8 m$ a% ^) d6 U. G: ]. W
    PyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:/ i' B$ E  \' E8 s4 D
      }# ]& \( R) Z% [7 ^0 M" Q' C& k$ S" D
    Name: PyRCC
    % I% m# A* H( R; V/ v: B. h2 T2 r3 S7 t* A) Q
    Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改2 }. i: m$ r+ W9 p
    , J% h8 h6 b) h# F1 ]
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py
    $ |; r8 ~* k5 B; w! m3 P# ~& D0 f1 [- n% ?  N; D2 Q2 g( x' x
    Working directory: $FileDir$. L! P: ~! H5 a" D7 J! o% g! l7 o
    PyQt5使用示例5 `6 g1 r$ L% q/ x
    # N; C: @- h6 R$ s! V* k
    创建一个空白的界面:3 I0 l" S& c  o0 L4 ]7 Y7 E
    + H9 I  }$ H5 H" d
    import sys9 _& O' I; ~( ?: ?8 b

    3 b. V4 C6 `! ]8 rfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    8 q# W6 P+ k9 a- u, _$ @+ ^$ m% B) z; l5 Y* ^
    app = QApplication(sys.argv); _! \% K& y5 _" V0 a
    : M' k6 H% h! I  W0 ~
    win = QMainWindow()
    8 {3 W& F9 K8 d# ]. Z# t% k& H( [7 ^5 s/ H, T( _
    win.setGeometry(400, 400, 400, 300)
    ( s9 u( V9 |& @" X0 _, v+ V( d9 I) @; U5 H! U5 p" P
    win.setWindowTitle("Pyqt5 Tutorial")8 o- D' [6 T  J) \% Y1 u/ t
    5 }* n0 A. d) O& w. C: I- j
    win.show(), s2 ?. `: A5 }6 D4 d- q

    , B  O! [2 \0 k4 Y( |; P, X$ j. osys.exit(app.exec_()). \2 R- Q% K/ m# O  E

    $ @: I4 f" h8 S6 X6 O+ Q- X
    , o4 {; W1 M4 P5 M! |
    ! p, r( |- V+ {  {9 g$ \8 [其中:1 O/ o& C* M. a9 `5 s: h

    ' s, T3 l/ B2 Q8 f1 ZQapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。& u$ C9 `$ @: W5 g1 N. E
    9 V1 F( M3 z& J% E$ k- E2 D5 e
    QMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。
    : g9 S* V: s, s8 h. N  Y2 O, L
    ! m% n' J, @; `: b8 ?SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。/ B! t- i! _  b0 v4 C

    5 w: ], v& z% {  ]1 `0 w  Mshow():用来显示窗口
    + H' e5 c+ a2 D, |9 n4 @. V4 P
    - j6 n, t& S2 [3 Aexit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭  u9 i# o0 X- ~, k$ Q

    ' o$ h. [6 _+ ~, ^3 _% F4 [PyQt5支持的常见Widgets有:. s3 _; \, R7 \& R
    . q: T- a) U1 Z) Y7 d/ m* n
    # Q/ |1 I% n# u) h: {; S3 F
      |) i7 ?0 [6 E! t8 u4 u
    从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar6 Q5 W+ {# Y7 J. E6 c1 Q8 U! `
      H6 v1 ?0 ?. N2 q" O0 H6 C
    对于使用Pyqt5设置文本内容,我们使用Qlabel:
    " R% D5 A7 F, I6 A8 m( K9 Y3 Z$ D" `5 T' s2 [. x$ N
    import sys1 W/ N& _0 b  A3 ^" w; c
    & A/ u+ l% W% n- n7 x
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel- D, _- Q3 u# u. I
    , I# i% B7 j% Z
    app = QApplication(sys.argv)
    2 A( [/ M7 _, X& |" f
    5 i; o; N6 D, d* Ywin = QMainWindow()
    1 y) s8 `, q1 v, ~8 R
    . U7 o1 O6 |% U! B) v7 \6 @4 x9 ^' b0 Bwin.setGeometry(400, 400, 400, 300)' l, F) [5 V  n) H
    & n2 A6 u. _3 R! d1 r
    win.setWindowTitle("Pyqt5 Tutorial"), I. {  s$ O( U8 c/ k

    1 N8 j- p$ ^9 r' k\# Label Text* q) o6 C' D4 ?

    6 [2 V; A, r8 h5 Y7 ?; ulabel = QLabel(win)+ v# i# _' U4 f/ K8 ~+ T0 [
    ' d& M; h+ k" O' T  D: R
    label.resize(200, 100)
    6 F) F1 c$ i# m- |5 B" I% }
    & \, G8 Y' _( c" n' Ylabel.setText("Hi this is Pyqt5")( W+ V; }; J/ m2 n

    % G8 L5 g9 ~4 Ylabel.move(100, 100)
    & w% G1 Y% `; p' c( F" M* I( g% T
    8 \# {5 I- [7 w* m3 c/ Z, C) Owin.show()
    - W3 B. a. K; ]7 W
    # d; t" }& C: ^& P5 n% p0 @sys.exit(app.exec_()). m: x+ m) r3 M! q5 u+ J

    # n8 k" v1 C; I0 S/ L% ]( f
    1 P- t2 n  R1 p. }  A+ W9 @7 A
    1 G1 o6 h& d( q; A' H, `按钮与事件:9 U+ @. U0 p( E' O" ?+ j5 v/ y3 R

    ! p6 c- K9 o) U2 t: Fimport sys
    2 h0 Y2 M/ O# f  @' \4 N
    / @3 n2 f6 _% z% ~0 j5 {- rfrom PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton5 Q2 G# s, @' \9 y  q& I
    ! I; n6 D4 ?8 n4 y( J6 q8 N; d3 n
    def click():1 D6 l0 ~( J- ]5 h. P  ~
    0 V  j+ W. g/ K: B" w8 M5 J/ C" e
        print("Hy Button is clicked!")  |' ~; M6 m/ W: p9 U9 K9 P

    + s4 L9 g6 R9 o1 c. Xapp = QApplication(sys.argv)! M+ g9 @2 W3 B

    " A) D  S8 l, j9 }) z. ]* x- Iwin = QMainWindow()
    5 n0 P( u. p! h  A; u) l& `; j! I$ }; X* h+ d4 u
    win.setGeometry(400, 400, 400, 300)2 J6 m. J. {, X& P. t
    $ Y' y7 w% v0 X/ J! D
    win.setWindowTitle("Pyqt5 Tutorial")
    ) k5 E+ {# G. h% ]/ }
    - N/ j$ K& j& q5 s# M2 P" Y\# Button
    8 u' n! |, p9 A  n
    , c. O" b. S: P' r- Pbutton = QPushButton(win)/ K# l+ u. @" q7 @1 d7 l

    ) o- |# W7 ^* @button.resize(200, 100)- c! R# I5 Y* G  R. G0 {+ g

    ) |+ [6 C+ S1 @button.setText("Hi! Click Me")  ^0 _* @: q" r, n

    * o1 x) C' j) A6 D9 Sbutton.move(100, 100)
    ) t" y$ }' y+ r7 ]* E/ F& d4 O4 E+ Q- d- h
    button.clicked.connect(click)
    9 \. B5 \+ j) q3 h* _$ x# N. C* W' p2 m  u' |& I7 n
    win.show()
    . F3 j+ T* R  t5 m7 Y7 a: ^; {& V2 |7 ^# D- B2 }. V% e! M
    sys.exit(app.exec_())4 m$ ^% I( ^9 {. k
    2 w7 J( s, e7 |

    8 H" w  v  Q. x/ h4 |0 X: l% a' C+ M; ^, |% K
    button.clicked.connect() 在按钮点击后执行特定的事件。
    # {: k1 s; T; V& H2 [3 d1 K1 i; P  {+ A0 ?# O; ]
    PyQt5实战! f: N- F, Y6 J( z% M5 }6 b, f) r

    - b! I3 n; l! q( v6 l  K, Q- A) t9 @实战项目:简易的天气查询软件
    7 I, g; L% y& N  h# L. J4 z
    + L8 w  d! O" Y3 f/ f1、使用Qt Designer设计一个界面
    9 q* s" Y: y; A, b* x  V- G# r3 J" e9 T) J
    6 G) o+ c& y6 Z* x
    - I  ?. V; _- R2 e. z2 u* x
    用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:
    , D3 u- q# i' L4 L* ]6 s6 X9 p7 ~( t  S/ C5 G( V0 X. p, i
    在Qt Designer右下角选择 信号/槽编辑器,点击+号新增& u7 C' m5 m' y" F- s
    6 F# z" ^5 o$ e$ s6 ^/ a
    分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)6 W, a0 u. ]( K: C: t
    ! y# H3 _: @- ~/ S; C
    以上完成后保存为Weather.ui文件。1 N$ z8 m2 S, f2 a, S9 G6 m' [

    : d  ?, w8 o4 O% F5 C8 x2、转换.ui文件为.py文件
    6 q- A, o# l) b3 }6 a
    2 r! d9 @; B! |' q, R# OPyQt5支持直接使用.ui文件:
    ) n$ o* f' t, ^$ x7 L7 A7 I+ m& l6 F) F7 J: S: P1 Y4 Z
    import sys5 Q/ Z; E3 g4 z9 ]

    3 |3 r6 }6 [. B+ s( Pfrom PyQt5 import QtWidgets, uic
    / s' c# Y: U0 i
    % \# a' U; k/ Gapp = QtWidgets.QApplication(sys.argv)
    . i7 E! X) j3 g4 z
    : u- C- |' A, Ywindow = uic.loadUi("mainwindow.ui")7 o" O  w* d* y
    ! g; r9 }+ {( m& S9 I
    window.show()) v" `1 \! W) H" V2 P
    0 d* S: T5 n# g" Y* t  D
    app.exec()
    ) J5 g$ `8 s3 I* i但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:+ s6 L; Q5 [" P; D2 d5 W
    1 j/ K& j+ B; o( E% r
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py0 I7 O. ^' P+ a3 C4 o* G
    其中,我们需要把两个按钮绑定的槽函数:, G& ^. N. a$ @
    % Y  H  t- t3 Y- G9 s5 H1 G
    \# self.queryBtn.clicked.connect(Dialog.accept). K3 z. y; Y7 j6 u0 u

    9 ^) x# _3 h' _$ `' `\# self.clearBtn.clicked.connect(Dialog.accept)0 u2 _- j. r* i
    + B" C- F4 E/ I+ V+ K8 t( x
    \# 修改为:# _3 X* e" t/ e

    7 ^4 y$ h$ m. hself.queryBtn.clicked.connect(Dialog.queryWeather)
    1 w+ S4 Z; K+ c% a5 a( i- C# W9 E- l7 \5 L- q
    self.clearBtn.clicked.connect(Dialog.clearText)/ _0 F- k  |7 K9 M1 A  a+ R! |0 a
    最终的Weather.py内容如下:
    7 _' E- E8 A) W" H3 J) g7 I# ]; B% |' O
    \# -*- coding: utf-8 -*-- a5 b" p: M  t  R
    / ~/ i# e# W: X) J
    \# Form implementation generated from reading ui file 'Weather.ui'
    % e; {' X( l2 P/ z# P
    : g8 T. _) m2 n7 G8 A' p\## J& V: e2 l" Y" a4 u) [
    * e# J% O' x8 s
    \# Created by: PyQt5 UI code generator 5.15.4
    , M% H7 g% U$ x& M. k. C/ s
    : ?+ q* P4 A% @& P8 K\#7 P  n  h9 q# d" l, q9 M9 u

    & \& L  Q6 D, C& a/ [$ `: W( ]\# WARNING: Any manual changes made to this file will be lost when pyuic5 is
    & j  Y7 h" @  n" C! z
    , Z; m: R/ c$ ^& L\# run again.  Do not edit this file unless you know what you are doing.1 L" U0 v# z0 q: W+ R( L/ C
    # [$ \" x% }8 y, m9 P# n
    from PyQt5 import QtCore, QtGui, QtWidgets8 w* t/ k- k( a5 f( |/ p
    " T5 X4 P0 @3 Y" G2 k0 C
    class Ui_Dialog(object):, B6 s" I  ~. O& C, U
    $ h. Y/ G" Y" U7 g3 d# ~3 |% F+ ]
        def setupUi(self, Dialog):* Q8 F' z+ T! q3 r. U  Y8 `
    5 z" g# T+ F) j( H
            Dialog.setObjectName("Dialog")2 G: j4 L4 s( l8 e8 `

    1 S; [; ?& \6 o; E7 \# A        Dialog.resize(600, 600)
    + W: Q# u& f  C& U" K4 e: S1 P$ `, s7 d" n3 P
            self.groupBox = QtWidgets.QGroupBox(Dialog)
    : j$ _9 S, O+ M
    " v& j5 l+ p$ s! P6 f. U        self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))
    ' i2 L. c# m/ a/ V  u8 q! f0 Q' \( P* p
            self.groupBox.setObjectName("groupBox")
    , u& s, V5 M0 h, s6 K+ f/ M4 U: c  n& K: A
            self.label_2 = QtWidgets.QLabel(self.groupBox)
    ! {" i; _: M6 u9 r0 e  x' j: O# k) Q
    9 J- V) U. h7 {) Q1 ]$ {8 @2 g: u        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))- t4 a1 k' U7 ~& ~- y
    $ p! @7 a# u2 t# n% w* b; v
            self.label_2.setObjectName("label_2")
    ; V( g' b# p4 M9 c3 H" m8 _6 o" \2 @$ E* ?2 k7 ~5 q
            self.comboBox = QtWidgets.QComboBox(self.groupBox)
    + m2 }/ R# ~7 h2 E6 m8 C' y  }/ m! v1 {" y7 K) O! a% L
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))! @+ S- T; a9 `/ _# p; m& o# j: W

    4 ^/ N& K6 t4 E: p% y$ h8 m; j( C        self.comboBox.setObjectName("comboBox")2 f1 x# g1 g7 m
    ; z  B* \1 H& r; u9 I
            self.comboBox.addItem("")
    2 K" r: \! s+ J6 i# x- I& `. I& |1 E
      I. z% ^: a1 U9 E: B7 m        self.comboBox.addItem("")! j/ n* @! e" M6 [; h! i9 C
    9 B8 a8 `' a/ b: j' o: u
            self.comboBox.addItem("")
    7 }4 I: \; I) y; Y" F+ h2 {8 M  J
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)
    . S  q' j% T$ a1 @$ G" }" k( _* T  v+ z0 b
            self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))
    6 {0 @4 x  b9 K
    9 w7 [, k2 V9 ^' b6 ~/ S! b9 M        self.textEdit.setObjectName("textEdit")8 V/ }4 E# S7 [6 w/ [' A0 s* k6 q

    / i7 D, w" X' x3 s. X9 H        self.queryBtn = QtWidgets.QPushButton(Dialog), R7 w1 U& E. N6 n% {
    6 z- h' d, W3 F+ J
            self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))7 t; ^3 m) E- c. `8 v1 m  M! a2 C

    + J6 y/ ~2 e- ]! p- b- }. l        self.queryBtn.setObjectName("queryBtn")9 o& l# ^) X! w6 M
    * }9 ~5 W5 Z/ y  g, s+ l. \. Z. k2 ]
            self.clearBtn = QtWidgets.QPushButton(Dialog)
    0 n+ w) @! ]7 x$ ^& _  T3 c* ]
            self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))$ [  m8 S' n: Y+ m/ N, h

    8 M3 h& V- _& K% k( t9 |        self.clearBtn.setObjectName("clearBtn")! N( W! {  j8 {! F2 W6 y2 `6 Y5 S

    0 `: T" q! ~& J7 @+ R! }% C6 G( d        self.retranslateUi(Dialog)# {! a, x0 r) I9 o2 L+ J% l
    8 K) Y% N: @- ^& l4 V% I/ P
            self.clearBtn.clicked.connect(Dialog.clearText)- W/ H, V! G: {, ^) \+ d! A. f

    ' P; e5 y6 J* m3 ?# {$ g4 x! S        self.queryBtn.clicked.connect(Dialog.queryWeather)
    9 t- k) q! ]8 a- Z5 n* g: _, c0 c1 ]/ ?
            QtCore.QMetaObject.connectSlotsByName(Dialog)# m  U! w( T6 a9 ]& c6 d
    7 v' }: C& `6 U- r$ t
        def retranslateUi(self, Dialog):' X# B7 z/ a* e9 }; H/ J0 N

    8 Y- f$ B$ i% k  f! \        _translate = QtCore.QCoreApplication.translate( o6 ~4 Y& V6 E; H4 [
    ) }" X: t4 \% A
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))# C: x7 a# y; D

    ! g) P$ p0 c9 M3 E! V& I, T" O        self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))( P% u6 Q2 z! V& [; B$ E; s$ T" p
    $ {3 t" h9 M, k2 K  _+ E8 Y$ a7 x
            self.label_2.setText(_translate("Dialog", "城市")). p! t* E! @$ l- M2 d$ K
    % P) B6 b' n+ R: l9 P$ c$ L
            self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    8 x  w- |+ c/ \! G, c+ B. b% Z* O7 D% S8 H
            self.comboBox.setItemText(1, _translate("Dialog", "苏州"))
    5 F, s8 I) i1 o) q
      K5 Q  Z* p6 o9 A1 E* ?( A" F        self.comboBox.setItemText(2, _translate("Dialog", "上海"))
    ( E4 T, m$ X4 w5 m! k; U& ?$ S8 X
            self.queryBtn.setText(_translate("Dialog", "查询")). W0 _0 j( ~! _

    2 p4 ~- i0 X0 Q        self.clearBtn.setText(_translate("Dialog", "清空"))
    $ G% F8 Q$ v  n  R6 W
    + d! }! P5 O) r2 ^* C* X1 P7 u$ |0 `  j3 ^3、调用MainDialog
    2 N' ?* L* e  L% R, g6 ]
    , I) Y: q1 V  _/ _' g0 X0 ], z在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
    : {4 X6 ?* ]" k" k# [+ q
    / z) L* T' B9 y' |: [2 R完整代码如下:& |7 J/ o% z8 A  j" t4 T& k7 H
    1 j7 X9 e. J, ?4 k8 K/ e+ f
    import sys
    ! J$ e; p& X& ?; j5 K' ^5 h7 o0 ^, A1 S4 M* G) b% T* P
    import Weather0 ]8 h5 M. ?) R; ]# W& l

    2 x3 }9 A+ k/ V0 ^7 Rfrom PyQt5.QtWidgets import QApplication, QDialog
    - X9 D( s6 u+ {+ h' L/ r' ]* q5 ^
    * m7 D( B$ b4 Wimport requests
    ( g8 ?. Q) u; T
    * |8 m- F) V: L$ C( C. bclass MainDialog(QDialog):
    # v% Z- ?& X% O! ]" g8 u6 b2 r: X& ]/ T8 j
        def __init__(self, parent=None):
      E+ D& A% K) l' k6 Y+ q4 X2 f$ P) }9 ?
            super(QDialog, self).__init__(parent)
    % O* w+ x  P: ~/ [2 ~! U$ P: w, j! Y
            self.ui = Weather.Ui_Dialog()
    ! J0 q3 Z8 y7 v. Y. b" M4 P, k7 P- `0 Q7 Y' T1 X
            self.ui.setupUi(self)! ^/ D+ ]! }6 M6 o- o* e( x

    , X* Q8 k5 V3 Z# I    def queryWeather(self):2 H0 i9 \/ h% I( J; U# E& z) @

    6 H! f4 ?/ ]% h6 b; u        cityName = self.ui.comboBox.currentText()0 k* h& e  F- d; I

    3 U7 ~% ^8 g$ e, B9 w        cityCode = self.getCode(cityName)) X$ Z+ X8 g# J" B" y9 v
    0 H$ g- r% b0 c0 X
            r = requests.get(
    : ^; f& F7 s4 }9 t3 N/ N, B% o/ A- e0 k
                "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format() P, F+ }) T- W9 z( N

    $ l) t6 n6 k+ D                cityCode)): I0 W3 ?  S2 {3 o7 U
    1 a" s* n& d3 z% w% K8 R; O! ^' N
            if r.status_code == 200:3 E# D$ @; M" f+ t7 l
    3 W% r4 u7 [6 L! r4 P
                data = r.json()['lives'][0]# D! l) w/ X$ G9 c) M

    1 C" e, q- y; J& A% }3 m# t            weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(/ ~5 v9 \' f5 F4 S/ k

    ( v2 E6 L- M# @7 r! H2 ]                data['city'],0 y8 R' Y7 U5 {( e) r9 }' K2 L: ^" ]
    9 l, N( K0 w. y
                    data['weather'],
    - k) s. ~6 D6 ?3 X$ B$ p# u, A# j
    1 G8 \, j8 ^: V9 F  }                data['temperature'],
    ; c+ y/ X+ k/ L* Y8 G4 v6 q  `) U0 p1 U0 h1 W
                    data['winddirection'],' y7 _( i3 g8 N" j. m
    2 L; k& e& e( ^5 _2 s( d, s' @
                    data['windpower'],) A! b- P! M' o, d' Q: r
    ) p3 G% u( t; v! q- O
                    data['humidity'],) n) {8 F  R4 Q7 X1 x6 |; @) L
    . n; p' l$ o2 ^3 i  r
                    data['reporttime'],
    9 k1 P3 Z. d4 b( J2 T
    ) p. ~6 Y: U- [1 h! g2 i" O3 O            )2 T9 d, J& }! B9 P# n0 h

    + l% v0 M& T$ A        else:
    ( L5 c' j. [; y1 X: J" O8 H# a" W) V; f4 q* s
                weatherMsg = '天气查询失败,请稍后再试!'/ x2 M" B9 t1 M) _' Z. {& s  a6 M4 O
    8 n3 d! G" O8 ~, x9 ?
            self.ui.textEdit.setText(weatherMsg)
    % k# e0 T) k$ Y
    4 p) i  l- G2 K+ T# V, T3 C    def getCode(self, cityName):
    & K7 ]: w& i9 I1 u$ u; j: u4 a9 j! x: o5 X0 W8 P
            cityDict = {"北京": "110000",! d# @# B, X( U3 r+ M
    ( d3 c3 v* c8 f" b8 |4 B! D
                        "苏州": "320500",# I$ f: n7 Z3 z# q: Y; y
    ) H( U/ p1 w6 E% i7 J- n, F
                        "上海": "310000"}; M4 L, e. m3 Y  V7 {: T1 w
    " B4 e4 Q: j( b/ k2 `
            **return** cityDict.get(cityName, '101010100')( r: K5 A" G! P" E: v
    : |6 u3 j" g* v+ C- x
        def clearText(self):
    8 C# X/ ]  h1 ~' A, o, i
    ; I* l! b, W& o2 l        self.ui.textEdit.clear()8 O8 q0 X" a- q; \) u1 U

    # R; g+ y  U- gif __name__ == '__main__':6 V% t0 B( \$ ~( T' @
    0 u+ q+ T& D! e/ t' A& Y% |1 ^
        myapp = QApplication(sys.argv)( g! D, x  L1 d1 I) H

    4 |8 g) R: j3 s9 e- o* c    myDlg = MainDialog()* ?8 l3 M/ Z: S' m

    1 _9 F5 l5 n# N. Q    myDlg.show()
    6 `$ b( @' [( R2 p
    & j% o, x1 j) Q) n: X" z    sys.exit(myapp.exec_())
    6 \* A; ?$ z4 G4 t( M7 g) y( R8 C1 U8 s; P1 ~
    运行demo.py并执行查询后的效果:
    - U" B# W% Q8 B4 ?7 }  u# P; y9 [% c4 t4 c) `

    ! W2 d( G' I( a/ d3 e
    7 N( ?0 \) x3 r) n3 [7 q4、将代码打包成exe文件
    # F8 b- t1 d' t: H' _" _
    ) {+ z  n# [' }7 J& i将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:) Q' O# W  x0 s. M
    - q: `1 e. v# Q/ j* ?
    2 n  B5 K8 G5 I( i- W3 a7 \
    3 m7 I0 t8 ^- ^6 O
    py2exe:软件更新已经不活跃,因此也就略过。
    7 }7 c4 h6 Y. ]# W% i3 ], G
    0 |6 X  a4 ?: t2 U1 ?4 ^pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
    5 b. J4 i  E4 [" [* P
    % j+ D* ^* P& d2 f! [9 Gfbs:基于PyInstaller,使用起来更加方便
    " N7 k! t" k8 U  _5 c, Z, ^
    1 g; P# `* h8 h6 j7 u- f/ @这里选择了fbs来打包。fbs的安装方法:
    , X. C+ I9 o! ~' c6 P; _5 i. ]/ F+ v
    pip install fbs
    " L" m+ ]# @8 ]3 U! B& }! U2 k; w使用方法,在命令行中输入:0 R; i# M; Q' D, I
    : s/ h* c7 s+ g6 q; G
    fbs startproject- R& r- Y( H) z2 A- ^' s
    执行完成后需要输入一些APP的名称等。完成后会生成如下目录:
    8 F" T. ~7 P; S: r$ r2 B4 x) Y) c, x' J. R
      r9 m' \5 k3 w3 `; M1 d9 q
    7 ?  H  a3 |5 P
    将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:0 w; {) V/ ?. y

    : k& [; |( {$ y5 n6 i9 Bfrom fbs_runtime.application_context.PyQt5 import ApplicationContext, v# }! {, T7 I, R" F
    ```
    ' T! F4 ~. H. l; m完成后执行:+ u) S+ o' L9 C- \' v# Y
    ```
    8 e4 ]( S' P# X" @- P. Nfbs freeze7 h- w5 k9 E" Y' Y. B1 U
    ```
    , k9 v0 S/ g3 U  L* g3 s2 a即可实现打包。生成的exe可执行文件在\target\MyApp文件下。' G5 r* \9 a; J/ k/ N  O$ x

    " k: l7 u+ D( @————————————————
    4 b6 A- P6 _9 ^! y& i7 x# p4 s版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。, ^6 Z" I4 e  Y: a8 V1 u4 S8 H
    原文链接:https://blog.csdn.net/qiqi1220/article/details/1262896674 h( W* s+ B, E5 U+ `8 o) Q

    , U! A* |) b1 q) `8 H7 u/ \& W# j. v& `
      ~* ]1 R# E( h) H% ?
    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 18:23 , Processed in 0.386836 second(s), 51 queries .

    回顶部