QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2253|回复: 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使用指南!
    / m1 @% w, N: w  Q! i5 b8 C3 p2 {- N& I& e9 @, n6 b1 H' D
    使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。/ m' L9 }" @2 q+ n( f
    0 c8 d- ^0 W6 |: v* S
    常见GUI框架
    # ~0 E0 T5 U& t$ ^# J0 Z$ D2 q
    " a- a2 E( X# c6 C! y5 SPyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。3 t/ E3 B' u2 H4 F- l$ a) x$ {
    + t5 R% c8 M9 a& f( q9 @
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。
    : s5 R; t8 }: }# C  ^* y6 s7 A* a0 S$ X* ]3 n4 E$ V
    Tkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。
    6 U' S  ]/ _. }- b& d
    2 I8 r: J1 F, c% C6 l: V5 L2 Q3 R2 t2 uPySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。  C  g$ l1 Z4 a. Z

    ' U# I) s2 F+ Y( J+ q, t* D( B) yWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。
    ! q/ ]( _' b1 y' d: T( n% k, L" }' A# P. _4 p* S
    Wax:基于wxPython ,为克服wxPython的问题而制作的一个包。
    7 X* Z0 z, n6 z. h0 n4 f7 b* }& R# F' T, b, s' Y1 y0 G
    Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。
    0 s/ Y, q* C  Z8 p* H  r0 D  f5 S* @4 f3 g- U
    BeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。) ]& W  \! A$ s. _- f9 x3 V

    - m1 S( y- I# V4 f$ gToga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。
    6 E$ S& z" z, w5 g
    ( _5 l0 @$ q+ c, @7 G. fEel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    & L3 v; d. ~- M8 c" [
    / [: q- a+ R. v! z* LFlexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。
    $ ^* Q0 _- V( C6 {' i3 l
    . p+ }  Z* a* v9 ^& R" [pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。2 O2 f- M2 F: S" d

    " z& J7 f( p  J! _+ l7 Venaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。. i2 P1 b7 n1 ~( F& x- F; |1 J

    , T" Q# I! K& M1 B" j/ ?* M个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。/ r5 ]! ?. B" K7 L3 Y8 E0 j
    $ Q+ H3 Z# `2 }
    PyQt5简介3 ^. M' r  ^* L, r( B$ Y6 \$ n1 s

    + n- S) n" D) F! P' mPyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。& o6 e- F* g5 ]2 p  R" Q  o
    6 x2 y: q: j0 J- D" p0 H
    PyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。& D0 S. N8 c  U. l0 [

    , v! x: C& U+ i% W& TPyQt5特性如下:0 @1 y/ i" c; m0 U+ r" m
    - M; c7 C6 ]& i
    基于高性能的Qt的GUI控件集。8 ^# m; m  k. Q
    7 |7 m) N* a2 ]
    能够跨平台运行在Linux、Window和Mac OS系统上。
    % b0 i- F4 d" u9 S' g; k) l  l# |% G2 U; [
    使用信号槽机制进行通信。
    4 v1 x4 x* O5 I4 l0 u7 F0 z5 d3 o) |6 Y' @6 Y& U" K3 X
    对Qt库进行完全封装。* T; X3 M6 w$ i. o* ?! Y4 ?$ s& C( `
    ( c( v4 p0 j$ [9 t) O. W4 D* P
    可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。; \. ~# @( Q7 d+ i) Q8 d  j8 x0 u
    7 G# c, U' O' y! m
    提供一整套种类齐全的窗口控件。
    9 ]: t" d* h5 Q; d$ J- h  A% a
    - S. {# a# D# D1 S# ]8 [0 pPyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:9 N6 m2 {( X$ @" m
    $ E1 F8 x9 ^' I7 C
    QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。
    ; s' {# p5 f4 m0 l5 q
    3 Q( X0 _1 \, o2 BQtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。
      c3 O/ B" |$ b5 C! R: O# b# V. ?( I$ w% H) h* r
    QtWidgets:包含了一系列创建桌面应用的 UI 元素。
    " r/ k, U7 O- W3 O% J5 @! L% a
    - Z8 x! c4 \% b! I8 q4 uQtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。; y+ n, X5 ^/ {, y/ M1 q/ @
      Z, l% S$ A" H  s' X4 a
    QtBluetooth:包含了查找和连接蓝牙的类。
    . I; G" s- P5 z
    5 Q, H/ `, l# iQtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。0 s1 ^* @9 T9 O" G% q6 k! }2 O! `

    ! c9 ~4 J2 M! [0 ~* ~QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。# Y7 M# {6 Y2 H

    . k6 ^$ l  ~- @8 x1 d. [! VEnginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    5 \/ p' ~0 [+ I0 P! _/ o. c$ h  x- {. [! c3 h3 y( ]
    QtWebSockets:包含了 WebSocket 协议的类。
    6 C- l. J5 S7 m3 h( Z9 f) b/ V2 v, ]: ?& H5 i% }1 d* ~  U
    QtWebKit:包含了一个基 WebKit2 的 web 浏览器。+ u  B7 f0 L, J/ y9 m( F9 Q

    # j9 U6 m( J& H  j9 FQtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。
    $ w7 [; F" t& `& I
    $ X' [; r; V$ ?# p9 IQtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。7 H; Y" D8 Q3 `% A5 T
    0 i" N, o3 \& D
    QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。* ]; W* X" B, }( D0 G3 |1 X

    ; v. F* t! |3 C8 SQtSql:提供了处理数据库的工具。
    . r  Q# r8 ^6 z1 [) x! y+ I) r# B4 M7 n5 Z2 W& P
    QtTest:提供了测试 PyQt5 应用的工具。
    , E6 d4 h' k( X* E9 ]! c- _) g. H7 W+ Z1 F0 j9 r# f3 N8 e) |, f, t
    PyQt5的安装8 R* O/ K5 A) C; z, E

    6 a3 h3 j1 y; s/ |! J% r6 j0 P由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5
    ; Y6 @! @9 }+ G2 @/ v- s( W/ D7 s$ H; ^
    安装PyQt5) e1 n7 S3 y6 d2 f, A

    5 Q0 U; L6 a; J3 Fpip install pyqt5
    : O! W( @% M1 G4 w$ }& |8 r% Q! S  Y( N5 j+ x: C
    pip install pyqt5-tools  I* o3 ~5 J" M- V; C9 Y  r4 N
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:( F1 v, A& |: V7 L( A

    7 _* N6 D/ [8 l, qqt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
    $ b3 q+ E' V4 W) F" I# B3 k解决方案:
    3 r6 r5 g4 E& S3 @0 ^
    2 \8 s" {; a( l( j/ E  K: \) z/ Kpip install click~=7.0% p( Q) A  e" k2 q, g3 W1 _3 @
    Qt Designer的配置
    " _) n) ?$ g# v% Z" L- ^# n7 v
    4 h' m5 |( m2 HQt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。% N5 p1 V2 K6 C7 m8 q

    # p4 W' G( C$ U2 G5 g7 Q% m. v/ v6 a! B6 R! t5 r: o
    4 _/ N; M5 E% g" m% U5 L) M
    整个画面的构成:
    & [7 F$ U0 s) J; d" D. p+ \) ^. t4 R5 n
    左侧的“Widget Box”就是各种可以自由拖动的组件. W) Q2 F9 U0 [7 \9 N$ t- l
    - Q/ {: {: ~+ y+ ?' B+ W7 U9 p1 F
    中间的“MainWindow – untitled”窗体就是画布
    7 E( D4 f$ ^) Z* d: v( W5 {6 `: r+ \. [2 r
    右上方的”Object Inspector”可以查看当前ui的结构
    $ ^% c6 C+ W" |, E/ W7 v+ I1 \8 b8 f8 n. u
    右侧中部的”Property Editor”可以设置当前选中组件的属性% e" I2 ]7 y4 e! n" b

    ( w0 r2 x, Z% G# s7 X右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等
    ; [% @. f8 [5 d+ _1 b# _# h5 _' a
    3 A9 ]" `+ o: Q1 ]" I最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。  Z6 L, P0 ?& Z' K% \7 N) C
      V) `, `3 w% B5 C, A
    QtDisigner配置
    " C# e# [- w' t% |' Y( [- |" \( s9 h, Q) o! P
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:' o  g; d: @* F: l

    6 u$ E  Y: \: }8 mName: QtDisigner' ^& i# A, ^0 z, [# d# p/ M

    5 T$ I# }. }( P* E5 s, S' ZProgram : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改
    / y  }2 b! I$ a& |7 C) U$ k& V& N
    ) A) T5 ~+ P, IWorking directory: $FileDir$
    + B7 |% C2 q# e" s- dPyUIC配置9 k7 {7 A$ U8 a9 m5 O/ ]3 {& G
    0 H4 e1 g% s* B  |; @9 v2 e
    PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。) o0 V) }  _4 d$ D: \9 K+ K4 _9 m
    $ J" T# T( X5 F
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    3 r; F) E8 O6 a: J: }. ?( \, S; z4 ^4 m9 P* J
    Name: PyUIC  J5 h/ w) W4 V  @3 V

    : |) {) a3 k! L7 O6 P& S+ r3 |" \Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改
    6 W8 q3 j1 H  Y6 K- x7 o; \! Z( T& Q; s2 y& }* E, E" p
    Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
    ! ]' i6 P9 w9 u+ {' Q2 f
    6 d, {9 p" k* }; d$ `" J8 F6 `Working directory: $FileDir$
    8 }" N/ L" V) b% d! o9 V. M- UPyRCC配置! q3 U. B' i' A- y6 x9 S

    : w3 A+ W4 ]( Z0 S- m) CPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:# \- r" g/ c# f! h0 X! p* }! Z
    + e( M( \! p* H; I' E7 a
    Name: PyRCC. f/ [3 ~; O. t3 m

    $ z  y8 X) m0 I! e  Y& [1 H8 k3 j1 t. lProgram: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改
      c+ |' Y! K; i# Y- u" Z, F$ Z
    - k) L8 Y7 }! ~! s2 }/ QArguments: $FileName$ -o $FileNameWithoutExtension$_rc.py
    2 q/ {, l6 O4 Y1 t- _( J) v2 k6 I) J
    Working directory: $FileDir$3 k9 `' W+ c0 s5 e9 m3 ^
    PyQt5使用示例
    9 _  u  D3 O2 w6 \" m8 d) M- f2 D& [( t6 p. u* K8 u
    创建一个空白的界面:9 U* [7 Z" r# e! j8 F- f* ~

    ; b2 K( q; v  C; |import sys+ _/ m( Q5 Q2 n' H1 \9 [
    ) @+ F5 k4 B  s
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    : K! c; |1 m! [3 u& f: B
    6 n& c5 A) _% ?/ K5 Papp = QApplication(sys.argv)
    * F" J# g+ I2 [3 @+ W" K; b5 J9 Y+ w0 U& G+ R$ U# `2 }# n
    win = QMainWindow()) x" n. h% M. X* q. `$ u! w+ r9 s

    , z: `. @0 J9 B) T1 e( hwin.setGeometry(400, 400, 400, 300)* n9 k, r; _" e! _5 A

    ' g) @7 c# L; r( p% [* gwin.setWindowTitle("Pyqt5 Tutorial")* i" y) G( a3 F; p/ F
    0 ?& y; g# P0 ~7 }: q
    win.show()
    . J/ U. d7 f/ w" I  ~7 B3 R
    % k# A, T0 E7 F4 A: v! Nsys.exit(app.exec_())' Z8 n6 O" x: L. s
    7 `, z" M1 ^* a0 C- y. ^

    * g) v6 A2 s' U1 n6 U/ Y' S. H& D$ h; h
    其中:
    3 T% \7 @3 Z; F5 u
    . r  p/ C% q& }8 qQapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。# Q8 W) p9 D# N
    ' }  ?4 S( F5 C. O/ h+ k) l( a& o6 Y
    QMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。
      @- H1 ^+ t: A3 k9 M
    1 z& d$ u+ r9 i: g- V2 `$ ESetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。. u  v  l/ g$ |* O6 i
    ! U- n0 e2 d! C+ z' y9 y4 t7 E5 [
    show():用来显示窗口
    8 W. t, X0 b  ]3 @, O$ n4 Z5 ?& w* v3 |7 }; `6 c
    exit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭+ j1 v8 D- s$ s# p) ~+ {3 o
    9 A9 |8 F! @  h4 d3 O& H* _9 j* t! `
    PyQt5支持的常见Widgets有:' l0 K5 i$ k/ w- Z& f4 z1 {
    $ ?2 y) C0 W& n7 P1 T: g4 n  H
    % }# G' Y' I2 z, t8 N- s" [. X( D+ }% k4 L
    . t: K0 Q( ^3 [: {9 w: w  F
    从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar" A7 s" y: t1 B$ n; t$ m1 _# y# X. X

    : ]8 w& m% E# h% {2 ^0 d9 {: I' s* e对于使用Pyqt5设置文本内容,我们使用Qlabel:, ]" g  H2 ]9 M- T
    ( T1 w' ]2 i; O9 F+ q: ~
    import sys
    ) N0 ^) c# D" C8 _9 U0 i) U. ^: T/ f4 B6 c1 N' {3 b
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel$ H3 Y; S7 I0 ]# x) H2 c# L' k
    : h8 c4 }( B1 x; D, I/ G3 ]; T
    app = QApplication(sys.argv)1 n* Z! B5 ~. P0 T
    ) ~  z1 u4 t  j; {9 a4 L2 ?" A# u. i
    win = QMainWindow()  }' O8 ^5 p% E" _1 t6 m1 i7 z+ z& R

    * [! j6 s, ~  t8 B/ N- e  ]win.setGeometry(400, 400, 400, 300)/ J* ]" z  J; K. h. o% A3 f

    6 ~" X. }' j7 F& Cwin.setWindowTitle("Pyqt5 Tutorial")
    " |' N+ p7 p; Y( H  w8 L  b
    - Q. O% K5 I' b+ x) ?\# Label Text  D- E( g2 S/ ~
    $ b7 P" b; H( C2 I- O
    label = QLabel(win)
    & j. r% z7 Q- a% N3 W4 i: }9 i' m- l! t9 p# {) o
    label.resize(200, 100)$ d1 i$ S; a/ i( X1 o  e. k& A7 U

      L! ~" I( T6 t& u- Hlabel.setText("Hi this is Pyqt5")  }$ R% E; U8 {2 g. q2 G
    1 Z  |  P" W, F8 ^3 `1 F6 @
    label.move(100, 100)" `7 Z2 E3 T5 C4 R0 E
    9 R; \  X5 {" R# S4 {" A) H" E8 U  `
    win.show()
    3 E/ i* q3 e$ B$ q% ^% `; z; \, X4 ?% x! P6 F  d
    sys.exit(app.exec_())! m: v4 M& T& R! g% A9 Q# W

    & P1 S0 h$ y& D/ _( z! x
    2 T) Y* w7 H1 E" d  R  M) \& u# u# q( r
    按钮与事件:
    1 n; n6 _4 u1 `( c; r7 l" d# J$ C/ Z+ g0 Q+ S
    import sys
    & ^! ]/ @7 ]5 l9 w1 O$ j7 J& t; ]/ Y( s
    from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
    $ W8 c4 H, H! q6 i
    $ S8 L* H2 h# t8 t' k/ `" }& |/ Tdef click():
    % L1 O1 f4 j& J- J2 v4 Q6 [
    $ V. \* W4 Y+ S" s- O  z* L) p    print("Hy Button is clicked!")
    0 Q; s% @( J( z6 w6 ]7 D
    ! r0 q  f2 ~8 A: `app = QApplication(sys.argv)& N% ~( Q" w' H$ S

      {! e% K# y3 \4 t7 L) i6 ]win = QMainWindow()
    " e2 M& U" m+ V" V* [0 @
    % L. S4 R8 o# B8 e* P2 iwin.setGeometry(400, 400, 400, 300)' C/ C" I9 N& K8 c6 ?9 l4 y

      ^9 [+ V& K/ J% Awin.setWindowTitle("Pyqt5 Tutorial")7 q; y  ^5 I8 {% d& A5 w3 b
    0 z* i( l+ _4 D
    \# Button
    * C2 P$ H( f! i6 T& ]8 d; i. b
    & R2 p3 _6 o- Z) J4 fbutton = QPushButton(win)" Y; e+ K4 [. J" y6 X! v: C% @- D0 Z

    2 x# H2 q6 J2 s! D$ Hbutton.resize(200, 100)( p! l4 {6 b. k  l3 L

    5 Q! q. t6 l* V  B+ lbutton.setText("Hi! Click Me"); e6 d: u: |, l$ y& p% F
    - {1 Y$ |# m8 P
    button.move(100, 100)
    1 W3 T! ^. w: }( C( V2 Y. m  O
    * h: @, w5 E0 v* X0 ebutton.clicked.connect(click)
    ! k3 f7 [: k- o! S6 w6 S$ W- C; v5 [  A7 {& u
    win.show()
    8 ^9 z& |5 I1 a, U( e; a% T6 `1 {6 t; O
    sys.exit(app.exec_())! g) q4 k" K9 r& ~+ n2 n

    6 V  u$ X& d( l5 K( x  V4 d' I: Y! x9 a* J$ Z

    " T0 A) S( P4 e3 R3 n0 n$ H0 Obutton.clicked.connect() 在按钮点击后执行特定的事件。2 R$ L: P+ C. o2 ^0 ]

    % ^; k6 ~' L7 K7 {# M; T0 zPyQt5实战
    - U4 S4 L7 h# f1 }7 I
    ! B. y4 l+ i+ |: e8 D6 @实战项目:简易的天气查询软件+ |+ Y$ b7 d7 L, ^% N3 `0 V, _

    4 W* p" Z+ F/ a3 e4 U0 R  L1、使用Qt Designer设计一个界面& q; I/ \& P* q7 n; A2 N
    7 k* J0 H6 i& }8 g) Z

    - u3 i( F8 ?. C1 r1 N: l% ^6 T8 h7 Z( Z
    用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:
    - O+ e3 P, V* y/ I" L0 r; n% R
    7 D) e" d4 k( E+ j; i6 O* j0 O在Qt Designer右下角选择 信号/槽编辑器,点击+号新增
    4 f+ N% s, s# Q2 N6 c" T+ P- D# G$ a; C9 j
    分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    7 i, O- K5 y: ?) b$ [$ J5 t, t6 Y* e9 z" c1 n! ]! H9 _
    以上完成后保存为Weather.ui文件。
    6 O% u# V+ b/ {0 B- s" t  I; h
    4 j2 A4 s; l+ K) D# V0 {- w2、转换.ui文件为.py文件
    0 t8 S( o1 d' R) B* M, L9 Z* G4 d3 }
    PyQt5支持直接使用.ui文件:) f4 ~8 X- u9 D2 f! X
    8 Y9 _# Y" W/ ~/ I& @/ k
    import sys; F1 h& E; P# h4 z+ ]2 K! z
    : |3 L4 ?/ c# _$ y3 \, G. q
    from PyQt5 import QtWidgets, uic/ ^" Y; @! @; k+ u5 b2 K+ R

    7 C  w) [$ z! happ = QtWidgets.QApplication(sys.argv)
    8 }/ \& z! }) d$ p* F6 q6 [: j* X4 q( n8 w" h. A9 `( [8 @8 E2 c
    window = uic.loadUi("mainwindow.ui")
    ) \, ~$ V7 }$ _& ^7 d. M/ u+ x2 b1 S. p1 x, ?5 w
    window.show()
    : O5 ]* v9 v9 Q+ F( j
    # d5 L4 ?/ S# X# i! Sapp.exec()' n; ?* {- \- D& T: v
    但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:; a( Y9 h' o9 f; d4 [; K
    7 o) u! O+ ~' }) J2 @& `9 ~% o5 |
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py
    + b7 R2 g, r3 S2 t9 J其中,我们需要把两个按钮绑定的槽函数:1 c5 s! r- w3 x% S! ~5 M
    % K" |- Y; s% a) x& ~' c
    \# self.queryBtn.clicked.connect(Dialog.accept)5 r4 s2 z. ]8 P, d6 r
    4 o$ r: h" M4 I( }! s9 P' L
    \# self.clearBtn.clicked.connect(Dialog.accept)4 I. z2 d' s4 g+ m: f

    : P9 o" B  T& x$ l. p, f/ r2 j6 w\# 修改为:& O+ z7 I# {% ?1 t+ p( ~

    * t0 L& v8 L, ^; M0 |* Zself.queryBtn.clicked.connect(Dialog.queryWeather)' [8 Z. q. u, B

    - p$ F( a* k# [self.clearBtn.clicked.connect(Dialog.clearText)
    - G* G# O& e+ j5 ?& \- Y- P最终的Weather.py内容如下:0 z/ E3 d+ V; B) _

    0 a/ M; P* M: x: K- D7 _) j* N\# -*- coding: utf-8 -*-
    9 s; k: S* C. R% U5 w3 Y5 |) L8 e
    0 A1 D* T3 X( C  p3 j6 ?0 L7 o\# Form implementation generated from reading ui file 'Weather.ui'
    ( S- I# y/ k6 I% }. q  o8 X1 D) q
    . `* t) u& z9 A/ r\#
    # j- b( N) F) j1 w7 q5 v4 |. k: L; C4 w
    \# Created by: PyQt5 UI code generator 5.15.4/ t" o9 E: V7 |6 E; r8 l) }8 \  ], |9 s6 p
    1 F8 @0 A2 o& _# [* l
    \#5 G& p* L% E: ]; M

    ( H  w8 R+ ]8 |6 ^1 Y9 `& J) `) E  u/ ~\# WARNING: Any manual changes made to this file will be lost when pyuic5 is
    0 G# z3 d5 N) _5 Q( p; _* V8 G' Q8 s0 M$ S
    \# run again.  Do not edit this file unless you know what you are doing.
    * p0 r- H4 J6 S8 w; y, H( w: E# p
    : K/ I' |' F: z0 ifrom PyQt5 import QtCore, QtGui, QtWidgets9 H6 j" f) I& h% x# W* G( U' Y
    % G( L, y6 n/ m, g: W1 ~4 y
    class Ui_Dialog(object):* `. @1 t: S4 x4 j( C( |
    1 W! U4 s( r' P+ `/ o- {+ ?  ]
        def setupUi(self, Dialog):
    / E8 Z- T% y- a: H
    ; j8 U! G/ F& ^+ B; T$ N' R        Dialog.setObjectName("Dialog"), I$ r$ l+ P% Y' u/ c
    / k4 |  |) y  i0 Q0 q+ _( m8 p
            Dialog.resize(600, 600)) d, z  v& m0 _5 ?2 D: s6 o# P

    * X% C# O% t3 r9 W9 o; z8 I        self.groupBox = QtWidgets.QGroupBox(Dialog)) o( R/ S: }- b9 v! Q

    8 M# w3 T* J, E$ ^2 h        self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))
    " i' x' u0 |# Q5 ^5 C: i+ e8 a) O
            self.groupBox.setObjectName("groupBox")) ]" G1 F( ]8 c) j" k

    - _9 m# F+ O$ U4 x4 E2 u( j        self.label_2 = QtWidgets.QLabel(self.groupBox)' ]7 X  D$ W+ j  r7 x

    9 O8 y6 b5 E4 k9 Z" m% d/ {6 d! P        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
    ! A% ^/ h& T& \$ ]( ~) f) A0 F$ O" }& n
            self.label_2.setObjectName("label_2")
    5 t& J8 g& Y; a$ E( G/ B+ A5 ?9 a4 z# H6 ?" T! I
            self.comboBox = QtWidgets.QComboBox(self.groupBox)
    1 E5 A) N& G# \
    ' V5 j1 n& }- ]/ h4 A( p# q+ M        self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))& Y8 S3 T5 H- {8 V7 N& f
    ' R  C; d0 M2 P% e. q( u& q' v1 }
            self.comboBox.setObjectName("comboBox")
    ' p( j) B, u8 }' `  X; o  n6 Q5 }, F! n/ k3 O4 S7 q
            self.comboBox.addItem("")0 G" g6 G% F8 K, W; y8 m
    8 w5 E; w4 f5 C& Q
            self.comboBox.addItem("")
    $ \& i% g1 q) m! V, W8 d1 o" g( U% Q; X& }3 d& H& i
            self.comboBox.addItem("")
    # Z. Y( E$ x# K& {1 U/ k) w6 e; ~; Y
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)
    8 R- l  @! }2 S. u/ G0 m7 U8 T# ?4 k) v8 h6 A: x  ^1 t
            self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))6 C& X/ I& }. b5 @2 a# X! e0 H

    3 L, g+ s! M9 |0 I! |1 C6 h        self.textEdit.setObjectName("textEdit")
    7 w" V' K3 Q7 j
    : z% m2 h5 \6 p# z0 O" ~+ }        self.queryBtn = QtWidgets.QPushButton(Dialog)* k* z6 }! [  p2 ?5 m. U* y: y) l
    ; G% m5 k& q2 r# e( u' u3 H, K
            self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))1 s+ _( |% W' _
    3 g" m) \: q; J( \
            self.queryBtn.setObjectName("queryBtn")& k/ Q$ s: ]4 U
    ' k% P8 X2 ~# O8 [) |7 l; J( u4 M& f
            self.clearBtn = QtWidgets.QPushButton(Dialog)7 m1 U- A3 {- r2 ^9 i# R

    6 ^( I5 x0 i1 {3 _- @        self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    * ^' m3 {$ R3 T! v( t" E8 ]/ S1 ~+ H# N8 F5 X+ T
            self.clearBtn.setObjectName("clearBtn")
    % Z3 k$ U+ h0 d2 m% {2 i7 M, r/ F( n- y2 z
            self.retranslateUi(Dialog)
    1 e# r" t& ?- p: `  j, {' e+ j+ c0 ~( j9 z9 l9 n" f
            self.clearBtn.clicked.connect(Dialog.clearText)
    / Y' D( g! k: d! Z5 U6 J$ A5 c$ Y! x
            self.queryBtn.clicked.connect(Dialog.queryWeather)0 j9 \1 K/ `) d1 v) {- H, Y/ @

    9 I1 m/ m# Y  @. x4 b/ n3 N        QtCore.QMetaObject.connectSlotsByName(Dialog)5 W7 `- j3 o0 B
    & `* X( h) X: v) Q# @' E6 q
        def retranslateUi(self, Dialog):
    ' L9 T7 f8 w: N  F8 w8 N- F( T* ]9 C9 w; L3 F
            _translate = QtCore.QCoreApplication.translate
    , c  r' ?8 q& d8 C% Y% `: n. U# e. D2 O
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))8 l) T% }, M8 s! K9 W

    7 f8 V/ d+ R! Y% _2 ?  t        self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))5 V) {: g2 H, G
    % m) F  c; k- i8 t9 f7 p5 X. e7 L
            self.label_2.setText(_translate("Dialog", "城市"))
    % z; ~4 R1 ~* J) `
    5 G; q8 y. Z5 j7 N% Y        self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    ; [  m- X4 L0 O7 _6 ^/ ^5 _  j7 j1 M
    0 L# s& q& k5 E& v9 U+ ~        self.comboBox.setItemText(1, _translate("Dialog", "苏州"))! d/ p- S! c- t
    + Q- c  m  u. N6 J1 a# h" n9 S% a
            self.comboBox.setItemText(2, _translate("Dialog", "上海"))
    9 P! G  o8 N2 l; _) o& H3 o0 v5 M
            self.queryBtn.setText(_translate("Dialog", "查询"))6 s; Z- B; W3 }" l

    $ I! n/ U3 v. w' I% w9 U        self.clearBtn.setText(_translate("Dialog", "清空"))
    5 o  {' h6 b4 Q" g. H/ f& D  V5 `$ L8 z
    3、调用MainDialog6 X* `! M0 _9 X4 A' O1 P. u- {" e
    ' b. [! J9 g# o4 m
    在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
    9 V- D; [3 C5 M2 f( O" _5 q: b
    8 R7 A' }) [( }2 |( M完整代码如下:% Z4 S6 w+ ~1 l; _% c

    8 L/ s! a2 A$ y3 r  r4 uimport sys
    7 p5 P! H9 P2 O/ l; u- U4 t0 E/ Y2 c# ]2 s! |
    import Weather+ z4 c5 W0 `. X* Q& ^% M
    : O$ ~4 h: o& j  K3 H
    from PyQt5.QtWidgets import QApplication, QDialog  S( C# N: F) J; s, I) c) c7 D

    9 H+ F0 L- R3 y2 Kimport requests
    3 J. y9 q4 h* V$ P' c! A. G
    3 K7 f) x3 B3 f* m( Rclass MainDialog(QDialog):
    ; ^7 M; y) Z/ d5 {0 k9 v! o
      ?$ ^) P0 O# l4 @9 d9 W1 L: J    def __init__(self, parent=None):
    " y* X% Z  X! A3 r+ B7 c
      J; h1 O! Q# R' \( B* R- J1 q8 [        super(QDialog, self).__init__(parent)# n; o' `, u  w- i# ~* C

    * R, R9 Q5 H1 k" ]% v        self.ui = Weather.Ui_Dialog()
    ) [3 I. q7 C4 ?* G' y8 L# n% b* V) I: C- V- a- }3 j
            self.ui.setupUi(self)% |; w+ }- Y0 K1 z& t+ V- W& G

    / q9 j% Y  e$ x( o4 U    def queryWeather(self):
    # v4 o7 s$ v* D: q+ H
    & z  D# d: {1 ^, e7 Y8 t2 |        cityName = self.ui.comboBox.currentText()0 U8 e: F& E: P! s: d
    ' g1 x3 C, ]! [; g
            cityCode = self.getCode(cityName)" I4 R5 Y; H7 }: M

      o" R( H# D. U        r = requests.get(2 ~+ m5 p) x! P9 S

    # G0 E2 t* s1 a/ B/ d            "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(1 X) N' n- Q1 p: S( K3 F5 c
    . X4 j# C3 e( U+ W! K3 X8 c% n
                    cityCode))
      Z2 ?0 j/ A$ W$ ?
    4 s9 e7 H$ m8 y- w/ P+ Q" g        if r.status_code == 200:8 O. `" @5 W2 A+ X% c* a$ O8 f

    0 y: ^6 k" k( z5 d4 f1 h, h            data = r.json()['lives'][0]
    9 T" `4 a8 M; ^4 p: S6 V9 g! |1 i) Z. a" v3 }
                weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    7 p1 i& P/ T: L' s( m( ~  o
    . x$ b. D& ?3 O; [' m                data['city'],
    - g& B( U. [) Y% f* N! P
    8 ?8 m& V4 G0 l2 L# Y4 w* A                data['weather'],
    " z# k% E* K; H) l# Y  C( `- B, |( N, V+ ]. G0 M- g
                    data['temperature'],
    5 Y. k* {" _. k% t
    5 r; x$ E5 z* ?$ O8 M0 G; H                data['winddirection'],
    0 R3 q2 B, R4 R, n% J5 L( o" C) u% K: [$ i/ K$ l7 f( O
                    data['windpower'],2 S3 Q# r) R9 B# c
    ! q# N0 `7 T( N$ n
                    data['humidity'],
    6 W2 |4 N6 {  P3 V  s" g
    & m0 g% p( S4 P7 D, s                data['reporttime'],  Y! w2 u- D; L, h/ B' F
    2 p; O* d$ y* s
                )* T, Q/ A: `" D0 I

    3 _1 O' A+ J8 c        else:
    ) n3 b3 X0 e+ i6 M- J! ~4 R, _; @' z! K2 |# J; L
                weatherMsg = '天气查询失败,请稍后再试!'9 S. P3 [7 Z0 b6 G( G
      J; k' N  @, l. f& I/ ^7 ]
            self.ui.textEdit.setText(weatherMsg)6 Z3 F) V! }) h6 l0 Y

    * _$ F2 b6 I& i    def getCode(self, cityName):! S. V. O- t2 v0 p

    ' p: F  q. o1 v/ ]7 Y8 T! e3 ]0 K        cityDict = {"北京": "110000",  W! m9 C" p! ]# J0 D: S! D
    3 D+ |' W  ^  K( ~
                        "苏州": "320500",7 o9 x% t5 c  M" e: Z- [$ m, s
    # v: b/ ~7 |8 z9 }8 v1 C7 ]7 Y9 _
                        "上海": "310000"}5 E7 h* p6 k$ Y/ c3 q

    6 Q  i. L5 j2 B6 A& T        **return** cityDict.get(cityName, '101010100')
    % w, j  A# m; e' z% R0 v5 x2 ^2 r8 N# |' p8 N
        def clearText(self):
    " A. h8 Y' r# f9 z
    - R# j0 F/ e; H" k/ Z% p% L        self.ui.textEdit.clear()9 z! r/ V- E1 I+ u7 k. m# _

    % F5 G: s8 `1 g% S  dif __name__ == '__main__':
    ( L3 ?: O2 z  d+ ^1 ^5 x4 ~# d7 O
    ! T( ]( y, Y6 e0 p0 @  y! S    myapp = QApplication(sys.argv)
    / T  S  I& u0 c" Z5 s: a7 s/ O& ~  h8 c
    7 o, L) F9 ~) E( ]+ P/ @4 E! }. s    myDlg = MainDialog()
    4 D" U! l9 t; I& k9 U* }1 Q: ^& ~/ s6 k5 r* T8 K7 P7 R$ j( w) z  u
        myDlg.show()
    ; c& N8 C. H1 x- |# l, ]$ P$ ?' Q8 Z$ e1 |
        sys.exit(myapp.exec_())/ C! w) f' J. Z
    , {0 R+ \4 k4 x, J2 C
    运行demo.py并执行查询后的效果:
    0 x- G2 e* ]' V* x/ f: P8 K, \1 Q4 ^: F2 E# l( E5 S* U

    6 s3 I# S4 E# B0 E0 [  G! R8 b% j/ L* M1 V% r9 k0 u/ A; P: n+ _" D6 F& T
    4、将代码打包成exe文件
    : O, O: j, @) C" m
    $ {' q+ ^, }, L( k将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:- F0 ?- C* y7 W8 [5 P  {

    ( A0 ^, T$ q, V' a' L& n
    ; u6 z8 h0 W  r& J0 L6 a& C# G! f4 t
    py2exe:软件更新已经不活跃,因此也就略过。
    / c6 V6 w+ m& f# m  c, g7 H" U7 Q% H3 Y
    pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。& p; B! n8 V! ~! b% G  A  ]
    ; S3 L( M! _+ j6 O0 o& L: [
    fbs:基于PyInstaller,使用起来更加方便
      S( I- x# I' R0 n5 \( V" B  [8 ?: c6 k3 B- w5 k# a
    这里选择了fbs来打包。fbs的安装方法:
    : F& M+ e  O/ ?0 R& |" p" ^2 l  B
    pip install fbs
    / E2 p; T, v7 ~* q( ~8 t使用方法,在命令行中输入:7 Y% D- m$ L0 G5 z: ]

    2 }5 B0 i. c4 v7 r: }fbs startproject7 F# }1 W, \. n* X: _
    执行完成后需要输入一些APP的名称等。完成后会生成如下目录:
    ! x+ |4 y; z1 _% G. Z1 {9 c0 [0 P+ F/ o- v9 W$ O
    & |( l& m: w  f& x* v9 f, d
    ) t1 g# W6 u9 l8 _& w
    将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:: J- x, ^, Q! l& ?# t3 H
    4 h! z/ K; C' e9 `! ^0 e
    from fbs_runtime.application_context.PyQt5 import ApplicationContext, ]$ k: P3 d/ P" C7 Z0 k
    ```. c$ ]7 `8 e5 G3 |2 }
    完成后执行:% K6 J% |! f0 m
    ```
    ( i; g9 m8 p& M0 z: Ifbs freeze
    / d4 S1 E" E; Y```
    6 N' K1 @  |* g即可实现打包。生成的exe可执行文件在\target\MyApp文件下。
    - l$ y3 j2 a8 ]1 e# Q2 Q' f) ^6 x- x3 ~1 y
    ————————————————
      ?' F; G+ H- a0 T版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。2 o7 y8 u3 v7 R3 }/ F8 i; e: W
    原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667( ^2 l- K* n4 g( B2 q, }+ X

    + W( M( f: g) t. p, v. u+ T. m- y7 K+ i# C/ v7 j. I# [4 A; B  K1 S& @

    . Z! ?7 [" s: C* Y' [$ m
    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-9-22 15:36 , Processed in 0.570574 second(s), 50 queries .

    回顶部