QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2186|回复: 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使用指南!) v2 S# u) b2 i

    * Y* B& D; M$ D. l使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。7 B3 {: O% A# P/ @
    ! G/ M: u' U2 L; u* f) M: K' k! D
    常见GUI框架7 W/ K$ t, Q- n; c+ e! y

    * S6 }  z) m  [* G- O* IPyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。
    4 ?7 S" U2 X' Y- k/ A0 R- ^2 z! [4 z5 @5 V" t! Q9 ?( P. k* I7 ^
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。
    & K, |$ I9 }( N% h2 }3 G# }
    * n1 p6 {% Y# z% kTkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。
    ; @  @: _/ h4 K. A( V5 c  A
    6 c+ l' T3 x" P; H, y5 l6 `3 B5 QPySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。
    / g* z: ?  W$ U+ ~' v6 n% O
    0 D3 ?3 W# R, j5 ~1 ]) N( lWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。
    " T  n3 q  t- `9 q( x% K0 Q! k" G5 c' E" _5 F
    Wax:基于wxPython ,为克服wxPython的问题而制作的一个包。6 j9 N6 K5 d7 b$ v, j
    ( w) V$ M# J8 x0 D+ A$ r! k2 O- Y7 l
    Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。
    & G3 q# R( t3 Q! Y! N* w5 S
    : o8 R# `, t% I) G# dBeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。% X& c' ~: o" ^2 j* M  Q" @# W
    0 i  x) R- \, A8 U( ^% G! L4 [
    Toga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。3 F3 N. R% H9 y
    6 N* ~' U) N' Z9 h$ z/ B. S
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    ) A' o2 |$ G( C6 c
    # T: c7 p; R0 Q+ t' K  NFlexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。" v0 ~9 {9 p. P6 [! @

    * R6 d* u* ^8 }. S# qpywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。
    5 m: B# z" h( ?2 F( I
    ! D& T4 H5 \8 I$ h5 R+ Venaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。/ s  P6 h0 N# }! _) J
    9 f) y- k! J/ b! ^
    个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。
    - p" C4 Y/ |& r4 u# W! Q# F
    % d+ q" m6 {  ?8 \PyQt5简介
    0 ?, {  p! [* e# u9 k" q8 D' C  n
    PyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。
    ' |2 \9 L+ W1 u' h2 j* ?1 G
    8 Z6 j1 N/ f9 A7 m4 |; QPyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。2 Y9 N  N- K3 e/ X2 M
    : ^6 O5 V5 U  w) x; U
    PyQt5特性如下:& J& f; Z! J1 u0 a& K3 O
    . }9 }) K6 r* L1 ]5 d
    基于高性能的Qt的GUI控件集。1 B' m' I' P4 q# G7 S; b! h
    $ V7 r5 m3 p3 r7 Y. Y  ~
    能够跨平台运行在Linux、Window和Mac OS系统上。
    $ W0 Q% d8 d* S5 q- \3 b5 B8 V
    ' ?1 |6 s- d% K使用信号槽机制进行通信。
    0 Y' t3 e# R3 ?' e" b9 c6 y; E6 H  R1 o7 `6 F7 \6 ~, z4 k
    对Qt库进行完全封装。
      t; b6 Q8 D6 I( H
      N1 \- V  ]* V# G; h6 N+ ?5 ]可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。
    % o0 @0 [5 p; ?- n
    " a2 ~  D. m( ]- c& c提供一整套种类齐全的窗口控件。. h" F" d' b! z* a
    - F, C+ u1 d) h* ]
    PyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:
    4 p' v) u2 ]8 G! N
    ! I! {6 }- d, x" Q, c1 M- N) w2 A  `QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。; B$ G  {+ {" @/ N8 I- }" ]

    " G) }" X' d: ?/ `, l( }5 VQtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。
    & j5 ]4 ]0 K  m5 F9 X/ t* ]
    & _# J0 m' z# @" l/ X, wQtWidgets:包含了一系列创建桌面应用的 UI 元素。% C" A; U% x3 Z6 @
    ! W" \0 I& `) L8 ~6 z
    QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    3 \8 O" M$ p$ @
    # l) n5 D9 b6 O/ O) WQtBluetooth:包含了查找和连接蓝牙的类。
    7 {2 O$ }1 F' c2 V% A6 u, G1 p/ E/ X- ~/ g4 A: e
    QtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。$ F5 p3 p. E( g9 L7 O* m1 t# u' e

    5 i+ E& p3 O2 d7 DQtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。( a. l/ W+ I9 p
    " N& V  n% s! t( p+ ^1 a$ [2 a; F
    Enginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    - q) G! z5 Z* D3 v
    , J$ K9 b( ^2 F! uQtWebSockets:包含了 WebSocket 协议的类。
    1 S; Q. g- F4 B/ ?
    $ _$ O# G* A$ u2 `! B* e5 l8 fQtWebKit:包含了一个基 WebKit2 的 web 浏览器。
    ; F' Z- q: l# {3 ?! {, \$ H8 x0 Y: z7 b  d" f8 A  C
    QtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。
    : `" E6 P9 j2 D, G4 t; y3 p+ C* F- U0 r( U* ^, p2 O" {, t% ~
    QtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。; z& T& n  S/ e9 ]
    . P* |7 Q5 [; v0 N7 v4 F+ e( ?
    QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。. \( s5 t, D5 S" S" D

    1 X+ w& \; `, \  Z- PQtSql:提供了处理数据库的工具。
    " B# p9 A3 ?! N3 s4 Y* @0 ~3 {) P% q$ t' L" M$ H8 a
    QtTest:提供了测试 PyQt5 应用的工具。9 l  O$ z2 p6 p9 O1 V
    " {" V% s! Y. {( \; A  N- G
    PyQt5的安装  g8 I; x( g$ j8 M, u+ n5 N

    ' q1 Q4 P5 Z( j$ h由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5
    5 {# K2 t' {% n; e
    / c$ |8 c2 B4 d1 r! }  E8 s安装PyQt5
    . X. D; a0 N/ J, ]9 W' a) y8 z$ K7 q( }& Q- n& q3 D3 n
    pip install pyqt5
    $ }; z! B" e& I- N1 J  P( b8 @6 ]# i/ w# u6 G
    pip install pyqt5-tools; f2 N. o% ?- ?
    其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    % O- y) {( S3 N8 S4 i# r& w( O6 Z
    qt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
    % U) ^; {4 G# o: r: o' G解决方案:
    8 O6 i* i5 v% e. p+ h% J; W" m, x, C. U
    pip install click~=7.05 a- B" b0 r( p
    Qt Designer的配置
      t. I! C; ]2 Y) a/ Z0 `( u# G3 `" b' A7 ?/ W1 O0 p
    Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。5 l) T9 W9 O4 f8 M! f+ |) `% X
    / B; `& W( l! H0 G5 H$ o' N
    ) f, Z. b2 E( s( u1 J; s, V+ u9 U
    ; s' Z% v+ F/ q( r  a5 ~
    整个画面的构成:
    , c9 Q3 C% w9 Y& k( H
    ! m: M& Q) d8 m' w6 j2 M) W左侧的“Widget Box”就是各种可以自由拖动的组件/ ]: o% ]" L( _8 Z

      S. H0 G& T1 b' ^中间的“MainWindow – untitled”窗体就是画布
    ( ^4 I) Y+ C9 e6 }8 S) W" e% Y2 ]; n2 Y  s
    右上方的”Object Inspector”可以查看当前ui的结构4 P( k$ O) n. p/ C. b9 l% X8 k

    " K/ j6 C. Q$ {, _) M9 k- f右侧中部的”Property Editor”可以设置当前选中组件的属性; l# b2 W8 L9 S( m* b

    5 Y0 ~: n8 v/ P3 E右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等
    7 ~4 H/ x5 k0 O' W% q9 i" i( V2 P
    最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。
    / C) x' J, e/ ?) W& D: B3 H  Q  j3 g9 V, K9 w' }4 \' D
    QtDisigner配置. j- x1 o' X$ M& L' t
    2 P4 M; c9 I- |# I. [, f$ r- O5 o
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:6 o7 c9 Y4 H' {( K  Q. `* p
    % T( q7 y$ A1 `; E$ |) Y$ \1 N
    Name: QtDisigner2 R6 f  C. N- q6 t7 R) Z2 U/ `+ z

    : L" t( b. c+ D# ^8 t) YProgram : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改5 `" S( f: M" Q) X" f
    ) p8 h3 f2 i4 L* R- c
    Working directory: $FileDir$
    " m" x% T1 Y1 |$ zPyUIC配置
    . ^$ |; h* {0 J
    ' P) r6 I1 O, a. y2 D) N" wPyUIC主要是把Qt Designer生成的.ui文件换成.py文件。
    6 j, e! q0 ~4 u2 N0 v; l0 C1 V4 ^0 F3 a2 B6 }! g
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    3 t5 O# B% I$ r& e) ^$ q
    5 N7 S8 ]! i9 L: j$ SName: PyUIC/ }0 @; L" y0 C

    2 ~7 c5 Z- A, Q. S) @Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改
    / A8 j" B( [6 K  H6 e! ~6 y0 w$ t
    ' [+ V6 x3 w+ i7 j! bArguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py: n+ n6 C9 I2 k* R* _
    0 y% B  W& _* x8 D/ {; A
    Working directory: $FileDir$
    7 k1 m5 L5 T7 A$ i4 {1 g( vPyRCC配置
    9 t8 l* d3 n2 q  C$ t0 d9 o& A4 l; @! E. S7 y' E) G& v3 `5 n8 |
    PyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    0 V& L$ c0 v2 u9 v; c: I4 [
    + g2 J1 y1 f8 R8 @# WName: PyRCC
    1 i0 v4 \/ b( x7 l+ I& }0 W& p1 Z3 O( a9 s# S
    Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改9 U9 u: ]1 `8 X# t
    + `# i# ^1 l; @( N! ~$ ^
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py2 D5 L, E. K5 x$ K1 d

    ' [) C% k9 u9 `8 FWorking directory: $FileDir$
    2 x/ X' K; S9 T+ u! n/ K$ fPyQt5使用示例" w- D) E7 a$ g# w+ K  J
    $ C% C+ p! o" a
    创建一个空白的界面:. v4 ]" [- d) I& U" O. Z) T
    2 F) b: Q- O) m+ o5 p- C+ F5 c1 e
    import sys
    / [" a& M6 j+ i. o5 m$ j: o4 c% E3 X0 X: {  @- j- A3 H+ _1 e
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel' G+ ], U, C! @5 I* r0 Y$ P; s
    2 j* H: H* a6 `' V4 {; ^1 [
    app = QApplication(sys.argv)
    ! n; p0 G7 [8 }  P3 V" X7 o- E
    2 c, |/ A( [6 D. D5 K. ewin = QMainWindow(). A; E; {3 m4 ~$ b

    # b& u1 e, O+ Vwin.setGeometry(400, 400, 400, 300)
    ! O: n8 B5 P5 T- _6 C& B8 C; U
    2 L; F- Z4 `: wwin.setWindowTitle("Pyqt5 Tutorial")  \/ H' L0 Y$ x1 F9 O" ?, |
    8 y/ ^: c" N$ d& t
    win.show()$ x3 W7 l, @  m! L9 L

    9 v3 ]- _  B  F9 S2 k5 asys.exit(app.exec_())
    3 N/ \+ p# a" C
    6 r2 _2 N# a8 }* I2 @+ X/ q5 v. O! }7 ]+ [5 _

    4 ]- u8 z$ Q* `6 E- l1 ]% T; t2 {其中:; O8 n& d- O3 T# r2 o# T, h

    : R$ U1 n8 R; r1 y- hQapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。
    5 U' l$ d4 {5 v1 C  D0 x* V3 m
    6 D0 j% \, v) \QMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。8 i+ e1 D5 o# t, t" a0 m" L% e

    : B( |' I' W1 w7 G; j" ?SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。
    " r6 e9 a) ~+ n1 a" H- Q) W% m. x6 p0 V! I
    show():用来显示窗口( G  w% ]: T. ?0 c/ s+ X
    , @4 Q) h4 }: O4 V4 i% b
    exit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭
    # k8 @3 ]# @- M- f- C. X4 i  ^
    2 C# s3 Z* ?4 g. @  H' J; ]8 k' lPyQt5支持的常见Widgets有:
    ! f9 Y+ S8 X) h% a9 j, l; r7 l$ F  M5 E2 |& s8 H7 e+ p4 g
    ; F  u0 }6 v# w" A

    8 ~+ b2 w8 j4 K8 Q从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar1 K. N3 I' v1 X$ J. X' @$ _6 V* g
    6 c$ |% I% s3 L2 N6 e1 v7 f
    对于使用Pyqt5设置文本内容,我们使用Qlabel:5 R3 y2 \6 z; A" u. `" R7 E( f

    8 m: P1 z/ j5 n3 e* Rimport sys
    3 E$ W3 `& S; f% x% X9 U; p( C/ o% l
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    " M9 R: Y5 G. J( S6 K/ R7 `- d, a  ~+ B5 u* ~" C( `# |. L4 I7 `
    app = QApplication(sys.argv)+ ]4 C1 q3 g, X$ a6 v. m+ u
    / O" C1 a# ^' Z- s8 ?- Q: r
    win = QMainWindow()
    0 d; I9 d; a1 R* t* x5 c0 \/ f
    " B1 L2 r9 V7 [0 _win.setGeometry(400, 400, 400, 300)9 f4 E( c/ h2 |" H6 Y8 d3 ^
    . _6 Y1 [+ t  u* X" ~
    win.setWindowTitle("Pyqt5 Tutorial")
    2 F. g7 b$ }- p8 a4 z. Q. ^7 @9 z4 r# k& I6 B8 E
    \# Label Text+ j# S- Q$ [2 S. x: O, Z5 L
    + X5 L# s3 G% @4 P' L
    label = QLabel(win)
    + \. T0 ^- F. K, B) I1 G- w- n: `  e7 v5 b) _  e4 X/ f8 U7 f
    label.resize(200, 100)8 z. X; K* i! ?1 A

    / D; Y) Y% q' u4 g( a) y6 qlabel.setText("Hi this is Pyqt5")* \+ B7 l/ ?* j. v. T
    * z0 I( v" W! t# y1 g; L6 }
    label.move(100, 100)' k2 b7 w7 }: G  j) I- b

    ) ^8 y6 [/ E! X* E5 S7 hwin.show()% K7 {5 z4 C+ u7 p( t  b
    8 J# c% }& Q) N4 K
    sys.exit(app.exec_())
    6 f. |1 h' v0 H6 X0 u& ?1 U' Y6 N  n: L) A, Q# q
    . ]' o2 |0 ^4 D- \

    2 ?+ G, E. r% P$ d按钮与事件:1 \& Z; Y9 d( u6 T
    # `' a6 P. c5 P2 J3 u% l0 F! v
    import sys
    * Z$ [# N5 y/ Q9 v" [5 J5 S2 d4 \
    from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
    1 W$ t6 H  ~( ^9 u, R/ S
    5 \3 J% W. b/ q4 F0 H) B8 s7 j" y) tdef click():
    5 z% ?: g1 p- Z
    : Q0 g4 @1 n$ F# M7 P2 g( |8 h    print("Hy Button is clicked!")
    1 p. k- a2 Q! j5 m$ |/ P! A5 z! }  ?! v2 Y. e
    app = QApplication(sys.argv)
    % x+ i( ?4 a' x8 m/ Y4 U& r4 f; a
    ) C2 D* g: t0 e' Zwin = QMainWindow()
    7 M/ s" d  {0 x7 ^6 p6 M/ Z+ f# a* K5 E3 k5 d. j0 X
    win.setGeometry(400, 400, 400, 300)3 ^! @. E6 h* q# P+ X3 ~

    " q* ^. _0 i" G- j) q$ Gwin.setWindowTitle("Pyqt5 Tutorial")& O: E; z) y2 g
    : e0 ]7 G" [  C7 G
    \# Button2 m9 G: S+ \5 F7 o1 b
    ; V# Z# h# t" }
    button = QPushButton(win)
    , {$ `) n! S" @; x; S5 E
    & @  Q. y" Y8 B: E0 I2 rbutton.resize(200, 100)! W2 ~! g8 |5 b2 e6 B, ]
    2 [! R3 o  l. x5 @
    button.setText("Hi! Click Me")7 G/ Y% I; r7 d  ?# A
    ; C9 T: M5 ^2 S; r1 e  \. V
    button.move(100, 100)
    , x5 T6 j& W, x/ D. \
    ' {/ v& Z8 F; [& v0 e4 gbutton.clicked.connect(click)  O( s% B( K: U! D# g

    # H9 `, k' E; n  Z+ Bwin.show()
    : O) i+ V5 E9 z, c
    9 M, w" z1 j) A: psys.exit(app.exec_())2 F. h7 i2 I5 \- {* J8 N

    - Z6 F  {) I2 m3 O! U( ~  \( s0 T$ A6 G! A, w. T

    4 N  \, q3 s8 A- s+ R1 ybutton.clicked.connect() 在按钮点击后执行特定的事件。( |' A  B) C$ e: C9 R$ w

    6 `- Y5 e( y) a) |8 yPyQt5实战
    . n8 K9 E9 h  ?9 E) x
    , q9 A! N: R, p3 Q% c实战项目:简易的天气查询软件: ?4 w5 z( m- F" O

    / M& D( X( i: [5 F$ n1 v( V2 d. h1、使用Qt Designer设计一个界面7 F1 f/ t' N- x" H* f9 r3 t8 U$ U; W+ t' y

    - {$ p! s' s- o/ S' J; l! F3 @0 P

    & W: e0 t  ^5 m* V/ X3 L用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:# ^9 J) T1 [+ b! Q8 Y3 |6 h
    , }1 g5 d( v. E  k! f: P% i
    在Qt Designer右下角选择 信号/槽编辑器,点击+号新增
    : O' M7 S) a; i$ v7 k
    . N* Z: D' G5 A# _9 L分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    $ b  ?: b  E: C6 Y/ h8 i
    ; M: d. i5 q+ m以上完成后保存为Weather.ui文件。
    ) D  r) L) h$ B7 r
    3 [: F$ C6 v: I: j" Y6 U2、转换.ui文件为.py文件6 a6 p0 f5 e0 j) M2 I$ q
    5 U. W2 A7 W9 {, W
    PyQt5支持直接使用.ui文件:. m9 {8 j) ]. T6 N& r
    7 M' m1 G; K" V/ c  M% Q# V
    import sys
    ' x9 \* l; H" Q- g3 U
    : I& f% j9 }. u; l* ]from PyQt5 import QtWidgets, uic
    ' N1 D. }3 Z5 b& _7 `+ q; C& l9 p- U
    app = QtWidgets.QApplication(sys.argv)' _& j' B& `) E* t- o9 R
    : f9 V3 e; A0 V( s  W
    window = uic.loadUi("mainwindow.ui")# K0 H& R8 t$ @+ a7 A  @8 _3 R' w

    ; }/ s( u, w  t# K( N4 d1 awindow.show(): I! A) B8 H  _9 @
    $ B) R; f2 ^5 Q0 v( i: L$ r( S6 o
    app.exec()
    ; b* O9 u, _) S: i& o但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:1 a) a  Y+ @6 x7 X
    1 }" n) K. Q  ], n* L
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py
    6 Q) v. ]* O7 O2 p2 h其中,我们需要把两个按钮绑定的槽函数:: q& C. `7 h" b$ N9 C8 G+ S% ^( h
    " L; p* A5 ]- G( W4 E
    \# self.queryBtn.clicked.connect(Dialog.accept)( j! l+ N. q4 N, Z/ E

    9 n: C/ ]" t, b+ }\# self.clearBtn.clicked.connect(Dialog.accept)! p6 c7 d4 }4 p( v2 e& B

      q( ^4 p& l# z) f# J$ N\# 修改为:2 ~4 I) W6 b! t
    $ B+ I& `4 h. h: X
    self.queryBtn.clicked.connect(Dialog.queryWeather)8 i6 F* M- W1 p& D

    : U! w5 l3 p6 c: Aself.clearBtn.clicked.connect(Dialog.clearText)7 M4 K2 _$ \! i  I( u
    最终的Weather.py内容如下:  F6 l7 p2 i/ @! c! Q% f
    + _  k, |% v( I4 j- p
    \# -*- coding: utf-8 -*-
    9 D9 u7 t4 \7 {2 U3 G0 U% c. x
    0 F: U" |8 x9 R/ G2 b; k8 x\# Form implementation generated from reading ui file 'Weather.ui', `$ l: P1 x2 b2 N
    6 ^' z! l6 f9 r/ @8 U
    \#
    2 E! @& C. C2 A
    ( R# D8 s- K- S  w/ S" y\# Created by: PyQt5 UI code generator 5.15.4  k- ~% B" u$ x. {: _

    6 M$ N/ a6 h) }, A/ C' B\#- `& x9 n4 z3 h( |8 s7 N
    5 Q3 d9 v. K/ W/ ^# R) ~
    \# WARNING: Any manual changes made to this file will be lost when pyuic5 is
    4 s! }6 O- N6 Y2 Z' Q. c
    ) s/ M" h2 y1 ]6 _/ }* A) b\# run again.  Do not edit this file unless you know what you are doing.
    # P! W" h  P" `/ L, K% F' L& c& Y6 j+ Z& K
    from PyQt5 import QtCore, QtGui, QtWidgets
    2 S% O3 W/ Y# W& ~& I) c; i$ V' r( q- p; O
    class Ui_Dialog(object):
    ) H' t/ e: h' k1 B$ F5 a, G0 g1 W; p
        def setupUi(self, Dialog):
    2 y8 K0 p% S8 Z; A: l6 ~1 y% v) T! W* A3 x
            Dialog.setObjectName("Dialog")  Q3 L  X4 x2 Y! h# x9 g, D
    0 L7 m* k0 Q. w4 L0 r+ Q
            Dialog.resize(600, 600): s  J  ]: a- f
      [5 s# j3 B4 p$ C' v  A
            self.groupBox = QtWidgets.QGroupBox(Dialog)
    ! e/ U# A( H! A  m5 _1 K& k# _9 F: N5 i: s9 d( Y( n% e
            self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))1 t( p1 \  G6 w
    ) j$ u0 ~* b6 E' Q. Y" ]( S
            self.groupBox.setObjectName("groupBox")
    / S$ Y* o: ?7 F! A2 R0 F+ h6 ~0 i0 d# N# z5 @% a* J9 t* r* r
            self.label_2 = QtWidgets.QLabel(self.groupBox)
    3 V* Y) j* V. A8 p4 {
    ) t' z, V$ c# ^1 H  |( V1 j2 G        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
    9 Y/ j, M2 U8 D& }6 n$ {$ M  A. Z* U% u+ o" X+ w% ~
            self.label_2.setObjectName("label_2")
    $ E% l# M( f* i# f9 t% q: V/ l
    4 L: k8 ^! u/ Q        self.comboBox = QtWidgets.QComboBox(self.groupBox)+ B: h5 n& {1 Y. g
    % y; f9 a2 ]; K. Y5 Y
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))9 C, g9 q) v# ?
    * s$ J- s7 P" O7 O* ?$ I
            self.comboBox.setObjectName("comboBox")% b& B7 |+ Z$ U% a0 v- j* y

    9 c: f" N+ ?) P0 i        self.comboBox.addItem("")4 ^+ ^( c9 Z0 f/ W+ o3 _# `
    " [! o7 n/ I; o2 q4 A5 N0 k
            self.comboBox.addItem("")' E" l, L" h' ]" A. v+ D# _

    ! S8 h; e1 q3 J2 a/ Y        self.comboBox.addItem("")( Y% P! ]1 @) V- M. h
    ) R5 o' ]% `7 c/ H  r) M" g' C* M$ T
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)
    & f0 k( ~2 C! c9 F2 j8 u
    1 P- T* q- [7 M& t  @        self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))
    % C7 j% d4 V1 {* C" \, a% L/ }" G- J+ U, A
            self.textEdit.setObjectName("textEdit")) n: j8 q$ y7 @5 b' G. ~! q
    1 q8 R+ }6 [2 d4 A& ]) z3 C% E
            self.queryBtn = QtWidgets.QPushButton(Dialog)
    ( |6 T5 U8 ]( b% r2 u0 I; D
    % i2 [! n# x+ ?# @5 ]5 B  [        self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))' D, O* r) F4 m7 u: y3 \
    3 Z% e) E& }, Z# s" ^8 ^$ G! u
            self.queryBtn.setObjectName("queryBtn")
    + D( e5 z, Y0 a# a# J7 [9 |$ f4 V9 Y+ y5 Q
            self.clearBtn = QtWidgets.QPushButton(Dialog)
      s6 }) p- X5 K/ i9 U, p! b( _0 P" I: d% E7 F$ ]* s& T# j
            self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    & P. t/ M6 q$ Q1 r: r/ G/ P- b! N( f* t; o8 l  g: H4 `, N
            self.clearBtn.setObjectName("clearBtn")0 @5 h% K2 z3 K8 n' }
    , z, ^' z. E. I/ i- E5 M
            self.retranslateUi(Dialog)% E# f. A- z2 |4 w0 C

    7 h) W+ @$ i: E* V, N        self.clearBtn.clicked.connect(Dialog.clearText)
    8 [* \7 D( v; \$ Y* T$ y# d1 g' q/ `; T* Y
            self.queryBtn.clicked.connect(Dialog.queryWeather)
    . ~1 \0 u+ Q3 O" W3 S' G! N. ]" F) K
            QtCore.QMetaObject.connectSlotsByName(Dialog)
    4 }) D6 X; l. a9 b* z4 [
    3 \: F# I+ \* D2 w    def retranslateUi(self, Dialog):
    $ n+ i  T' Q) K" {: m9 e8 `5 q6 Z. U# |& j7 W# }
            _translate = QtCore.QCoreApplication.translate
    ! I' z$ v! h  m  p! S( m
    - F& G; B$ s  V( a) B: U9 d* ^        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))" y% G# k- x1 @0 H

    1 V- B" ]$ U: i5 V, U% S        self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))
    9 K, a1 F( Y" v' a# s; h2 H" J, u& q! l: k. u: J) C" n
            self.label_2.setText(_translate("Dialog", "城市"))8 v! p( A- ~9 T: q$ t( {# ]; o6 M1 i2 d
      [) }" q2 D5 ?2 [' i& `8 Y6 c
            self.comboBox.setItemText(0, _translate("Dialog", "北京"))+ A. D/ A8 g+ z

    & [& m1 A" N- Z        self.comboBox.setItemText(1, _translate("Dialog", "苏州"))
    $ C5 e# [& X5 x) g9 F5 C' ^( {( N& Y* N4 c8 l7 l1 U
            self.comboBox.setItemText(2, _translate("Dialog", "上海"))
    6 `1 P+ w. ?8 c$ I( P$ a) h; b# M. _1 U& B6 c- `
            self.queryBtn.setText(_translate("Dialog", "查询"))
    / q2 U( ?: N* y6 ?5 u+ V8 X6 Q0 y- n5 Q* r( i. x; V3 E
            self.clearBtn.setText(_translate("Dialog", "清空"))
    - G+ s: j# g# G  [1 Z# e2 t% x  c3 Q, h2 Z' s+ r# L
    3、调用MainDialog
    ; m6 f! w  Q; ?) V0 ~9 g' ~: y
    $ ^0 t  T% j4 C, b在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
    : f* x, F% r! N  _0 a% o8 b" O9 {4 j8 R
    完整代码如下:
    6 o+ v* E; k# O) R' _- x7 Q9 \8 b6 n, x1 V9 T7 r7 }% P
    import sys" H* c8 F1 p. e

    6 j+ h/ d& O, I' |import Weather
    : ~" _( X1 q6 C3 h# e/ D* F
      d1 `6 `4 R' I- Qfrom PyQt5.QtWidgets import QApplication, QDialog
    & |4 w; p2 M+ n
    ! ?, m; S1 R, T8 G7 h- N, y0 `import requests$ Z. h; Y; ^% Q. }( s

    ) H) R' I. S( ]3 l* Y0 Mclass MainDialog(QDialog):, V3 y- C5 A" N7 J! @
    / t2 j0 h2 o1 r
        def __init__(self, parent=None):
      E0 X; |$ ~, g6 M4 v) @4 a9 v* A' w8 t; j' @5 g9 n' w
            super(QDialog, self).__init__(parent)0 \# l$ d$ L' v% S& P5 ]

    9 Z6 Z6 u0 V; v$ D        self.ui = Weather.Ui_Dialog()
    ) C' s: P* \1 O: G+ j& e- n$ j5 ]' L( o1 f5 _; B
            self.ui.setupUi(self)2 }0 Y# T1 C6 f
    : v/ J# K. G0 ?; L% h
        def queryWeather(self):
    / m( c' b! M/ [" y
    ( t# Y* G' J2 a7 H; J3 x7 o        cityName = self.ui.comboBox.currentText()  D9 ?3 ?5 {! n( d& o; y  X

    5 r- ~+ O6 c* C2 X        cityCode = self.getCode(cityName)6 j) O1 U/ j" {0 e' t1 ^# S

    7 b- \3 J; i' ?        r = requests.get() z/ E% n/ \* a& P: w& o7 X

    ' u& h, |, `. W3 p9 n) }9 r            "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(6 T( ]2 Q! k- e

    & _5 S7 J' H4 y) n6 z' l' i+ c$ g# {+ y                cityCode))
    0 s" {9 ?' X7 Y& p6 e% w: o4 _0 g
    $ i+ ^. `. x1 g9 ^5 b        if r.status_code == 200:
    8 [' p/ c! X! x& m7 D0 c) `
    $ z5 f, N: P* O6 R! X" T* L1 M            data = r.json()['lives'][0]
    + n( z: Z4 j  }: r
    6 L* i" U1 E& Y) z, n# P, @4 M* Z( O            weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    * ]6 F: ?1 `$ w- v& a
    5 ~- a6 E# I+ g' w4 K                data['city'],
    6 _% q( R2 o" S0 r3 r! w
    . J+ C. N$ i: u' i2 H/ k                data['weather'],
    0 o/ N+ \9 l0 X9 a2 L; a" [' Z; d  r' m
                    data['temperature'],2 s" W# l: F# P5 R# x& |$ \+ D* [- P
    5 [2 u# v8 W* A6 P. m
                    data['winddirection'],0 v8 T2 m, n2 e* c6 E
    % U" n. p* x) R' g* s* q
                    data['windpower'],6 x3 ]" S. O5 O/ {, T7 j: M* ~
    % D! e% h3 a) K6 D3 `
                    data['humidity'],
    " t3 y% _% S, {0 Q4 g! c3 l
    9 r  J% `" E; i7 t* k* P/ ?7 H                data['reporttime'],: B; ^" f4 {& c$ H- d2 B
    6 Y; F8 p2 V# t+ z2 w
                )
    . q! p# U( X* Z7 ?/ s
    ! m; |. q& Y0 K$ U' \. v, S        else:7 q3 f; f! [" p+ C' r

    2 H! ?) X4 w4 g- |            weatherMsg = '天气查询失败,请稍后再试!'
    & d7 c; h1 I) }9 X5 x1 H3 p' w4 `/ h
            self.ui.textEdit.setText(weatherMsg), W1 p  ?5 k9 M7 ~

    - J* |& @5 U" Q1 F5 y: \    def getCode(self, cityName):- Z6 U  C9 J! y8 D* k1 P4 K

    4 K1 F: z* i( J' K9 x4 s4 w5 ]7 O        cityDict = {"北京": "110000",( `- x6 M6 ^9 A: b9 k9 f. M% m
    3 m6 y; Z; |8 @5 s: T* x
                        "苏州": "320500",' m0 }* Q: g! ?% Q; M: E

    6 y, c! M: D1 [. I7 I                    "上海": "310000"}7 D' M1 {6 K1 J# J: h% W9 F& y. O

    & n/ n8 E' u/ ]& s) [" S        **return** cityDict.get(cityName, '101010100')! [6 q& G4 s& ]$ K9 o  e

    4 P6 ^! H, X1 q1 c% _" s    def clearText(self):
    / n) u1 |) G/ k  n( [9 f7 {( a1 L* Y% _: @
            self.ui.textEdit.clear()
      W* F* E+ \: t
    - ^" L- i! Y. c" N4 Hif __name__ == '__main__':8 z* p& K/ `- g" R# Z

    0 y6 g+ o% V& P8 j& D* c    myapp = QApplication(sys.argv)
    9 i& ]; E" ?7 l5 A: k6 {/ `
    # v2 \# ~* p. \' ^; Z    myDlg = MainDialog()
    " C) T* B. }( p( }! K! M8 v+ @, O
    . V! V0 \& x* L0 n    myDlg.show()
    & O; @- Q) V+ U8 Y+ \9 O: o; H9 X" L( U
        sys.exit(myapp.exec_())- P3 f+ v3 W' @, W" j
    6 ]* l3 t" W1 V+ x& n% q$ q
    运行demo.py并执行查询后的效果:
    + h: n& {8 N# B9 L. _6 J2 i! C) V
    3 D& \% n4 K2 W4 F: T
    ; _" N, q; r, H4 M1 q1 Y( Q8 U, ~# s& O6 ?) g* J' g
    4、将代码打包成exe文件5 h! t) S; \9 j

    9 ^$ j$ M7 O# `( o将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:2 s3 d+ G$ x1 d$ Z' B: k7 V& V( f1 O

    8 x- }( x0 j8 T1 g4 l
    ) Q1 L3 f( U( S/ ^- t% M, H8 y( ~$ D/ |! r+ r' r
    py2exe:软件更新已经不活跃,因此也就略过。& N  g. f# ~2 V- O2 ]/ Z6 i7 c: J+ [
    ; w- X/ ?& i7 T  _% p& U( |
    pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
    / Q0 N3 u3 ]% b8 L- b" g. M" u6 s' L1 z5 H2 j* e+ L% `
    fbs:基于PyInstaller,使用起来更加方便
    8 i# t8 |* N- p. K% j+ J
    2 F$ `! k5 t$ V! k0 c' }: M% K这里选择了fbs来打包。fbs的安装方法:
    , t) \" c) ?: r4 Z& o% `. x
    ! ?" l6 O7 z# B! Tpip install fbs
    ( E  v6 C* s/ s6 x3 o1 q使用方法,在命令行中输入:9 T7 i+ ]" E) u# p# T% X+ d6 |

    * H. U8 \& K7 C# ufbs startproject& R% t) r2 y1 c9 v9 U
    执行完成后需要输入一些APP的名称等。完成后会生成如下目录:
    2 b- P8 C3 _7 E" u3 y
    ! t* I% {( \7 W% {) s$ v' a! b$ g  L0 J, P' C  F

    % A1 i: M, b9 H  c将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:+ d9 `' I$ f( Q. S, l2 b
    1 i% d8 W  U( X, F  e$ u9 M
    from fbs_runtime.application_context.PyQt5 import ApplicationContext# L2 F+ F. l7 u; u: `9 G
    ```' {0 R( x2 v5 z9 Q8 T
    完成后执行:
    8 j) n& `! y3 y; G6 M4 Z+ R! P```
    & }( X) r, i2 J2 l9 t6 r  vfbs freeze+ y0 O0 C. s6 E' c. q: W
    ```9 V- V. [* w9 d( \( S4 \1 ?( V
    即可实现打包。生成的exe可执行文件在\target\MyApp文件下。! j: Z2 Q: [: y
    4 n: [9 L# R; o
    ————————————————
    , }# [% E0 A, g$ h; n8 E5 {6 p版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    3 a* F3 h4 C1 C9 |原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667/ i  }# \/ M* a% I" T: ~/ ?4 R6 g
    " Q: r. e2 h' S( G% U

    5 B6 b5 ]; x( H) f7 H
    - k4 g4 N& y' i
    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-10 13:16 , Processed in 0.398474 second(s), 51 queries .

    回顶部