QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2213|回复: 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使用指南!
    8 ?1 c0 S/ _  @, S2 l2 w' A
    8 t; _0 L" f5 w, y: s  i7 }3 O使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。! p' R# O. f8 ]& p# g0 D

    + ?8 }( }5 T4 J& @2 S7 F$ M* H常见GUI框架2 A4 [0 t/ ^; d1 ^+ ]
    9 [$ S6 ]! L0 t
    PyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。4 Q3 o! @) E. A( E

    4 Z% }, ?# d6 X$ C. d. Z$ P; u5 H$ `Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。
    ; c% a6 _  u: ~5 Z$ L$ B; b6 h/ g  m$ l4 y% F* O5 C7 M5 A
    Tkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。
    , Y3 C) k# \, Y4 O& |5 [/ s, ^
    PySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。2 p3 X. q8 C% C" n; x- z! c
    8 I+ b0 d7 n/ x2 J* J# M
    WxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。) `) |/ O# ~3 ?. q* X$ j
    9 ^/ A5 O! N& W5 L! Q- a; Z+ ?
    Wax:基于wxPython ,为克服wxPython的问题而制作的一个包。( K- p4 ?* ]* S
    - T( Y# M6 U) i" L' u8 B) E
    Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。; G. A; ]4 y% o3 K: ]+ U

    ) z# ^% Q( e3 v" i" \& w/ D! gBeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    2 [  `) z3 x! g) j9 m
    & j) j9 ~$ B( V, tToga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。# I( Y% L1 ]' P" l
    4 F5 E' ?; O, w; o. Z
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    ' c4 b  b1 {  M- l# M1 Q) Z- m' `7 R) X8 P2 E+ p* q: J
    Flexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。
    9 s# f, N4 A. y2 O' }7 ?0 X# v; B) F' s  {. T) h1 h0 {
    pywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。
    2 Y& K) ^& D+ p; j2 k" h6 a2 T. l8 V4 W+ f3 b; u
    enaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。) H6 t9 a3 V* t! G  f4 N
    5 \2 d" W' n; n& `+ F( \
    个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。+ I" @( H% \% l& h( V0 x

    % w) e( G( }7 IPyQt5简介
    . ~+ K% z' P' l; s6 [. p0 h# J. D9 g5 [# x
    PyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。9 \2 j& W, E' J
    3 d' r1 G, r1 }5 R, b  p
    PyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。8 L! k1 R- B  T$ }# f
    ' a, w6 s) X) v8 v
    PyQt5特性如下:
    0 j) X% ?# c. E% {6 Z' ]2 g! }1 u+ B+ _. X
    基于高性能的Qt的GUI控件集。+ X) ]3 x6 p/ ]4 Z9 @: `8 z' ^

    7 W3 v; M; t5 C* ~3 z- D6 d3 K能够跨平台运行在Linux、Window和Mac OS系统上。, ~1 `1 Y6 c4 B) r
    ' E2 e- @" T& u6 s, P, W
    使用信号槽机制进行通信。* z3 L: h0 ]: D0 `+ M( k1 P5 m
    + o3 ?0 B; M6 j3 X" X! j- L& y4 @( @
    对Qt库进行完全封装。0 V1 U$ w. b2 L6 O; w/ I/ X: F" ^6 U

    7 ]: h8 U8 H( s" W* R7 b可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。
    ; A/ [2 n" q& G( @0 |; ~' \: _& c( A7 R/ g% h; h+ M; C/ e
    提供一整套种类齐全的窗口控件。, d& [6 E2 z/ H2 V

    ( m3 }# X7 J5 f, mPyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:" o9 i( I1 F, b6 j

    7 V1 S- h# W$ Z: z, x' E- lQtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。6 n3 V6 P8 A) p/ \  T4 q
    * ^) x3 b  A+ e8 m0 j0 D
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。# t$ o' R6 g6 j$ y
    $ a+ k/ j, ^* X
    QtWidgets:包含了一系列创建桌面应用的 UI 元素。
    7 p  ?3 U; ]! R" t' @. d( f8 i6 }& K' a* F' s& m
    QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    9 n$ o4 N8 |. b  ^8 L% K8 Q; f% q: U3 v/ f: J6 t" Y0 Z
    QtBluetooth:包含了查找和连接蓝牙的类。8 I; }2 ^3 g7 _+ i5 ]

    % Z9 O, A" l0 K- F5 h3 t! k" l/ TQtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。
    $ ?$ c+ d2 t0 v7 }! E* x
    - y9 N' @, C; w/ [& p' {; o: KQtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。
    ; D" f7 W$ S0 Q' ~7 i
    2 A. p4 V' d* F2 }+ r6 VEnginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    # _% ?, x7 S2 n
    # J  B" F, w6 d+ ?/ IQtWebSockets:包含了 WebSocket 协议的类。
    0 F0 N8 n/ r9 w7 M1 Q& N  p# s$ r/ \/ g( d& j
    QtWebKit:包含了一个基 WebKit2 的 web 浏览器。; b  f- y- h) {6 `' U$ l

    * w2 E, a9 r& L2 V& t' \" D/ HQtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。
    * b) G" K. \# E( O' [4 P/ {; `
    ' r" i" {- d  [. VQtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。
    ( ~2 q  t' W& x9 [5 W* K, [. n7 X) n! |# e! Z+ K/ m
    QtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。
    ( e7 D! H8 z5 L: L1 F" c2 \# o* Z2 u3 b% D+ N5 T- Z
    QtSql:提供了处理数据库的工具。
    5 j) p1 T; x4 D) h2 H5 s
    4 X. g7 `2 Q- X: Z3 N9 v2 [) wQtTest:提供了测试 PyQt5 应用的工具。7 A- Z- Y# J9 `9 Z! s8 K2 q; L% U  I

    & C" f! ?$ ^4 h! s  x7 r; I- z7 B, i6 ^PyQt5的安装: y% K( s0 n$ V2 L2 p

    & Z3 M) a* X& H% ]+ v$ G由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5 1 `8 O# g. n; _( r7 U: |( t2 E# H3 `

    9 t* E6 d$ r3 G1 b! I$ l8 `安装PyQt5" @- [1 S. ~& }" r
    ) e5 c2 j7 L) P' u
    pip install pyqt57 V8 E3 h. O( ~( D; m" _& j
    4 B( L# p' P2 Q
    pip install pyqt5-tools
    0 K' Z& u8 g) d9 \3 Q3 Z其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    5 Y$ L8 _' \  w* S& C) H% m! S# a
    & m$ F2 Y# F* k+ [7 f8 ?2 bqt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.
    ! e) ~# a( A0 F( c解决方案:
    % j$ e, ~+ C. b; Q( M; d2 U! w, L" t1 z+ Q% D, Q$ N+ w$ @- O& J
    pip install click~=7.03 z2 T- W8 g5 e3 R9 C, d& H
    Qt Designer的配置
    ! l8 X+ ?' f) C" J
    ; _& D* e0 s+ J/ P; R- ^Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。
    8 ?2 G2 j0 o! \3 }4 J8 D  Z' }. T0 A  f3 G# q7 A  e5 i
    4 S( g/ v1 d2 ]) m/ U( |0 Q# x/ }3 }
    5 s* L* @$ u# F8 T8 n5 Z. Z+ c
    整个画面的构成:
    $ @+ S( q. q" S, o6 b
    % t; J9 S# H6 o" D6 J( X& K7 `左侧的“Widget Box”就是各种可以自由拖动的组件) K3 S; l" `2 s
    ! Z$ o9 ?- q/ U
    中间的“MainWindow – untitled”窗体就是画布/ P/ l+ ~6 _5 `  D

      L2 H7 \/ g1 d" L右上方的”Object Inspector”可以查看当前ui的结构
    8 [6 l, R- I& ~# a. Y( s% m7 A( |9 p/ g. K
    右侧中部的”Property Editor”可以设置当前选中组件的属性
    ' G0 [' K1 F% K' _
    4 x) k9 V' A1 }" N" B右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等
    . F; s5 k' |8 r' {7 e: x. t. n' Y# |9 E! _3 b
    最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。
    8 f' T/ f: |) M6 `* V# _6 y" c: c* F* J
    QtDisigner配置( @( {) m/ x! b9 P$ {

    5 I% c: |& k- m$ A在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:) Z7 s- }8 D( g5 R

    + {* x- h1 @3 IName: QtDisigner
    / y) Z1 u0 a, ^" P' Z' V0 Z# t/ D0 I, A
    Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改
    1 h! K6 I1 o; S: T4 S5 c
    % c7 p8 X" U: F) L0 QWorking directory: $FileDir$: |8 p. O, O* Y9 _: V; m+ D( w
    PyUIC配置
    2 ]& B' h$ z! z& F8 B- f% |
    $ v$ c6 S$ ]" U8 fPyUIC主要是把Qt Designer生成的.ui文件换成.py文件。
    , y/ ?& ?- T9 L3 ^7 V1 P0 n6 e! ?% E7 v# q, n0 P2 C( M8 M
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:7 ^* O3 }! j- t! B/ @
    * F8 C5 L! A; D
    Name: PyUIC
    3 J4 M# y; q3 ?
    0 Q) C6 D& n% E/ A  |/ VProgram : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改
    # B) t7 D3 p0 Q& m: _0 ?- R: m9 h3 I$ I: G
    Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py7 c2 i9 R" t$ {2 Z. H8 \
    7 X8 e( ^; d  a$ l+ \# l0 E' ]
    Working directory: $FileDir$# T/ K2 v2 j: u! J1 C
    PyRCC配置, P+ v) J9 z  y

    0 r+ Y# s/ H) rPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    " A- Q- n6 i5 z$ F
    & O" H! X! z; v3 VName: PyRCC9 z* ]' c' F  f9 P9 C9 q3 E
    : ]2 D! I5 _' u2 ]! h
    Program: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改" ~! r# U; a' q5 n, y& z
    * L1 \& _5 m8 l4 U* P
    Arguments: $FileName$ -o $FileNameWithoutExtension$_rc.py/ p* _  w4 y4 x8 \/ L
    7 f3 q- R6 K4 |
    Working directory: $FileDir$% a; C& W& Y! m6 F2 M# K$ z: C
    PyQt5使用示例
    + H* c& I$ k. ~7 T! L+ F( A  m& |8 q# H* r
    创建一个空白的界面:
    % I: P# m) m0 t  V
    4 }# _8 L" q# w# q( `import sys$ w# E9 X" U: m$ @% t& X% }

    " V1 \( \2 [* Lfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel4 k; ?4 J8 d9 Q; ~: z1 y' H' @

    ; H3 m8 j, N. [app = QApplication(sys.argv)
    " Q: `, L) R2 Q9 ]# r" h* X
    " ^' H! z, P$ ^- D, Iwin = QMainWindow()& ~% ^  n1 a5 |* z

    1 t) |/ D  ]0 p1 L# ewin.setGeometry(400, 400, 400, 300)
    ( B/ }% u; ]+ W  u& w
    ! L6 s, S! a' d: b: nwin.setWindowTitle("Pyqt5 Tutorial")0 d' Y6 ^- u) g

    8 S$ i: |: G# `win.show()
      Z- T8 {) h6 o2 D  G2 s/ G
    1 j, u4 I1 ~  s  F) `, }sys.exit(app.exec_())
    / R& d% a" a' [; @8 |2 c) e% ~+ O% v. T$ G; C: Q2 t
    % K) o3 R% |1 B; w' x
    ) [, i. s' r4 l
    其中:& o! T, v7 Y' ~5 ?; e" r- r  }* P

      ]. T9 {; ]+ s7 hQapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。6 x- {: t  h  G( [1 D, l) X

    0 \; L& S& P5 F  T6 t0 u+ ^* OQMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。) H/ I; @1 L/ p1 S7 U/ }+ ~

    ) y9 M% z) Y9 c0 z8 o( D$ `- cSetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。
    $ Q, Z. q# `9 N+ u+ s# ^0 n0 x. q2 k
    show():用来显示窗口
    , |1 F# \* y4 Q' T5 |+ L( i- Q/ U/ q/ z' g' B
    exit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭
    $ f. A! l- w# F6 n8 T$ j' l" o/ c
    PyQt5支持的常见Widgets有:9 P; H5 ?4 w( l7 v! G4 a. V0 f
    . n1 _2 S' c! _0 W

    . h- M: N! O) Y
    ! N" C/ F+ U. n9 r3 w从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar% \( b# e5 G8 a4 v+ N4 `; X
      l! c2 U5 y6 v4 t/ I
    对于使用Pyqt5设置文本内容,我们使用Qlabel:. D7 [( k9 w/ Y# A2 P! _- }2 p$ w

    ; w8 f% b0 L9 l0 e: kimport sys) \4 g9 e  A2 [4 a' ^; F

    * D( \' x2 o* G' W$ S; Bfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel3 S* M" e: q5 Y( Z( ?7 W
    8 j6 k+ |/ d' p: D  f+ s% P' W
    app = QApplication(sys.argv); F7 ^6 c2 d; q: E* }; N2 L

    7 Y* G& Z2 D; t& Jwin = QMainWindow()( C* u% j( N* b' l4 a
    9 C; c; G$ i. h
    win.setGeometry(400, 400, 400, 300)% w1 D# \/ \% N! y4 T' Z  v3 w
    # U8 ?2 d! H; c5 e+ m1 ?. Y2 Z
    win.setWindowTitle("Pyqt5 Tutorial")
    4 B$ [" ?5 _8 k) Q5 T- v' L5 Z! H. F7 H7 I
    \# Label Text6 R: {$ N. b" z6 g6 e7 g
    : S$ L& C3 X( j, K2 x6 j8 b0 G
    label = QLabel(win)
    5 i" v3 d0 N9 N; G4 P3 b" H1 {. r( {" U& {: x& q: ^( c5 t
    label.resize(200, 100)1 K# x( q- o3 Y
    4 D/ M" \; C$ N* N" G( p
    label.setText("Hi this is Pyqt5")0 p. D: N5 x' k% S. H$ M; t

    3 N0 l, B% K$ h5 P# B8 Y3 y  t& Ulabel.move(100, 100)
    3 d  S' K( }3 I( f4 y0 Y" H
    * R+ P5 }2 Y' F4 Z/ i* d% `- p8 cwin.show()
    / x8 W: e" i* ]+ s3 `9 ~2 E* E7 c' _) d' J( a  E- i
    sys.exit(app.exec_())
    ! b1 a+ |! {, I. l
    - e' H& X" ^3 e5 K) y
    . G2 n+ @  W/ w6 o! J
    0 h) F* T% B( u, \, L按钮与事件:
    ( c3 J6 `( c' V. \
    ' s" _2 @% o6 D; y2 Oimport sys: p% W5 N+ b$ X

    . h' N3 b; q# H2 vfrom PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton- s3 Z3 h, _7 ?- F

    . j- _8 f6 ^9 ^# Kdef click():
    : z' V. k& X- j, m& Y# {. U
    3 x7 K2 ^7 @. H3 R    print("Hy Button is clicked!")
    6 L) Y$ ~* r* E: J' |6 d7 x, i2 W) ?. n0 R; r- T
    app = QApplication(sys.argv)
    6 t# n, G1 X6 q7 N+ c5 t# c: `, b! f: v
    win = QMainWindow()
    1 {, x8 N+ O+ k! O1 u0 S# }
    1 S0 p, m- I/ Q  iwin.setGeometry(400, 400, 400, 300)
    ) T- I8 L; b5 i) i" V: C7 i" K. a
    win.setWindowTitle("Pyqt5 Tutorial")2 N9 u' Y" o. F+ f  ^  p

    ! V. w# A; O' Z. ^2 e\# Button+ O& J8 y" G3 O6 Z2 M8 p0 ?  ?

    + R8 y6 w& O  d5 G6 z  ?button = QPushButton(win)
    & e% v' t% {4 Z  {8 C  ?4 |% H  {. T! ?/ Q5 a4 }* O
    button.resize(200, 100)
    & M, G' x  I+ V, C: `% }9 i+ I/ m6 U; Z7 W) V! q: |7 ^$ K
    button.setText("Hi! Click Me")5 ?- K4 E. ]1 x9 @8 x+ I9 D
    . Y" z3 ~& u1 ?- q8 ?2 Y
    button.move(100, 100)0 N& d/ D  V) X' n

    $ @, m( S+ L- m5 J1 Z1 jbutton.clicked.connect(click)( u$ @% [; n! H9 {9 b

    2 u. I8 h( ]+ E# G1 V- ~win.show(), ]: i# W7 H( v+ h& y2 h

    % U5 H2 u* F6 N+ y, x8 D# bsys.exit(app.exec_())
    * p$ I" c: x' d3 U% u9 T7 o# ^: A

    7 ]& \+ A$ b% F
    : ]9 T+ ?8 F. A9 P/ @6 \. Xbutton.clicked.connect() 在按钮点击后执行特定的事件。1 M( r; t3 [# D4 Y4 D

    4 P$ h" A* Z3 C; r, }$ X& LPyQt5实战
    7 z' C& w! ~/ _7 i- a5 i2 v8 @1 u$ R7 A* L
    实战项目:简易的天气查询软件* Q) _8 K7 C* |0 g1 K# s  {

    : l0 n) s5 P$ B+ }6 a- K2 E3 |1、使用Qt Designer设计一个界面- _- `% f: J, D6 w* u7 B+ c4 }  ~6 i

    / {* S& ]' S3 w
    " W+ c7 }- f% Z8 ?. |) p, C( ^% w* P* l
    用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:
    2 F4 |# U' I/ t  }2 P
    , r% I0 }3 c) j9 k在Qt Designer右下角选择 信号/槽编辑器,点击+号新增
    + B% x& a7 P9 V7 @5 _" M$ M1 t( S& i* }2 z- s* X' s* A
    分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    9 d, ]; o& ?5 ]; w
    # S+ X- a; W3 B% G3 M; r2 {以上完成后保存为Weather.ui文件。
    3 D, m7 @5 G6 J. u/ Z) y( ?
    $ C! i+ {4 t' H- E2 ~2、转换.ui文件为.py文件
    ! s6 c! v1 @  V! h. I$ }6 q$ X6 ?* o/ ^) [. Y3 V3 l! u
    PyQt5支持直接使用.ui文件:
    / d, \$ M. l8 \1 p7 g6 F5 A
    0 N1 ?) @- ?' t" Yimport sys
    - Z. [, G2 s' g& \& g# h4 n5 Z1 e0 g7 A- U* N
    from PyQt5 import QtWidgets, uic
    , [0 A1 g: C' R% r! ^- }. m, Q/ v. [9 X, a/ f
    app = QtWidgets.QApplication(sys.argv)
    7 A6 O2 Q  L: q5 @; a  b
    7 r5 S% ]6 i4 U9 Mwindow = uic.loadUi("mainwindow.ui")
    4 y8 s7 U9 s9 a3 ~- }2 E/ P% d8 K. x" @- s
    window.show()
    1 l* @( e2 T8 o$ }! V( K
    1 \* V+ E. l$ napp.exec()
    6 C& a) H/ A- i! n' f. m, _+ E5 Y7 }/ h但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:
    . }0 a+ r2 l  V7 O; K% Y* k
    1 a( h- p2 K- N! W3 J9 kD:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py
    * N- C4 z# O7 ]8 }其中,我们需要把两个按钮绑定的槽函数:! ~) Q0 n# {4 A9 G; h5 p
    % b0 A, n% T) E7 c: a8 B5 S
    \# self.queryBtn.clicked.connect(Dialog.accept): a, d) z0 C8 o: ?7 Y4 g2 D7 a

    * L1 s% ^6 g+ S; r4 W- b' R\# self.clearBtn.clicked.connect(Dialog.accept): F: h2 n3 B, I7 U6 q9 {
    7 _& b" O! y2 e( {$ U3 i3 ?- r
    \# 修改为:. u9 F! A5 [* I; O! e
    ( g" K; j6 P8 |* V' j$ ^
    self.queryBtn.clicked.connect(Dialog.queryWeather): b# u3 e* `0 i2 T' ~9 Y
    5 P  k5 o; |  h: o6 F' l
    self.clearBtn.clicked.connect(Dialog.clearText)- k0 T! ?+ ?4 }  {0 E
    最终的Weather.py内容如下:  z4 V  W$ J5 q) Y& w* d' |

    & W9 Q$ F- v* g\# -*- coding: utf-8 -*-* W+ `: ]2 W" \* }+ s

    : s8 l3 J5 S5 _3 W2 U' E$ r1 Z\# Form implementation generated from reading ui file 'Weather.ui'. T' n$ s& c3 o

    % N, W: y0 V' t4 y: H\#
    ) n" ~( e6 a2 V7 g) A
    8 x* t- w- E' e- `. ~0 k, d\# Created by: PyQt5 UI code generator 5.15.4, E# n: k; _- n/ {! Y7 N

    # n! C" x9 g/ X! S\#
    # Z" d, l) l# c* y# @1 R' M" i4 M7 R
    \# WARNING: Any manual changes made to this file will be lost when pyuic5 is
      h: y6 ]. k2 Z7 E
    & w- i. {3 @/ X2 r0 b6 m* m\# run again.  Do not edit this file unless you know what you are doing.
    ' ~8 k6 z  L' K2 [2 v
    1 c& L! j5 X7 l* Afrom PyQt5 import QtCore, QtGui, QtWidgets$ ]$ V5 y  v6 x4 S3 k

    & A3 P) \4 u: S$ p( vclass Ui_Dialog(object):
    * H/ Q: \1 P5 i$ ]. i, o' `# s5 |" x% y2 r+ R8 ?
        def setupUi(self, Dialog):
    . T  M* _  G9 C
    ; |+ G/ M6 P! b5 g        Dialog.setObjectName("Dialog")* T5 J( s/ k  y+ H3 E5 g% X( L0 v

    9 h" m/ z! L& f. e5 I        Dialog.resize(600, 600)
    & f5 g6 y, _, O
    * ~' X) m9 ~) W& T5 d        self.groupBox = QtWidgets.QGroupBox(Dialog)2 i2 e5 Y5 R: R$ `
    9 X9 A5 z  n* ^- i/ B
            self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))
    * f1 s8 l" l6 D9 w4 k3 V$ A3 h" K. W* D, E- [9 R4 V* f$ a% i, k
            self.groupBox.setObjectName("groupBox")7 L9 p) ~- p- K3 B

    0 O# p* P' p6 X) U        self.label_2 = QtWidgets.QLabel(self.groupBox). T7 L) ]; A/ g5 s) x4 P3 A
    3 B( h3 c" R- b. T. G
            self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
    8 \% ~3 j% g- u; T5 d
    3 \$ n, P# ?- w, f        self.label_2.setObjectName("label_2")
    # `% g9 |9 c1 k1 [8 [! X- l% v  ~
    & d) i$ M% _' |3 l; U6 n        self.comboBox = QtWidgets.QComboBox(self.groupBox)6 a: k! X( g- x+ e0 l) J( i, y1 ^
    . I( _5 Z- S# g9 T
            self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22))
    ! T6 L0 |8 ^8 X" \% N
    7 C9 b! S0 X6 ~! N        self.comboBox.setObjectName("comboBox")  K* S# @: l( j! e% G

    % b9 H, _6 m# T+ w) d. f0 Q        self.comboBox.addItem("")$ E- Z6 Q: C& y% x5 d" J7 i5 J) v

    1 m+ h# ~% O8 c6 ]' r        self.comboBox.addItem("")
    . U, u3 W8 K' ?7 a
    5 |! Z* X  |. w! f        self.comboBox.addItem("")
      B5 l) O8 M$ A( j! L0 _: T' l
    3 M+ B* ^0 ]: n        self.textEdit = QtWidgets.QTextEdit(self.groupBox)
      Q" T" \+ ]0 r. Y+ H1 t( w. _' {" u% T5 n; t% A0 V: O4 D/ }0 U
            self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))
    6 v/ \  T& W- m  V# S
    % Q6 A4 j( a. O  m3 A& z. _        self.textEdit.setObjectName("textEdit"): L1 p# I- `; x# j0 h0 z
    $ N) `$ _  Z9 p9 J. H( c) T
            self.queryBtn = QtWidgets.QPushButton(Dialog)( K5 g; R# q9 ]+ q$ T
    3 t& y1 M* o: o5 T4 H6 I" C+ L
            self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))3 Q: A2 Q3 A5 i

    5 S  M3 L3 J; U: r/ f5 X3 J$ x4 J        self.queryBtn.setObjectName("queryBtn")
    ; r  F1 c4 u8 u- e. I6 n
    . q- F2 H) F0 D% K        self.clearBtn = QtWidgets.QPushButton(Dialog)
    * v& r. H/ p1 u, e2 z
    2 g9 Z8 n& E3 w" H        self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    2 T2 C: z" g  X4 |+ o+ p6 v+ M1 n( b- E& s' V! b0 k
            self.clearBtn.setObjectName("clearBtn")
    % b. z6 s  m% L
      {5 y# r, A' p. o" A        self.retranslateUi(Dialog)  U4 ]8 S$ r7 g! a9 n8 X
    % |8 V4 k' i* C
            self.clearBtn.clicked.connect(Dialog.clearText)' J& G( o- u  x; d

    2 z& _2 |. j9 H& F3 Q* T8 F1 ?        self.queryBtn.clicked.connect(Dialog.queryWeather)5 [( S2 I- Z. ~3 f( K

    ' @+ s% J) Z1 n3 Q6 A3 s% X+ B        QtCore.QMetaObject.connectSlotsByName(Dialog)7 ~9 r2 f/ _* y- I
    7 J3 l+ p* S1 y. d% W
        def retranslateUi(self, Dialog):" I; ^7 P: P# |9 V9 o& a

    + Z( Q# a! C- g) R& f+ B        _translate = QtCore.QCoreApplication.translate
    ! B3 g; C+ R% z9 _( p. P; n. ~( t1 t; r3 O" P1 ?$ W5 ?
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))! @) e) d% P$ \  @" ]2 D$ z" x
    ( B2 T: ]1 R: `4 R" q
            self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))- B* v8 J- M8 [* }0 \
    & o& ?; h) _& y( x
            self.label_2.setText(_translate("Dialog", "城市"))
    7 c. w1 n& a: c) T1 \( M
    ; k0 ?9 m/ _7 ~& @' E, n) b5 u% z        self.comboBox.setItemText(0, _translate("Dialog", "北京"))2 A5 g; H+ ?0 ~2 [* F

    ( E8 \- j& n8 }4 g% l0 S* Q9 u        self.comboBox.setItemText(1, _translate("Dialog", "苏州"))1 e: ?) S& M4 Y: A5 a. [- W9 v+ b
    0 F6 e/ t& v2 F% t4 J2 S4 v
            self.comboBox.setItemText(2, _translate("Dialog", "上海"))* r+ Y& m' `7 m
    3 I7 W. o$ N  u; y/ H
            self.queryBtn.setText(_translate("Dialog", "查询"))
    & m7 ]( ^  G% e# s' H6 u& C" E- [+ ]& c' S+ z# q7 k. N
            self.clearBtn.setText(_translate("Dialog", "清空"))
    7 S. ], p6 r) @4 Q/ v3 b7 |2 O8 `4 I$ m
    3、调用MainDialog
    2 x2 ?7 E. P1 J' l$ k3 L
    7 ~, t( T) ]: J# Y在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。! L) n4 a" i3 A/ o7 d  g# O
    + S- i: {/ N: O, ?5 V& Q7 c
    完整代码如下:% z, C$ H% A( F' C8 f
    5 T: T5 x9 g; `  X8 L
    import sys
    $ G1 L, Z/ Y6 S5 [$ F6 k; R
    " w2 S; I% D6 a- n& Dimport Weather
    # a/ k- u, Z# C( f2 E! I
    ' k4 V/ x9 M4 }* y. afrom PyQt5.QtWidgets import QApplication, QDialog  ^( N1 t9 @0 Z- W$ E  q

    4 z) n" g" k7 e" E7 I! j- Qimport requests
    0 Y5 ^7 k4 F/ C. k% M6 ]/ E2 }! I* n9 l+ T+ d4 i7 [1 F: Y
    class MainDialog(QDialog):
    ! ?  b9 [5 i) @8 x5 k% C# u& A" Q' t/ L2 P7 l8 L. q3 B
        def __init__(self, parent=None):- A# W% p; T* C9 D* O; K( p/ Q2 |. ?
    8 C/ g" G( u) z- s$ E' E
            super(QDialog, self).__init__(parent)
    + U8 d. b% J2 n% X( g: W) k; V% n9 S+ L5 M& X. k% H, E" n
            self.ui = Weather.Ui_Dialog()
    . I2 [9 R7 y3 u: A' p- z* f8 F
    1 N* I7 O' K6 N& m6 P4 l4 c2 e        self.ui.setupUi(self)& ?1 H/ }" k, ^5 }3 h" q6 q

    3 K) d& \' \( C3 d, H    def queryWeather(self):7 O2 q- Y) u. x) a1 r
    5 ?9 V  y. a* S) c' A
            cityName = self.ui.comboBox.currentText()
    % o  m: q$ x& I4 \$ o3 R( u( W+ s% L
            cityCode = self.getCode(cityName)9 c* L  i! s6 [3 k: c
    7 M* z& I) L; Z5 ]0 \6 m
            r = requests.get(
    & V+ G1 Y. }( A# [" v( @
    , F; l; |* v. U            "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(% m- {) F% k2 P& H' r

    8 o, Q+ R+ o; o3 V3 V% Q                cityCode))8 k/ z! K8 o& J# ], i

    ! @7 U. P! e% u' I+ f& q  N, ]8 i7 q        if r.status_code == 200:1 {$ f# t$ k4 m# K

    - S. z2 b  I4 M- b2 `- [( F            data = r.json()['lives'][0]$ C) ~# A/ B0 {6 E& W

    6 c* \0 Y9 E& I1 Q9 _            weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    , a+ _' E0 k  b7 ?9 |" }* m0 r8 C) U/ D1 Y( ]/ G7 b( W
                    data['city'],
    ( b8 @; f( m0 b  r" I+ Y
    6 w9 Q0 {8 x0 ~0 w8 k- P                data['weather'],! N8 M- w( ?: z7 ]9 o4 z4 n  C
    , e/ [1 ~: W  L* [; L* a
                    data['temperature'],: r3 G# \. |) u: [' W
    : J1 M8 P( A: U9 s6 r1 p0 _
                    data['winddirection'],# U2 ]6 l) ^3 j" R
    " l0 E+ [, M: t) e$ d: U) C! [+ Q
                    data['windpower'],
    ' z. T* c& }8 L4 |# H2 V8 k4 U( E# y0 Q
                    data['humidity'],
    " }1 J5 [( W3 p; t: f. ]# p* I- v
                    data['reporttime'],
    2 U, K( P/ W+ O7 |# V, F3 v: P1 r3 e( W; A! s5 O
                )2 m) x. C& \$ l

    4 V. Y- a7 ^; S* `) \" V2 X$ @        else:
    / m1 i( N$ D- @1 \
    % l1 T# j" {# z% ]0 r  I2 p% t            weatherMsg = '天气查询失败,请稍后再试!'# T8 d, ^4 W* h& ^8 n2 j5 n

    . H; b0 \4 z, [: G        self.ui.textEdit.setText(weatherMsg)! {$ b- v8 `9 q3 q& ]  V% s

    5 h! l* _2 }( N' G# p7 s. A    def getCode(self, cityName):' a5 H# _2 s2 l8 }7 K

    $ ^: F/ \* y; ~3 d; Y9 g        cityDict = {"北京": "110000",
    6 O- I8 X$ l1 R; o+ {# i% Y5 y( H( n+ {  S$ D9 e) H
                        "苏州": "320500",
    $ _1 `5 P8 @5 f9 {$ q3 t7 j) n
    / S# Q, u, q7 M# B) V                    "上海": "310000"}
    1 b3 l' T- |2 n6 }7 F' {; B- l
    ! N) y$ w7 l- D2 R' ]        **return** cityDict.get(cityName, '101010100')3 G( ?. u1 c: s2 r
      ^; A& L5 u: R+ q. U, n
        def clearText(self):8 Z/ A, Y, E# I, i' o

    % i6 D' ^( ^# A4 V+ O$ h        self.ui.textEdit.clear()
    0 x, u1 `+ G' ^' i
    ; d) p. n7 z/ E( ^if __name__ == '__main__':
    & L* n( {: S9 q, j5 H/ b$ ^( S
    ) \8 h3 B# a; U' y    myapp = QApplication(sys.argv)# l6 P3 g% |  P  c; w& n6 P, m
    % Z& I8 v6 F3 Y8 O, V" \
        myDlg = MainDialog()* W4 u. [  N& k
    & G1 d! }8 C. n7 w* F6 I# i
        myDlg.show()
    7 Z6 M" E, o* h# ?) J, g. D0 _5 b/ R3 l! F0 \* l8 m
        sys.exit(myapp.exec_())
    - Q( _* O8 V1 v( ^
    ! v5 k  j" Y* A$ e/ O运行demo.py并执行查询后的效果:
    7 @: c7 u2 [. K+ i
    9 I$ D  M5 z9 E
    5 q; H  n  A& N; M/ a! z  ^! t0 `( Q+ v# e8 W
    4、将代码打包成exe文件
    ; r, ~( ^1 v) F5 E& B
    * m7 V$ C: l1 X将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:, G  ^2 Z1 ]' ]9 N

    4 J- O7 `- q( a5 k$ Q- d/ I9 K' K% f2 _6 z6 l& L; p6 o! Y" T9 X& Z: x  O

    , @5 s% M8 `* X& Upy2exe:软件更新已经不活跃,因此也就略过。
    4 r5 A* g  a7 s4 f* v$ {# I/ K4 W  n- \, x2 l) n8 Z9 Q
    pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
      x, e9 _1 i. ]8 a8 y, e
    , X) V$ q7 P8 T' p+ T: s' P5 T  X/ rfbs:基于PyInstaller,使用起来更加方便: `0 I+ o" ?+ _) o7 V8 |6 ?
    / m' ]1 p2 \/ I/ S  y4 r! z- a4 W" Z
    这里选择了fbs来打包。fbs的安装方法:
    3 c9 E; t, f. e" c  \0 O5 ~! n4 D1 Z! o4 E$ g, `! J1 j! Y
    pip install fbs- g* C2 g8 `' w4 q2 p% |4 z7 I' o) u
    使用方法,在命令行中输入:
    ! M, A) u, @6 s0 ?
    9 R3 s- e4 `# ~, a) Dfbs startproject
    7 h4 u; k; M0 ]执行完成后需要输入一些APP的名称等。完成后会生成如下目录:+ L- u7 z% G& M6 y- `8 |

    0 Q9 J) I4 i' L" a
    3 W, }4 f5 e# n) M& Q9 G- L( b, K2 z7 V/ q  Y( |
    将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:
    : z2 k* g) h4 D5 b" w  ~1 L& O+ _. B6 Y
    from fbs_runtime.application_context.PyQt5 import ApplicationContext
    5 R% K" o7 I$ @+ X# c/ w```% B; w4 `* t7 |3 L% h) H) s
    完成后执行:
    2 v! [& J+ V- S' \0 B8 \: ]; C```
    * o- ^9 P* E. b! b- [fbs freeze
    ( C3 W, Q5 I2 V```
    / q( Z8 B6 f4 N  ~即可实现打包。生成的exe可执行文件在\target\MyApp文件下。
    2 N# r# h; R# Y, k; y6 j# s4 l" n5 b
      {/ F& ]0 `6 ?( A' H% r4 t' a1 Z————————————————" H9 W8 j. c. X" E( `
    版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。- M4 B/ ]5 a/ v* L5 U, ?7 }
    原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667: L' @' z$ o. E3 `$ `" H8 Q

    & B; V* v0 [( Q9 T" d
    0 D+ [- h. X+ ~3 |( P  r% E+ H  Q- R6 ~, l: @+ s; {$ 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-6-15 01:27 , Processed in 0.453523 second(s), 51 queries .

    回顶部