QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2193|回复: 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使用指南!# D( ?0 }" |8 A9 g8 T/ }

    + ^* g& I+ z! {2 P( L使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。4 O( D' g) G4 C7 j4 f7 }

    % y* S: p/ }; c- R# c$ n常见GUI框架. s/ ~: j  t/ q; d
    : A8 u1 @0 N% S# F$ ~9 G7 u/ z
    PyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。( R4 Y& x, K( K+ f

    ) b1 i5 Q8 d4 S) xPyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。) [  Q+ Q4 M$ A/ k2 S1 W/ H# }' }
    0 t5 o/ V8 k; U' \
    Tkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。
    , M9 }9 _' v8 J; a! P9 j2 ?' a
    # x3 g1 e& o* L% @PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。
    1 M! l6 A4 B+ {9 v7 n( e
    0 _8 ^4 c1 A& N& k. t  \# v1 W; XWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。3 `2 e6 h# @( A( M  B( X/ o1 s
    + j$ \4 m1 E7 ~. s4 S# l! t- N- O  c
    Wax:基于wxPython ,为克服wxPython的问题而制作的一个包。
    0 q: k6 [$ j9 F, W. A# ^. f. J
    7 E9 W+ R) s+ Z: b8 xKivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。
    : Z- v4 S" W0 B6 F/ l
    3 U) U7 G* L. F6 Q  JBeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    # y5 g% a" ^5 z+ ?+ M2 F. r2 \* h3 W
    Toga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。
    1 E" l+ P3 v- h: A0 o/ L( c4 X' w) d1 Z3 R- U6 b, ^
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    7 a7 `* b& y" R3 e: s# N) b
    & P) z+ p0 M8 q' |( eFlexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。2 d$ U. W/ v# o, ]
    ; _9 B% t" P+ ?
    pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。+ E+ O, ~! n9 |' y9 S0 `

    ; d7 \  @2 f* s8 G! {* f" H/ Lenaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。7 Y+ w! }' }+ g
    9 E+ i+ u% }4 s) d3 @
    个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。, W1 }# u0 [# u! l1 j, y

    1 E/ b7 A8 H3 a! v5 m6 c8 KPyQt5简介: M, o5 y; c+ j! a6 n$ ^9 ]

    - q7 O! m7 l% s! s# dPyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。
    5 Q, H, I: L( l3 N$ z9 A1 }& v" h8 G
    PyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。; ]1 Y* q! l* }6 n7 d$ z

    : d3 ]/ i: d! |9 x6 t; F0 }3 n' \PyQt5特性如下:' }1 L6 y. O* G6 }- D
    , m) e( D8 o" D: \4 O
    基于高性能的Qt的GUI控件集。
    4 }$ k* M3 @; s! L  m% h0 D) M7 l7 ?, D( d+ g/ R  p
    能够跨平台运行在Linux、Window和Mac OS系统上。
    : o; `8 H6 J0 ]1 C. z2 d8 S
    3 \! B# D( x0 q3 I7 H" }使用信号槽机制进行通信。% a( M- j/ Y0 R4 _! x" f: S

    8 z3 E" h8 p" ?* v$ h" T对Qt库进行完全封装。
    2 @( w  \# y9 ?9 s* Y- ^1 P7 ?# m0 Q  @8 E. c) h0 _+ n
    可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。
    % A* E9 u# x. ]1 g" [! c$ m9 Q% ~# C! f0 ]- W) y0 x, a4 l
    提供一整套种类齐全的窗口控件。
    3 P5 V3 e7 J" t* q( F( d5 n$ S3 M4 L  c2 u
    PyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:2 ?- j+ ~, N5 K& b

    / ]) w5 U" G: q0 l  K, A4 CQtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。0 j2 J( c' W) E- |. h1 S  H
    $ O! l' L+ Y% o# j
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。
    ' R. r. j, A# j1 @' P* K4 k3 s6 p/ b0 _
    QtWidgets:包含了一系列创建桌面应用的 UI 元素。% F& e# Q/ P" O% E1 l7 I
    / P  a6 i; Z# D2 Q4 p/ b2 e
    QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。8 E( I* \2 \5 U9 [( C( M
    * j" v7 C3 V) F6 A( |# ~
    QtBluetooth:包含了查找和连接蓝牙的类。
    1 ~' c1 ]& |$ F3 c9 b8 O* r/ ~9 t, |6 k
    QtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。1 k& m7 q4 \, [, e

    2 ]) W3 T3 T& M' \QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。, o  A* `' |. m" p

    1 A/ N2 T3 x; u+ a1 X* ?% z  j! E  xEnginio:包含了通过客户端进入和管理 Qt Cloud 的类。3 o2 x1 O) H2 W  x4 r! Z

    ) G& M: }7 J2 ?; UQtWebSockets:包含了 WebSocket 协议的类。% g2 G, k. ]0 \

      F* v: h" g  Y8 t+ ?) j9 _QtWebKit:包含了一个基 WebKit2 的 web 浏览器。
    ' Y! x: R) u- X+ K$ g  N
    " g' t2 T, j1 c. E( fQtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。
    - |. I) [1 Z* X3 R% d$ K3 f/ C1 F- x8 u# _3 I
    QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。: |4 q4 j3 m1 t" J  g

    " L2 M3 r8 W% l# M1 h6 e  d. @QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。
    % ^0 X# w/ A: L5 |
    " U; T5 O: [' X, ^' h; R* R2 c7 fQtSql:提供了处理数据库的工具。
    ' |# a8 M- |( i& D7 X: s+ N1 {; O$ ^
    QtTest:提供了测试 PyQt5 应用的工具。
    9 O- `5 f- N) \4 q8 g
    - [  d5 L3 x4 t% pPyQt5的安装' S4 D0 t( w1 M# Y& R! q3 k5 n
    , c% w: q! A8 O
    由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5 + n& G# {  F$ X+ @' z+ z
    / ~: K/ |" l- s4 S$ R
    安装PyQt5
    + D* ?7 ^& n7 h- T* y7 I
    0 @5 @4 o$ k  L2 |- jpip install pyqt5
    , w( s0 {6 c1 N6 X6 y- ~3 y6 D1 C6 u8 t
    pip install pyqt5-tools3 g+ N( n3 X* R$ q  \5 I
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    6 B+ N- t5 M- f5 N  u' @7 a. S( n. T* H) v( N$ ?+ \
    qt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.1 s- y: U/ v5 O% J% U9 _' @3 @
    解决方案:1 ^4 h5 c+ V7 V1 @0 p
    % I7 G! r8 U+ C* |, I
    pip install click~=7.07 Z  |, I0 {, X+ Y* A" Q
    Qt Designer的配置
    , o7 g" a; @. W6 Y7 R7 b! s. [; V- c9 p& T9 O& \! E7 Z& w
    Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。
    * s$ ]& l& o1 ?
    ' T3 F, b1 Z9 R8 ?7 E3 I% L
    , ]1 R  e4 B% X, Q' _
    + s# E0 G/ ?  H4 T% r. Y% ^4 @整个画面的构成:5 \: {- k$ p# M3 r% c
    , _4 z: L( D2 h! V+ k. b
    左侧的“Widget Box”就是各种可以自由拖动的组件
      k* n  {& }8 d1 p) o3 q9 T: k9 \- Z7 \+ H" x. L! d" k, u
    中间的“MainWindow – untitled”窗体就是画布
    $ S% n- t/ a7 x% D, C
    6 \( [7 U$ V9 w" t, Q8 W右上方的”Object Inspector”可以查看当前ui的结构/ o6 `6 n0 \  D( |0 O+ R  b% c
    , v' `9 u* ?1 [; ~* c  V
    右侧中部的”Property Editor”可以设置当前选中组件的属性
    ( d' S! i, w$ L  j  S$ n1 g2 e
    ; n/ d! {' O/ @+ O5 i  N8 G右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等3 h$ n9 \& y% o" I
    ' E- w9 U  V$ J/ e. H0 x
    最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。- d0 S9 \4 `5 k% `1 I
      |) q4 v, ~# V4 u8 C
    QtDisigner配置, x& _. t0 q2 O8 q

    ; g) u7 a( _' x在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    * L. J1 Y. @" R8 V# @4 @  p& f$ v, ~: J1 c- g. ~$ d- B
    Name: QtDisigner
    7 c& v& F8 L* _  J* ]% ?4 n" d2 x/ }* c8 y+ X/ o
    Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改
    " b0 P- e' \$ K& o6 {% ^8 k4 ^3 C' u; W1 ?- r+ O
    Working directory: $FileDir$
      E# J6 C& f" ~* F6 y& d& R! PPyUIC配置
    ; S/ P2 [" s% M) ^8 h5 [
    5 p$ {; i6 z1 u2 ]PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。9 j0 S' G- l; l

    ( \+ g- J! |3 z  o" j! Q在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    3 T# \; _' y& I0 L8 k; r
    0 P5 K( J6 D) g1 N% c( jName: PyUIC% Q7 u0 X2 ]8 M( Q& e

    ' E2 u2 h+ E2 G7 jProgram : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改2 m$ r. V0 T/ O7 s( n' x6 M' N

    6 K! u: e, s/ [9 K! p; l6 pArguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py3 F: ~0 G7 E( W6 n8 L
    * F( q9 z4 b/ F$ _
    Working directory: $FileDir$
    7 J: ~4 b- G- m7 wPyRCC配置4 O3 M1 W) B: [8 C# I$ E$ L

    ( ?) b7 U9 q: s8 P; h: dPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    ' A; x' X& n- }3 e; ?1 F) E% [4 R4 T- ?# N. o& Y
    Name: PyRCC
    ; @& m5 R" v5 g% e' W/ h2 x6 `0 F8 r0 X) [
    Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改
    & o8 r' F' \  u2 U" R* b% |7 \, t- P9 Y! p: g! R. V8 v3 Z
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py
    ' J! U* u5 C, c' b9 ^
    ) `6 v1 [1 W) ^4 `; AWorking directory: $FileDir$8 D9 `+ h6 d3 B) p1 Y* S" Y
    PyQt5使用示例) {8 x" X9 v: R" i0 L
    8 r* x6 d9 z; C( ?5 C
    创建一个空白的界面:
    ( Z7 O1 _2 t" p  D  Y/ G6 |- H. @4 Z/ Y5 d" i5 Y
    import sys& ?- h  ?1 X; q

    8 Q2 x( x; N+ y% T! [- i4 U/ @from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    - ~- S+ G. @# J2 f& R, _& u
    " u! a3 K- G; O* L! J' uapp = QApplication(sys.argv)+ V8 c7 u, S7 A
    % |9 G% q' q: H/ C, m+ o, n
    win = QMainWindow()0 i: R2 e' q; \3 b* ^3 _
    1 r/ ?2 x4 Z; r  [. ?
    win.setGeometry(400, 400, 400, 300)
    9 `# C0 q' Q  S- Y) @$ k9 u0 ^, _6 |) ^, h# q2 G% L% ]: q
    win.setWindowTitle("Pyqt5 Tutorial")) i3 C; u& t) ^1 S
    ' q; R/ w( T  L' D0 T1 w$ E
    win.show()
    . V' ~, G* C0 h! Z) G+ L# k  u; V7 O/ G' W: Z. P: Z
    sys.exit(app.exec_())
    * H8 {+ H( ^' ]9 p( w% s
    : p2 `+ q% P) E2 q
    ( x, j' {, ^9 Q6 ^, }6 k8 \+ y8 r! n( `- b  L
    其中:
    % }5 ^$ V9 c! P6 e! d* L7 \' R3 K9 w7 C9 `4 A5 h) e4 ]9 T, w1 U
    Qapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。
    $ {1 M. j( W% }% k8 Y
    4 R0 W4 ~8 Q4 P# v" Y' S! q1 qQMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。0 y4 ^( m7 e8 K: g
    8 {/ ^8 m% {2 y5 G+ F
    SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。
    4 o( ~- s' b8 k+ `* j% X; d) ^5 m) G% }5 ~5 A2 h- A
    show():用来显示窗口
    - J: I- T8 I. T+ Y) X- L
    9 `; X2 o! u. H% mexit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭
    : Z1 w+ ^! W" L+ c3 h0 ]4 f& A
    + j4 L# x6 i1 D4 _4 y! q0 nPyQt5支持的常见Widgets有:) I4 O9 i% l1 ?
    . G) n  s( V0 D5 W9 s# T2 k* p
    / u- D/ T. |2 V! t  s
    3 i0 Z' U) w+ I: s0 }$ G$ y  t
    从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar
    4 S+ B7 N1 P* n4 O
    1 \3 U+ Z1 i- T2 R7 Z对于使用Pyqt5设置文本内容,我们使用Qlabel:* K/ c0 N7 Y$ v% K

    ' H+ C- s$ h3 X: U" c- nimport sys9 G1 q* V8 c$ o1 [7 z
    / v- I( t6 s. f; s6 `$ F3 |4 F0 G( y
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    $ R2 b8 m! |/ w/ D2 E' r! W
    ( P6 l2 D7 ~8 p" B7 ^app = QApplication(sys.argv)0 }. o2 K6 [1 s$ `3 K* c" R

    . W/ q! i# H* U: x, C) `% jwin = QMainWindow()
    ! @1 m6 [2 [( k$ Z$ M! k' l; U" S- A/ U* L, R
    win.setGeometry(400, 400, 400, 300)
    7 g+ q% a/ B9 E" i4 N+ y/ d7 l/ P7 z7 G) c: }3 x" W  t
    win.setWindowTitle("Pyqt5 Tutorial")/ I& f% F0 h5 K  }, A8 h

    ( ^6 D2 _' B, s% q9 u# ^7 `\# Label Text* N7 k: @. ]2 D" H
    $ z+ Q) V! G) Y. M# H' v/ K1 [/ B
    label = QLabel(win)
    6 R" g, T2 r. n8 @
    / j. T- Q6 B: P' |. F& clabel.resize(200, 100)3 @! }0 S8 J1 k) r9 c
    3 ?# R) ?. j3 O6 B9 A
    label.setText("Hi this is Pyqt5")
      ^0 l* k- a# ?; Z3 I& ?1 i* X) r: ?% J' d7 d
    label.move(100, 100)
    % [% S. v2 A% k9 R8 G, P' i- `+ V; @' d
    win.show()! c1 _% T) d+ G" e+ a
    * e. m6 Y- w$ u/ b$ x4 U
    sys.exit(app.exec_())
    2 a+ b" S3 O3 c' Q; _
    % w9 \# c1 G8 B, U+ d* Y% x/ k
    + M* q8 @( D/ V& y. d$ ]0 U3 F8 s9 e! |* J8 _) }! A) a6 H2 S
    按钮与事件:& i2 i; J! b+ N1 l& R7 G! e
    ! S) K- @4 I8 \
    import sys) V% B) B! S' E/ J& @
    $ F: [& r9 q( A) Q% D8 W4 V
    from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, c" `# g  J, f6 W7 P

    % i6 ?+ ?5 Q; r" D/ pdef click():
    1 d9 a$ Y' X; V2 h+ X6 _
    ' d- o% }5 G! G5 ^/ [    print("Hy Button is clicked!")
    7 Y) V/ F9 x) S% ]! a- x  Q  E9 c3 _! W
    app = QApplication(sys.argv)8 ?! H7 x  _7 S3 n& y+ x

    0 M, T+ N, G0 D5 ]9 Kwin = QMainWindow(); F) Y; o7 k4 w: Z) L0 T- v
    / x8 P$ p* a6 i" ?2 D$ y
    win.setGeometry(400, 400, 400, 300)4 _, G- t: d- M2 Q) B+ ]

    8 g" e7 }0 Z6 D9 `- F2 K8 Owin.setWindowTitle("Pyqt5 Tutorial")7 |1 a0 C, T/ P# E  g/ S- r2 Y
    5 l4 j8 u% n" T) k
    \# Button& N7 q& O" \/ ~
    & C6 R6 R" c5 _' _1 I. }# p# M
    button = QPushButton(win)
    ( b3 j# E& W( z
    6 ?2 U8 [, \2 {4 y- S" wbutton.resize(200, 100)& X8 Q* `/ x) G* G5 Z

    , O& Q8 Q& }0 u' d8 a  @1 A6 }button.setText("Hi! Click Me")5 Y: C8 M- I8 t2 e5 h

    & [% U# H6 u& ^  p( H: ^button.move(100, 100)' R( _' T5 m' }

    9 }& D1 V. m1 }5 W  l/ i9 @6 Obutton.clicked.connect(click), N. R7 L' c" [$ e
    5 O2 r' ?/ ~. K( z6 b0 P2 w
    win.show()- J9 R( r- p2 t$ Y, e5 h

    5 K+ \& E! K2 q/ l0 i, a. asys.exit(app.exec_())0 L$ y' i* |" E

    2 \: Y' C4 d4 I
      {) D' i) X4 B* o; p, D  }
    . E: y) U" f$ z' y  B% q: G, Y4 b, ~button.clicked.connect() 在按钮点击后执行特定的事件。( J; e, t% W4 i, I. S1 U
    . J! d" J. P* [% d$ z9 R; Q
    PyQt5实战
    : O1 K4 [: V" r7 }$ ^5 h7 n7 ^
    $ C$ ^- d7 D( M, D' E实战项目:简易的天气查询软件
    # ^7 P* s7 F7 n: S2 @
    ! k' S* c6 ]* Y; v' C  U1、使用Qt Designer设计一个界面
    4 u: p8 Q7 C7 q4 N1 V* D' Z* \- ?5 N5 U: z

    7 F$ b% t- E4 l  `& e3 @, [& y# h3 N/ M  u, g
    用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:9 H. C# o7 Q0 `( I( t2 Q

    9 `$ G+ c9 Y# q$ i8 }在Qt Designer右下角选择 信号/槽编辑器,点击+号新增
    : [* l7 {( i: J$ E# R# {) q0 ~; W& Z& I7 ]: `* {/ w* ?
    分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    - s  D; G/ ]3 T7 P: T5 b6 [
    # U9 d# U8 {: F* l- V以上完成后保存为Weather.ui文件。
    0 S' i& R. z, q
    . m1 f6 z) }" Q4 F% |1 [2、转换.ui文件为.py文件
    5 m! _3 w5 q1 \8 E% A
    / i! H7 W5 c# A$ TPyQt5支持直接使用.ui文件:+ C6 B& Q& e! s8 c' ]
    $ n! Q# f$ ^* S9 v" B! ^
    import sys
    . n' }) A0 {5 C4 E1 y9 R, l
    ' Y! F; @) b' b# }5 G0 E; Ffrom PyQt5 import QtWidgets, uic+ S& c! @5 S; A

    ' ^6 Y3 r! r! Capp = QtWidgets.QApplication(sys.argv)
    0 {( D. L& a5 l  A8 `
    4 z! o  z( n5 G4 }! L5 ^window = uic.loadUi("mainwindow.ui")
    7 ]3 g9 R1 K8 X. n& h
    " D2 C. l; G+ B: j3 ^& Qwindow.show()
    . d% q, X) u5 ], ]* O9 b
    5 u4 @4 D& U1 Japp.exec()6 }4 P( U7 G4 K" _- y% G% E
    但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:
    . _! z; m2 P- K9 r5 k' K2 ?" h) r# {2 D$ g5 N; S1 c
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py
    . j1 W# j2 s! x) R. ?$ h其中,我们需要把两个按钮绑定的槽函数:8 b$ H' z8 ~$ V9 L8 c* N) |7 o' A

    , @3 I& a, r- i! b6 c\# self.queryBtn.clicked.connect(Dialog.accept)
    - V0 r: {- K' ]5 ?
    / S; X/ ?( \6 w7 m, L\# self.clearBtn.clicked.connect(Dialog.accept)( j0 W* P; A6 {. Q; c

    8 W+ U" n8 H( T1 H* U/ l7 b\# 修改为:5 @, h0 n" M" [; W$ W

    2 w! K6 s" k5 b  q0 @self.queryBtn.clicked.connect(Dialog.queryWeather)
    ( x/ k6 j9 ^& q% a( R) g. ^5 N( U/ F% W) |; o$ @
    self.clearBtn.clicked.connect(Dialog.clearText)
    8 ~+ Q, I: M0 i# o7 B4 G最终的Weather.py内容如下:
    - {# W' j: M8 p5 z, P3 ]/ |3 H% A+ L6 H/ O' X
    \# -*- coding: utf-8 -*-( |) k$ }/ _; S( f# ^1 w
    ; Q* q* S( Y5 t
    \# Form implementation generated from reading ui file 'Weather.ui'
    9 q0 O: P( q8 f$ R
    . G5 U7 ?+ i) x; e\#8 F* ?/ F( e9 T' L& Z
    " h* c- ]: q& Z
    \# Created by: PyQt5 UI code generator 5.15.4
    6 ^9 n/ M6 a" `3 F8 e& T
    8 J! U/ e) m; N+ A' H8 h\#& S( i- p, @) V: ]4 G" ]
    : Z3 V4 l5 N; _, ^1 H
    \# WARNING: Any manual changes made to this file will be lost when pyuic5 is
    4 Y# S% D! o0 V; g: Y. \' y0 [3 G3 i& S. S8 B5 ?
    \# run again.  Do not edit this file unless you know what you are doing.. Q0 e# d" R' d5 O

    0 ~/ j. s8 b8 {% M* A4 _from PyQt5 import QtCore, QtGui, QtWidgets
    5 l6 Q% ^9 b4 ~9 p) j9 ^; \7 h% l
    : g. ~5 A4 f' V8 k- Z9 k& _class Ui_Dialog(object):& q& e1 t) O2 q$ D7 J) i+ g

    1 [3 s; B% O5 |3 ]+ t0 L    def setupUi(self, Dialog):
    6 c- M- K" |8 t  [+ ^: U" p
    # c& \: c( C* R2 _5 D, K        Dialog.setObjectName("Dialog"), X- P( L; ^: L9 W; n  {- g! z& p

      B1 N+ i2 J3 `/ k        Dialog.resize(600, 600)2 M( T/ X8 f" @
    7 G2 j9 l" t' R% j7 n! }
            self.groupBox = QtWidgets.QGroupBox(Dialog)
    ! u) t6 D+ O) d, u8 n! ]: U
    ( J: F7 b& l- i' s        self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))' j, q/ ?0 t* J
    : J/ ]4 Z# x! T
            self.groupBox.setObjectName("groupBox")
    * H6 _0 U% N$ {# d5 \  g
    ) \: ]/ x4 n! l3 j. H% [        self.label_2 = QtWidgets.QLabel(self.groupBox)2 D4 R) b5 P1 l" R) t# Q4 G9 p

    - ^- B$ O5 N1 }" ]        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
    " B$ i- q7 E' D
    ) P$ I) w& T/ s# s. |- h" R/ F  l, C$ W        self.label_2.setObjectName("label_2")
    1 ^  o  i! ?. H# g/ O& T" G( c# u4 W3 @- d4 R/ n
            self.comboBox = QtWidgets.QComboBox(self.groupBox)' `% G' O: }/ O7 N* p
    ' [) S* `! x4 i$ I% m/ \
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))
    ) v, s+ P* y" p! E: Z) [7 Z2 v3 Z, z
            self.comboBox.setObjectName("comboBox")
    & N0 [  r9 r' H0 n* q% O/ ?) k) U+ k9 F3 H$ Z! }* T0 e1 c4 F: @
            self.comboBox.addItem("")9 m* t# \* T: U- Y9 A6 {
    1 y5 R% o; ?2 \0 o0 D
            self.comboBox.addItem("")
    " D8 O' a! a2 K
    6 H0 Q7 s" ~- T+ `& [# [        self.comboBox.addItem("")
    9 Z& v9 ]& D9 j( i% A0 {
    & x3 j/ w% T# G* e3 t3 I: @( b- a        self.textEdit = QtWidgets.QTextEdit(self.groupBox)+ M/ d7 e7 F& c

    % j- h3 h8 T4 R' i        self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))
    6 s0 d. z; D/ Y: C0 S- T+ X: D
    . v8 D- a  W1 H5 ~( N! \# E% F* o. g        self.textEdit.setObjectName("textEdit")# d/ S8 W8 v1 Y3 U# f- \/ |
    / Z  i# }" J* j% _, U
            self.queryBtn = QtWidgets.QPushButton(Dialog)
    $ z/ e+ ^% S1 K$ u3 R" A# m4 S$ ]' b. S9 m2 Y. Q. i* Q
            self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))
    / q4 s8 `! T/ D5 `( l4 ^
    8 M( _1 D: L# ^( m  P% f9 [; h        self.queryBtn.setObjectName("queryBtn")# j+ ]; O: |/ T7 ], }

    # y2 u7 r, l3 q' Y; g2 r        self.clearBtn = QtWidgets.QPushButton(Dialog)
    ( c2 o9 n/ B2 d$ C) [: B( e0 a3 R2 T6 l" {! v6 H& t5 \
            self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    2 `* N& K: C3 \& H+ s2 d' U4 i& m
    7 ]. A- x. c& C4 x        self.clearBtn.setObjectName("clearBtn")
    ) [  L$ ]) @# M6 S0 X* ^& Y) U8 s, K3 z% U# r: D
            self.retranslateUi(Dialog)
    ' D( F  z& N* @3 z# u( q. E8 f; S
            self.clearBtn.clicked.connect(Dialog.clearText)
    . W6 p( F, h* b' n( N+ Q! N" Q9 o# P% X" |' y
            self.queryBtn.clicked.connect(Dialog.queryWeather)
    ' }  l, p- z9 |6 p8 C. B2 }3 q# U# p7 X4 I! P; ~# u
            QtCore.QMetaObject.connectSlotsByName(Dialog)
    + ~4 f( c* t$ m! V4 v4 H5 @* U3 V$ \
        def retranslateUi(self, Dialog):& d. M  C) ?9 z2 w. ]$ B+ h
    ) F+ {1 r) _3 l
            _translate = QtCore.QCoreApplication.translate1 k  ^. R# n5 M1 B
    & t4 o) n- t. A3 S/ f$ m& @" I3 n
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
    2 p( Z4 A" y0 S
    # p* J$ [+ M7 ?9 X        self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))% P0 W. k( T4 n& P

    2 N, U+ I- ^7 a5 x4 I        self.label_2.setText(_translate("Dialog", "城市"))
    : c8 g6 ?2 c# g' }: |0 L
    8 ?' ^( m5 ~- D$ S. p* A        self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    # N; `) U1 R  `; t, p. N4 g! B# H: K) `" o) p" J/ g$ S- L+ ?
            self.comboBox.setItemText(1, _translate("Dialog", "苏州"))
    ' O2 v4 _' E' \' P* G- W
    " N/ _& a$ m. e6 \6 r# w% F2 d        self.comboBox.setItemText(2, _translate("Dialog", "上海"))
      R. z* X0 a* t4 S! X
    ; u$ C: g, a$ @% }2 G4 Y7 C        self.queryBtn.setText(_translate("Dialog", "查询"))  `. |4 e/ p& h
    . r9 s0 \* O7 a9 f4 }
            self.clearBtn.setText(_translate("Dialog", "清空"))1 R6 u  y/ Q- V7 k
    ; {9 G( h  m5 }$ e8 Q, w# ^( c
    3、调用MainDialog. ?; t7 ^" E! M( q) O: }

    ; i* L, C3 w% n8 h  C1 r在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。. f' R# \( \" [

    " p5 d) |" u  ]完整代码如下:
    5 z4 Z' y/ D* X7 r8 q0 Q# J! ~8 j8 Q4 h& t) i
    import sys+ i& J% ]7 i4 i+ J% z  M3 J

    / ?$ Y' S; ~3 }% mimport Weather2 u* g# n& u. B( _# v
    : t6 |( [8 o" a0 {
    from PyQt5.QtWidgets import QApplication, QDialog
    ; [1 Y' t: s" Z) ^
    # w1 [8 T7 X- j8 fimport requests! r3 b8 Q# e3 \' ^' {" f8 M

    7 Z9 X4 ]0 k0 y/ ]; ~  _$ C3 Lclass MainDialog(QDialog):
    6 O: l' ~$ E2 ~9 V# r8 Y& `/ Z2 v. A) C! C# j* |
        def __init__(self, parent=None):) u" C# `7 ^6 A
    & j, {' F. h# ~: H( s1 M) C1 @% A2 g" q
            super(QDialog, self).__init__(parent)
    : K1 u: W% e0 N9 U7 ~/ y' u' _1 ]
            self.ui = Weather.Ui_Dialog()
    - A3 C, C( f( m; ]9 l
    , a+ R# M3 S9 R) _5 m        self.ui.setupUi(self)( p9 Z+ ^: V# u$ A. s

    2 Q# _/ ^" n0 G' d; d    def queryWeather(self):: x& H! I9 H9 b' T

    - e) P) l6 ^3 O        cityName = self.ui.comboBox.currentText()
    $ P# W# \0 |' d3 E
    * Q3 }1 C% z5 i( f: w        cityCode = self.getCode(cityName)5 _& g4 r' s( ?& Y- K4 o3 ~
    % x! M, s2 `4 C4 o5 a2 q$ Z
            r = requests.get(5 N) z8 i9 ~2 ^8 d9 b
    ! C7 W0 |1 H/ u7 {" r# J
                "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(
    1 W3 d% C8 H4 U6 i& ?& t! t1 M" \" n
                    cityCode))
    + O! l% T9 O9 Y' X$ d( r3 C5 x% J# }' q& _
            if r.status_code == 200:8 n0 C$ a0 J+ Q/ j, Z2 M/ U, P

    5 F* f  Q0 P" i3 y3 D, H7 [            data = r.json()['lives'][0]
    + h0 b. B9 B6 f' c# R6 u2 r0 S8 \+ L2 ]
                weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    8 t: N/ K7 a0 [8 D, T& B( m3 }: u3 G) M3 Y& R  [0 k
                    data['city'],1 }; G6 j: K4 u5 |
    : ^! q) p2 ]2 b9 J, D% F: s
                    data['weather'],* N, y, M+ M5 Z
    2 O, ~8 ~/ |- e* Y) q: r0 c
                    data['temperature'],- W/ u3 u) Q- X
    7 I4 Z  P& ~/ y5 p  }
                    data['winddirection'],( B: {# F- r3 D
    & k$ k5 n4 I3 C  ~& n) h( B
                    data['windpower'],' P( o  S* {, C+ G- }

    " Q. u) `4 X, Z, [. x) v                data['humidity'],
    5 K' M# t% |. [, L+ T6 i- W
    - H& x) x* Q5 r& n$ k* p+ x                data['reporttime'],
    - C+ F3 g8 a- g9 ?  j/ e* I2 N" m  w; G3 M6 Q
                )
    ' i" T  g" e) \9 Q/ B
    + Z2 Y  {: Q* S1 b& w4 Q        else:1 N9 E, _/ j$ _( a9 I9 n- w
    ; m0 P% W  ?% @. O
                weatherMsg = '天气查询失败,请稍后再试!'
    . K' g% w* _* @- J1 G. L+ K
    $ c+ H* `7 u# M; u        self.ui.textEdit.setText(weatherMsg)( h* N2 h  U! q! Y

    / D6 W; u: B& l- A( u9 n    def getCode(self, cityName):
    9 G# V! U' ^- a6 e9 H6 B' R/ J. j0 U
            cityDict = {"北京": "110000",
    ( H3 [6 Q6 h$ X
    / ^, g! K2 l, E3 o6 G* W8 z                    "苏州": "320500",) T& A, y( q9 J% U% L8 W8 R

    - q3 \. y- ?9 `9 T2 \* M, Z; Q9 h& ]                    "上海": "310000"}3 n& v6 C: ~2 s. j2 Q8 \, ~

    6 e- V0 ~6 p" j) V- Q; Z! F        **return** cityDict.get(cityName, '101010100')
    5 ~) G; m4 d. X- L( b1 u; x: W, `' A+ I$ ^7 s
        def clearText(self):1 _7 t4 o' C; ^$ T' H8 P+ g
    : m  B7 A# c& V
            self.ui.textEdit.clear()
    4 t$ a( G+ {& |& @- y
    / y4 C2 N% X$ |6 b1 N# Z% T' a" `2 hif __name__ == '__main__':
    6 F& W2 Q+ _" K0 \6 T
    / M! F% C% t+ B& R    myapp = QApplication(sys.argv), ~3 `$ X8 z9 q5 c

    3 j5 M7 p, U6 `' R' l: W3 j    myDlg = MainDialog()
    4 C8 F3 k* Y0 e( w9 m; f0 N1 y4 I' s$ k/ i% {1 I
        myDlg.show()
    ( N$ E  l5 V% Q1 r% C3 T6 m( V+ }6 `) ~  s4 b3 \
        sys.exit(myapp.exec_())4 i. R( y5 w& E! s

    ! |- U: }* X) V运行demo.py并执行查询后的效果:
    % X. d2 x' x  \/ q# x% |) j. ~: f) z( }, e7 p3 I

    ! O) }' F, C, F5 O; `4 C- c. ^; r# w, o- ]1 }$ L8 {
    4、将代码打包成exe文件" r% u6 s7 V5 A7 M
    4 P# f( W3 m7 i0 b% `/ X8 L! m
    将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:
    7 f0 f  d  u: `7 T4 q6 Y- f8 b5 O5 a8 D) b. j& B$ L
    ! a: _! o2 C) _5 W0 M

    " a+ ?0 y: F  }4 Z0 a; P0 T( Apy2exe:软件更新已经不活跃,因此也就略过。
    / ~1 D$ c" N% {' ?+ I
    1 b. ?1 Q7 Y8 F  q2 Kpyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
    - j4 z, y7 y) z( g
    : C# e# o) J% S( w1 Afbs:基于PyInstaller,使用起来更加方便  E, a6 k2 y# ^$ c

    4 s7 r- H$ `2 T/ g9 U: j, h7 \这里选择了fbs来打包。fbs的安装方法:' M& ^2 }, \0 T# A2 ~* q; o$ k
    8 u; }2 a2 b( p% H8 O$ Y
    pip install fbs
    ; N% k! a( x) M+ C使用方法,在命令行中输入:4 k, S/ e6 i" T. [9 H; [1 p

      o. V( O6 ?2 k# U, j1 s9 Ifbs startproject3 R* Y6 _3 T# w) @
    执行完成后需要输入一些APP的名称等。完成后会生成如下目录:' K8 B& H( \6 h
    4 g' [3 K" q/ P7 O" t7 d
    ; Z6 L; W) X& y8 J! j- U! O
    8 D; l, e) k# g; Q/ W* m
    将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:! J% V: F; d. i6 O/ B. u8 Y

    4 ?5 s. s' E" }  T' w2 q! mfrom fbs_runtime.application_context.PyQt5 import ApplicationContext
    6 q" J" M' H! R& K3 T0 x8 h```. T% p: j$ U0 w4 n
    完成后执行:% R: ~5 Z: @0 t" Q/ ?2 R- b
    ```
    + F* \, d$ @1 Wfbs freeze' P2 n; J* L. j" d7 w
    ```
    % s( _: l6 z) {6 y0 L  R" y4 B即可实现打包。生成的exe可执行文件在\target\MyApp文件下。! P6 E+ b3 `4 \& H/ Q$ c
    / I4 I# ~4 A9 ?- b" |6 N7 g( w
    ————————————————! e- R5 F# M: R' H
    版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。! V, P( B( i: U4 D
    原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667
    . D5 O+ X  b1 F5 N8 ^* N0 }4 K/ _( F# O2 [7 j

    8 X7 W& N9 P" }% e  p1 H
    , l" K! z$ E  c
    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-15 21:34 , Processed in 0.609238 second(s), 50 queries .

    回顶部