QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2218|回复: 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使用指南!
    1 L" q3 f- `# Y4 O7 v1 K4 A' V" c8 T: z
    使用Python开发图形界面的软件其实并不多,相对于GUI界面,可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说,未必不是一个好的工具。
    , M/ v$ C# b; e8 O
    8 Q% z# Q3 T. h# y+ F6 O常见GUI框架6 X4 N3 N! ]8 L: [6 h6 `9 `( `
    6 v$ L) _# s; a* p+ }' D
    PyQt5:Qt是一个跨平台的 C++图形用户界面库。QT一度被诺基亚拥,后出售给芬兰的软件公司Digia Oyj。PyQt5是基于Digia公司Qt5的Python接口,由一组Python模块构成。PyQt5本身拥有超过620个类和6000函数及方法。在可以运行于多个平台,包括:Unix, Windows, and Mac OS。
    8 c, I6 W  \% w$ E7 c. e- \0 X8 R* E/ c! ~9 b5 N" Z
    Pyside6:Pyside是QT公司官方提供的Python包,上一版本为Pyside2,对应的是QT5,最新版命名规则进行了调整,更改为Pyside6,对应的是QT6版本。由于官方出品的比较看好,缺点是发布比较晚,网上的资料没有PyQt5多。& ]  i+ ^1 V2 S

    / j1 d; r9 v% gTkinter:Python内置的GUI框架,使用TCL实现,Python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。2 y! @. {" M1 X; R" ]6 z

    - l1 B9 N- r' q5 ]% l5 l  NPySimpleGUI:PySimpleGUI 是 Tkinter 一层包装。使用 PySimpleGUI 实现自定义 GUI 所需的代码量要比使用 Tkinter 直接编写相同的 GUI 要少得多。- b7 o9 T% f4 F

    5 `- J' z( a. P8 Y! bWxPython:wxPython是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。用得比较广泛,跨平台,C++编写,文档少,用户可能就需要根据编程内容对不同平台中的GUI代码做一些调整。遇到问题不好解决,代码布局控件,不直观。
    + [4 I+ h5 F: \: {1 @/ N
    3 c  m5 T6 k1 m$ e; yWax:基于wxPython ,为克服wxPython的问题而制作的一个包。
    , w. g" `) r2 ]  G1 o7 d/ G9 v4 ~2 g9 N5 f- ]- h
    Kivy:主要针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持(Windows, Linux, Mac OS X, Android and iOS.)使用Python和cython编写,中文支持差,需要自己下载中文库并且制定路径。  `0 X) L( u# D2 f% U

    ) F* ?6 v2 Q+ X  }; yBeeWare:Write once. Deploy everywhere.需要与Kivy配合使用。
    8 H. W  C5 M" i. N0 |- ?1 u$ c* d1 _: ~2 p
    Toga:一个使用Python开发原生APP的GUI工具包。Toga由一个具有共享接口的基础组件库组成,以简化与平台无关的GUI开发。Toga适用于Mac OS、Windows、Linux(GTK)以及Android和iOS等移动平台。
    % d+ I% M$ \+ r# _6 O- u  C( o- e* t. h
    Eel:一个轻量的 Python 库,用于制作简单的类似于 Electron(但是比它更轻量) 的离线 HTML/JS GUI 应用程序,并具有对 Python 功能(capabilities)和库的完全访问权限。
    8 i7 l3 k, y7 D' Q1 v5 m' C1 g1 ]. M
    Flexx:一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出一个应用到独立的 HTML 文档。因为使用纯 Python 开发,所以 Flexx 是跨平台的。只需要有 Python 和浏览器就可以运行。2 r5 y5 E0 p+ {+ N, U6 V

    , {5 H7 U* p4 f  vpywebview是围绕 webview 组件的轻量型跨平台包装器(wrapper),它允许在其自己的本机 GUI 窗口中显示 HTML 内容。它使您可以在桌面应用程序中使用 Web 技术,同时尽最大可能隐藏使用浏览器构建GUI的事实。
    / R# U" B) r' y, M7 {1 {$ Y/ y9 q
    ( |" t% z( ?" j3 kenaml:一种能够让你用最小的努力就可以实现高质量GUI界面的的Python框架,也是一种独特的编程语言。enaml将声明性语言与基于约束的布局系统结合在一起,使用户可以轻松地定义灵活布局的UI。enaml应用程序可以在任何支持Python和Qt的平台上运行。
    3 C( U, P% r/ T- y1 C, U' C- E1 U
    / ]+ O4 s" Z/ w! X+ X8 j个人想法:太多学不完,先学PyQt5,原因是资料多,学有余力再学pyside6,最后看下PySimpleGUI,看能否解决一些简单问题。; e/ N  ^( [( x) L: }+ e4 @# E

    7 C0 B! _" l8 j* w9 bPyQt5简介9 h- I, E0 f4 h3 u& @. g! f
    9 V7 n$ ^! F! R9 ^
    PyQt是Qt框架的Python语言实现,由Riverbank Computing开发,是最强大的GUI库之一。PyQt提供了一个设计良好的窗口控件集合,每一个PyQt控件都对应一个Qt控件,因此PyQt的API接口与Qt的API接口很接近,但PyQt不再使用QMake系统和Q_OBJECT宏。0 h4 }1 W9 z5 ~3 `

    ( v" j3 A( O, a8 S/ ]2 }* VPyQt5提供GPL版和商业版证书,自由开发者可以使用免费的GPL许可,如果需要将PyQt用于商业应用,则必须购买商业许可。% Q8 o; _/ ^! Q" A# f

    ! ]2 J2 S0 O, U) ?& t+ S& `1 }PyQt5特性如下:* k0 C0 t( w9 \8 v/ }7 K

    # f1 w; ^/ e; m( _3 J, M基于高性能的Qt的GUI控件集。% b% D# U$ b9 _$ M! M

    2 K* c0 [( w; a0 C8 Q3 q3 J能够跨平台运行在Linux、Window和Mac OS系统上。' b: w1 }8 i7 p; e; s" [: v7 e1 a
    8 d5 u  h% o4 C
    使用信号槽机制进行通信。
    , g! F3 m1 c" v6 q  w) O/ o8 R- q8 j! A9 a& l+ Y" k
    对Qt库进行完全封装。. a: J- m" T2 b$ J, B
    ' U5 C* |& h1 q, {) ]2 e1 _
    可以使用成熟的IDE进行界面设计,并自动生成可执行的Python代码。3 }; _3 E  ~. W

      {& g/ D) R- C' e( A提供一整套种类齐全的窗口控件。) H' T) v, q: |  \9 i, I

    0 I: J$ D* x9 D* PPyQt5是由一系列Python模块组成,有超过620个类,6000个函数和方法,主要模块如下:& x+ m1 J" B/ a% c7 K5 M
    & x% g& y" u: d
    QtCore:包含了核心的非 GUI 的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime 类文件、进程与线程一起使用。" `; H2 N# ~+ k2 I3 _1 i
    , |$ ~+ K6 Z& x' f
    QtGui:包含了窗口系统、事件处理、2D 图像、基本绘画、字体和文字类。" a, s# r) y- V  e6 D0 Z# c
    - e. B, r0 g/ v' g* D- z/ G6 D/ |' y
    QtWidgets:包含了一系列创建桌面应用的 UI 元素。
    9 p" K/ u; S4 b' f! R  U) N/ s% y! f+ p9 L5 f& E
    QtMultimedia:包含了处理多媒体的内容和调用摄像头 API 的类。
    ' p1 ^1 D* i% O9 ~
    / u5 y7 m8 w" @( x  D9 bQtBluetooth:包含了查找和连接蓝牙的类。& R) S3 L/ J- k( {

      d1 v+ {, L+ y* ]5 D" D0 Y) DQtNetwork:包含了网络编程的类,这些工具能让 TCP/IP 和 UDP 开发变得更加方便和可靠。; @0 Z7 t; }1 m* d! P6 X
    8 Z4 r1 Z, r8 x" Y! S* g1 [
    QtPositioning:包含了定位的类,可以使用卫星、WiFi 甚至文本。7 p5 i" j& U. o
    ! F! ^: Q9 h8 R7 u( K6 Q
    Enginio:包含了通过客户端进入和管理 Qt Cloud 的类。
    ) A+ o" \1 X. x- s8 H+ V' w4 p
    / |4 k$ D+ N2 Q! k- @# rQtWebSockets:包含了 WebSocket 协议的类。/ e) J) @& O" W. P' p  f2 b3 ~

    : j+ Z9 |6 @( p; U. m3 VQtWebKit:包含了一个基 WebKit2 的 web 浏览器。
    6 h# n  u+ G* T! q4 ]# a3 N0 ]0 [- w. M+ Z
    QtWebKitWidgets:包含了基于 QtWidgets 的 WebKit1 的类。, U% o) V4 }4 h8 D" _- a, C

    & x7 [7 M3 l8 |  f4 y; XQtXml:包含了处理 xml 的类,提供了 SAX 和 DOM API 的工具。8 N. o- T; G0 o+ b

    3 n2 E  T0 j2 K: S& Y9 VQtSvg:提供了显示 SVG 内容的类,Scalable Vector Graphics (SVG) 是一种是一种基于可扩展标记语言 (XML),用于描述二维矢量图形的图形格式(这句话来自于维基百科)。8 _1 n, V0 t) P
    5 t8 |5 o) g$ ]! L2 q3 Q$ s
    QtSql:提供了处理数据库的工具。: E5 a  c4 W6 o
      W! U7 v+ j; R# b1 `
    QtTest:提供了测试 PyQt5 应用的工具。3 O! |+ c# T% O; I7 c# ^

    / ]5 P* u: W4 DPyQt5的安装
    - m6 p, W% \) j' E3 v) ?/ Z4 W3 `8 \$ M8 R1 m$ e
    由于后期要使用fbs进行打包,fbs对Python 3.7以后的版本可能存在兼容问题,所以我选择了Python 3.6.8进行了整个环境的搭建。主要内容为:Python + PyCharm + PyQt5 2 h9 ^8 |9 D" l/ v) j
    9 g8 Y" O; j1 @/ y4 F
    安装PyQt5
    ' L, j6 H; B+ K" k3 ]# [+ E7 b8 b3 `' e, [) ^
    pip install pyqt5: F, l+ C1 E/ X; g( C

      ?5 X- M) k+ M4 w, e* jpip install pyqt5-tools
    9 }2 h% s9 Y' C其中pyqt5-tools为Qt Designer拖拽式的界面设计工具。安装过程中可能会报如下错误:
    1 s% S( H  Z. o- u4 ^  F0 }
    : _! e3 h. L" y: u" mqt5-tools 5.15.2.1.2 has requirement click~=7.0, but you'll have click 8.0.1 which is incompatible.& z2 D" n& u* o
    解决方案:4 A7 }  z8 o; f& j
      ^" ?" o" v0 e; O8 O! x
    pip install click~=7.0* c: g5 _0 ^5 P3 L& g2 _5 N6 i+ [% H: `
    Qt Designer的配置5 V0 U* J# K) V  s& n  l! u, a

    6 s5 p6 X  u3 LQt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计。5 f: c( ^& Z, Z
    8 x; s9 D6 F) z

    ' y* V5 a% e2 M4 S/ h3 y5 p$ k1 C1 W) P+ h/ Q' ?
    整个画面的构成:, D" q6 \$ r# `5 b
    2 a/ r! P% k4 Z" C
    左侧的“Widget Box”就是各种可以自由拖动的组件
      ]# J. B+ |5 y7 ]. U
    - v. ^" t/ D# B中间的“MainWindow – untitled”窗体就是画布. y& d3 H' k) A4 M4 d* o& p8 L. p4 e+ [
    # h7 ^# C( s3 [* b7 l: U( @
    右上方的”Object Inspector”可以查看当前ui的结构; S" p4 l# }4 B' B
    2 R, y% |( _# o  V
    右侧中部的”Property Editor”可以设置当前选中组件的属性
    * w0 s6 O$ t9 P3 m- U4 |4 v
    : o5 _' V, e  t  \# ~9 q右下方的”Resource Browser”可以添加各种素材,比如图片,背景等等5 C; }! t3 [" \7 r7 N' Y! {' K

    5 z. ]7 f3 ]8 N最终生成.ui文件(实质上是XML格式的文件),可直接使用,也可以通过pyuic5工具转换成.py文件。
    6 Z) G$ n- h2 `- ~" ?, O" b# |& o4 e$ W* F, \  U% f
    QtDisigner配置" K4 M4 c& k" @6 h: `/ U: k
    ' o5 q7 M' Y7 c3 ]
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:
    ) |% j5 I5 a; I3 H: b5 B* m) Z3 p
    Name: QtDisigner8 ^6 ~. z8 c  e) n
    ; N7 a# v# v! s) m
    Program : D:\Program Files\Python36\Lib\site-packages\qt5_applications\Qt\bin\designer.exe # 请根据实际修改
    - ^2 _: y& C5 z0 \" L) }. ]+ L- R# y
    Working directory: $FileDir$
      ~9 O& _* J3 [4 |) U# P9 _6 }( C- tPyUIC配置
    + Y0 k7 o5 ?6 S/ [& a1 j. J4 ~6 z
    PyUIC主要是把Qt Designer生成的.ui文件换成.py文件。1 p0 [' G7 U- ]) b5 k) R
    / B. V* i) l% L; M
    在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:, |. |' J& Q- X/ x
    " D/ u+ J! O, a* Z" A: ~
    Name: PyUIC% o0 w* h/ k! ?. F' S  y4 e9 ?
    - C- R2 b) k8 p/ a" N! q; R
    Program : D:\Program Files\Python36\python.exe # 当前Python目录,请根据实际修改
    4 I6 Z+ a; p' z8 Q3 g2 H
    8 s: x3 O5 q3 ~- ~- NArguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
    ( G& H) J. v0 ?0 u, U; E" L
    8 B5 k" V9 Z% G# J  u2 NWorking directory: $FileDir$8 N- S9 v  S% E$ v) |, J1 }
    PyRCC配置4 Y; D/ J7 a3 f- t! k3 \+ T

    1 v& Y3 v$ M7 W! nPyRCC主要是把编写的.qrc资源文件换成.py文件。在Pycharm中,依次打开 File – Settings – Tools – External Tools,点击 + Create Tool,配置如下:9 n1 O4 e& G" A& ?. V# T; A% j3 D

      H1 I6 q. I' Q5 g" WName: PyRCC
    ) Z- Z' w6 u) \7 Q2 q% u8 N
    ! y: ?+ L  D* J& N9 F( qProgram: D:\Program Files\Python36\pyrcc5.exe # 当前rcc工具目录,请根据实际修改, x% I) z) e  A$ d. h4 s

    ( T' m/ h) b, B( T/ U5 [" c' j7 fArguments: $FileName$ -o $FileNameWithoutExtension$_rc.py& p4 S9 I! n9 d2 G2 T+ g

    , m. b3 u6 |% Q* S! e/ s' E. l/ KWorking directory: $FileDir$
    ) f5 }& \" ?2 R2 Q- U8 s' CPyQt5使用示例
    ( l3 Z/ G" B; S# v# F! R  }
    & d# u! R+ j) x2 j; G1 U创建一个空白的界面:
    ) n/ o9 G# j) c" a# ?7 W6 q: p( w* [  A+ a( s/ y: S7 x, L' |( z
    import sys/ ]( q# f/ c& T
    / w. D2 a: M* K
    from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
    / a8 Z2 w& Y  J
    + a! w: D; A9 t6 u% e0 napp = QApplication(sys.argv)
    7 ~5 W1 U) @7 V8 b, O
    - b& N. M0 t4 h' z0 t: J: {win = QMainWindow()
    : Q* n' j4 [8 I0 z
    ' i6 g1 f) T" v: B7 V' G$ vwin.setGeometry(400, 400, 400, 300)6 x9 l( h3 v7 Q# u  ?
    / s/ ~6 j1 A! g* g: v( [$ O* E
    win.setWindowTitle("Pyqt5 Tutorial")' `3 P$ _/ }7 T# b  k
    - w5 b( R8 Z6 z$ x
    win.show()
    " s+ Z8 R3 ]6 i# Y0 }! t. l* Q- X3 {4 f: C
    sys.exit(app.exec_())
    1 J3 {* K' _$ ]0 ?6 F. t( z6 ?, L) {6 {7 W' D: D' ~( X

    , N" u8 i3 e7 r1 ~+ K( Q" E
    ; g0 v; d$ ^6 m5 Y- A其中:$ O. r  W3 x7 Y" r3 Y7 M1 _% ?- H) ?

    ; e" A& {% x. t/ m4 }Qapplication():每个GUI都必须包含一个Qapplication,argv表示获取命令行参数,如果不用获取,则可以使用[]代替。" B6 o1 ~/ E+ X: G5 v0 ^

    . Q6 [  G# W7 p' BQMainWindow():类似一个容器(窗口)用来包含按钮、文本、输入框等widgets。arg标识可以获取命令行执行时的参数。' _* S$ i$ w" u: c; }
    - `8 ?9 \8 H0 i, M0 l
    SetGeometry是用来定义 QMainWindow() 窗口的尺寸, 语法:setGeometry(x, y, width, height ),其中x,y为屏幕上的坐标点。
    0 k# s, r- j0 i/ H
    1 r" f+ ~( k8 d. m% h9 P3 Tshow():用来显示窗口% `5 x- Y) S# e! l9 z

    $ {8 X% D% q8 ^3 \6 gexit(app.exec_()):设置窗口一直运行指导使用关闭按钮进行关闭* M" u5 ^% f+ X" U7 Q$ J
    ; V1 z3 P# @1 N# A
    PyQt5支持的常见Widgets有:! \. N" _' M, C6 v0 e# P
    ! x* L3 C' R3 s' c' g/ i) s* S

    2 x9 B& f0 _/ Y
      i) ~* G: I0 c  q' s从上到下,从左到右依次为:Qlabel、QcomboBox、QcheckBox、QradioButton、QpushButton、QtableWidget、QlineEdit、Qslider、QProgressBar. N6 ?* \, f& e2 h1 l2 J
      u' f; D7 p/ l* A! I0 e
    对于使用Pyqt5设置文本内容,我们使用Qlabel:* K0 d1 V$ o+ c

    8 ]* B' R/ K2 J0 ^3 dimport sys
    1 y2 r4 A5 z. Y0 h
    / Y2 y- ]' W5 Q- x+ U+ C% _# Mfrom PyQt5.QtWidgets import QApplication, QMainWindow, QLabel2 w9 o1 E$ Y* _% I  [, D
    . |4 w4 i6 {: Z$ ~3 k
    app = QApplication(sys.argv)
    . B( n* e. V) x& v
    ( D" z/ o* z" e( Gwin = QMainWindow()! K% @: c' ^$ l0 p+ y8 Z- p

    & x3 w6 \2 ]) H, k1 _win.setGeometry(400, 400, 400, 300)2 t( ?3 d$ T3 ~1 m( F! Z' ?/ Q
    ; ^0 E  h0 S; a6 y. n
    win.setWindowTitle("Pyqt5 Tutorial")3 F3 @# Q4 o. [

    + W) ^. M( Q1 W* N, C1 r\# Label Text0 m  z& ]2 x$ _; Q) Q
    # N1 x7 d) i! `) [+ i7 ]' A, B
    label = QLabel(win), y8 N, w7 h7 y) J2 f4 R- ~

    & B) e" @& |" G) S2 n! V) x" llabel.resize(200, 100)+ `, \8 i: G2 L( M1 g
    # t6 l: Z8 u, y: `: ~
    label.setText("Hi this is Pyqt5")
      \/ ?+ H2 _6 Z: e5 y
    ( i2 L; e9 L4 `+ mlabel.move(100, 100)
    + m% s, C! t. z% F1 q) F6 S; M8 P5 p
    win.show()+ C; J; G! r, K" D2 ~
    , x' Z% d% }- J& F
    sys.exit(app.exec_())
    + z/ x% K8 g3 Y8 ]* \1 h
    - `" s( Z+ ^- {9 q$ C& B) s# }2 S% H# t2 q* R2 S- _

    ( O8 v3 b/ }5 t0 o8 m2 v按钮与事件:% j8 v9 ]6 Q2 h! l2 P

    " P1 |) i) l/ z: K* @6 nimport sys
    / P" o. |' S2 _& U
    2 H* j6 q& N, s3 X; ~# Zfrom PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
    ( }6 M; P! W" c
      y& |% X: S% M( U% ~, K4 M+ [& L$ Ndef click():& V3 M. f% P+ W

    5 Z; M! Z( t6 H% ?    print("Hy Button is clicked!")
    7 [( r5 G$ \4 _$ `/ y& w
    ' S$ w9 x$ d& v9 l" happ = QApplication(sys.argv)+ N' p2 W, C- r0 B* g
    $ r- y' e+ t' B! h& l
    win = QMainWindow()
    0 d: h# m) h5 e8 L6 m$ R5 d4 y3 r, y) T1 T
    win.setGeometry(400, 400, 400, 300)
    - c% Q7 y2 Z( `3 f( B9 @) u& ?+ T" h  s4 F( ~% X: u' q, h% n
    win.setWindowTitle("Pyqt5 Tutorial"): D( X3 B. o# l# A% q- ?: ?: d

    9 t  n6 ?, B& {\# Button
    0 B4 s5 L5 @# a6 u8 |3 M0 M& \% M. ]. }' ]9 B, E* L# t" C
    button = QPushButton(win)% H7 W+ n/ D9 @: z! e

      F* x+ B8 a3 K. o: nbutton.resize(200, 100)
    2 V1 t! r9 l$ i$ m
    7 `0 d! C6 }# |button.setText("Hi! Click Me")1 `' g+ n- a5 Y# D. G, f

    1 h! T+ g: B1 d* T2 y7 H) j  @button.move(100, 100)
    ; O3 o4 Q5 k9 c& \( H' K: u1 ~
    ' S/ }: G4 g* _button.clicked.connect(click)* t/ V+ Q2 l* x# M

    * a& h  {. d2 H) _win.show()
    + m7 o# B7 V% v( d0 r
    2 P6 L: E3 c6 n0 bsys.exit(app.exec_())9 K5 M2 r6 |4 g6 d7 B
    4 b6 ^# g! q9 g/ `6 I. H% g

    # x7 M9 }2 m, c! v9 M- n2 z. ?% S! b3 j+ Q
    button.clicked.connect() 在按钮点击后执行特定的事件。
    ) t( O7 c& T7 T% B: p' k% T. V- w' t9 d
    PyQt5实战2 m+ D" m% u1 x4 |

    # h$ c9 ]: r' J& d) W5 Y! Y9 A实战项目:简易的天气查询软件
    3 k' Y- M4 D7 \6 A2 Z* G
    4 Q$ K' q: o1 [3 {6 B9 K5 i, ^1、使用Qt Designer设计一个界面
    # `$ P3 Z7 @2 g" W8 ]- `1 y/ [
    . s1 v& R1 b: ^6 b0 f+ }6 A6 ~/ e- {
    - l+ ?7 k1 s- h' @" y0 @+ W3 V; n* E: Z
    用到的控件有Button, GroupBox, Label,ComboBox,TextEdit,同时定义了两个按钮queryBtn及clearBtn,分别用来查询及清空天气数据。我们需要绑定槽函数,方法如下:/ M$ A' g1 `/ y1 q4 A( F# W/ k

    / }! r; ]1 H6 Y& Y3 {在Qt Designer右下角选择 信号/槽编辑器,点击+号新增1 @6 X# K) r  l9 d: _
    ! p- s& c" M9 P& l  K1 q
    分别选择queryBtn及clearBtn,选择信号 clicked(), 接收者 Dialog 及槽 accept(),(槽函数这里不知道如何定义,后期在代码里再进行修改)
    % Q4 s2 R9 n+ V0 A  e2 t- i" C( f4 t9 C4 i4 N( O7 H$ j
    以上完成后保存为Weather.ui文件。
    . g) |! F+ }! }/ b: u8 m: c' K! Q& c- J' U0 n  u" t
    2、转换.ui文件为.py文件5 m% w( |3 I' f& s

    ( {0 H5 F- ?% D! `) w3 t* GPyQt5支持直接使用.ui文件:
    - U1 }; h0 y- Z8 G5 i4 V! Y8 q2 q  u+ s
    import sys# q+ E& D5 n$ h! k& g2 L2 u1 |& K

    ' z1 s) [0 Q2 \$ J" s# ~  Jfrom PyQt5 import QtWidgets, uic
    2 G: I: u* b) D8 Z  h9 R0 g
    ( }4 L' M$ |4 \, X! q* u7 xapp = QtWidgets.QApplication(sys.argv)
    ' w0 b! W8 v$ u6 C' w1 j( q4 f4 l
    window = uic.loadUi("mainwindow.ui")
    3 l2 o* Z  U5 h! {' `6 x& z+ [# L; e+ ^8 `8 S* W
    window.show()
    1 O8 i" c- O6 w  f4 S
    + e2 K5 s% ?8 ]4 napp.exec(); |' u5 z; h+ d, Q$ S& N
    但是为了更好的自定义及修改上面的槽函数,可以使用External Tools – PyUIC,即可生成Weather.py,实际运行命令如下:; [6 d) F' ?9 Z( B* J4 c1 A2 M: g
    - [: p- h" J6 A& Q* \! |
    D:\Program Files\Python36\python.exe -m PyQt5.uic.pyuic Weather.ui -o Weather.py
    5 W% Q+ r5 e0 W9 F  ~, |其中,我们需要把两个按钮绑定的槽函数:
    0 D5 _) o! E5 ]& T, H7 n" s( T5 B  E6 Q2 z; k
    \# self.queryBtn.clicked.connect(Dialog.accept)
    % |* g  h( {6 O* n% t' |( L& D, s/ x/ [( s( [4 t2 N: t: [7 E
    \# self.clearBtn.clicked.connect(Dialog.accept)' u. U% d/ `' m6 ?

    , V& P9 e/ K0 ]\# 修改为:( z& D! j% z4 S

    2 c: U6 X# j# D* ^' Iself.queryBtn.clicked.connect(Dialog.queryWeather)5 l& a3 v" c1 C# n) {3 X8 i# Y2 `
    9 u+ A5 V, w1 A1 R) @4 Q- {( h
    self.clearBtn.clicked.connect(Dialog.clearText)  H; L  J1 t1 }3 O* p3 L4 t7 l
    最终的Weather.py内容如下:
    # U$ v; i' c3 |* p- q$ D% N; v# q" j& p
    \# -*- coding: utf-8 -*-* i2 `* y: [; x, U* x0 }
    & _5 V! k0 U3 o) A
    \# Form implementation generated from reading ui file 'Weather.ui'
    5 K( |8 ]& M8 t% }! B3 b4 T' b+ h3 Z! s: B
    \#
    0 Y" |6 e5 A2 g( i3 m( k2 _1 s: N. x, E% H5 |3 b( _4 z0 C0 {# J
    \# Created by: PyQt5 UI code generator 5.15.4; S' T& {' z+ E: ^4 J! W

    ( w9 q1 k& K$ `7 T\#+ }' a: x9 q' ?# z; k0 e. w
    1 G  `- }9 n8 K( m" Q
    \# WARNING: Any manual changes made to this file will be lost when pyuic5 is0 G8 d3 O: ?5 p% S

    ! Q* h9 J; I0 w( r\# run again.  Do not edit this file unless you know what you are doing.
    ! B5 R$ l4 N: f0 Q
    % G- y7 x! x" `2 R! K3 F& pfrom PyQt5 import QtCore, QtGui, QtWidgets
    / K& J  e; R9 `) q' @9 Q9 [# d4 _% j* h/ i9 E: d, m
    class Ui_Dialog(object):6 Z* C' r) C9 {& f  a1 b- ?$ [: a
    7 a* o& Y- B, P  d! h
        def setupUi(self, Dialog):9 _# I+ X7 k, v+ F+ W$ K) V( @" N

    * y, |' r1 [+ ^, l$ v. F* n* o* o2 a- s        Dialog.setObjectName("Dialog")$ x4 a4 F& D9 x, z5 v: W

    7 D+ d1 O% K  o8 f! L' r        Dialog.resize(600, 600)( B+ R( A3 m( g1 m
    & X) \+ z( c2 R8 K3 T2 |
            self.groupBox = QtWidgets.QGroupBox(Dialog)
    ! N; I! [- d% S, C0 [* u
    0 O# Z/ C2 R5 h1 l. N        self.groupBox.setGeometry(QtCore.QRect(30, 20, 551, 511))
    3 l$ t2 p0 Q4 E/ ]( w
    9 ~; M, J' G) b1 j        self.groupBox.setObjectName("groupBox")) G9 H5 }  v7 c2 O

    4 v1 p  f6 Q/ d5 j  T        self.label_2 = QtWidgets.QLabel(self.groupBox)
    % h( v! d3 r4 I# h+ i& \
    ! ^8 n; H/ K7 r        self.label_2.setGeometry(QtCore.QRect(20, 30, 31, 16))
    3 b" q" M$ @: I) I# O: y' N' [% T" x- H7 l: A
            self.label_2.setObjectName("label_2")
    5 T% ]0 o5 F( n4 R* h' w5 J# X6 ~, R% M8 b  e
            self.comboBox = QtWidgets.QComboBox(self.groupBox)8 r+ T% l% N: |" a" `$ D4 B

    9 u1 C/ [% L* \7 R6 m        self.comboBox.setGeometry(QtCore.QRect(70, 30, 87, 22)), p& H2 i& X( P' D! N

    4 {) v5 p% o+ Z9 _# C  p4 ~8 H        self.comboBox.setObjectName("comboBox")
    0 }7 @$ B; X6 |+ j$ x+ s) q* B5 Z) ^/ c/ w
            self.comboBox.addItem("")
    . J0 E8 S3 ^0 p: D( r- q7 f6 s. E. C! z! F: g4 p9 ?3 F
            self.comboBox.addItem("")
    5 A* y* u% m5 }& q
    % A% y9 Q& q5 o        self.comboBox.addItem("")( e0 b2 h7 r# B: N
    5 Z* D3 B( b5 K% b, m/ |: ~
            self.textEdit = QtWidgets.QTextEdit(self.groupBox)/ w6 |. K. |: J/ D

    6 P$ N4 f/ Y8 B0 a% I' n        self.textEdit.setGeometry(QtCore.QRect(20, 70, 491, 411))# z+ j5 i" M) a5 B4 f

    9 j5 M: I9 T; b- H1 K* r$ p        self.textEdit.setObjectName("textEdit")
    4 r/ ?8 o7 q, }8 f- I8 K
    ! H& }: r- T6 S# C$ ~        self.queryBtn = QtWidgets.QPushButton(Dialog)4 l$ [7 d8 ~1 K

    2 y# X' p9 n) n) M2 |0 G        self.queryBtn.setGeometry(QtCore.QRect(490, 560, 93, 28))
    - l: `) }+ L3 J" b# z* Q' [& C, e0 l) `. I8 R% w1 v1 `2 H
            self.queryBtn.setObjectName("queryBtn")
    + P3 L/ J5 T2 y0 G* N; h4 n  ^6 N% _, W6 g
            self.clearBtn = QtWidgets.QPushButton(Dialog)4 W: F; A. e' \0 ~* s( O

    ! Q7 u$ @7 i7 X( _% h9 m/ i  S        self.clearBtn.setGeometry(QtCore.QRect(30, 560, 93, 28))
    ! S7 o9 _+ S% B! e6 h& t' y) X& m: Z, \: e! O0 |/ h0 J
            self.clearBtn.setObjectName("clearBtn")
    , f. [3 v/ R1 ]2 A. H; J6 {5 ^/ l3 J6 I( ?) q. V
            self.retranslateUi(Dialog)
    $ B: z" N- ?" D1 z4 O# w$ ^) o3 Q/ \* B' k2 l! W) b
            self.clearBtn.clicked.connect(Dialog.clearText)! t% R, ]/ i( l1 J
    + U" `4 |1 _/ e7 x8 ^3 ^
            self.queryBtn.clicked.connect(Dialog.queryWeather)
    / i/ s) U2 p' c% J2 O
    5 U+ f. V; L/ P( O( X        QtCore.QMetaObject.connectSlotsByName(Dialog)
    ' Q3 r  S& n; n& s6 g0 B. q
    1 v; o" E9 r/ n    def retranslateUi(self, Dialog):
    ' ^" I) o: ~5 \. Z7 A; E4 l
    1 y( Q' O' ?7 u4 n' m& G        _translate = QtCore.QCoreApplication.translate
    1 O! I& n5 @4 z5 P6 H; z+ ~( n3 T. [3 A8 Y& r$ X
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
    ( W, w0 [/ k5 o
    0 P/ y% y: T5 S# I        self.groupBox.setTitle(_translate("Dialog", "城市天气预报"))
    5 @' s% z- j2 ^. f
    * \3 |9 G4 D, I7 ~9 s+ K8 W. R7 q1 y; ^        self.label_2.setText(_translate("Dialog", "城市"))' r/ L0 Z1 U& l- ]3 R! [

    6 v6 K( s: B- C: M' G        self.comboBox.setItemText(0, _translate("Dialog", "北京"))
    7 M. N4 J5 e; i, t# v4 `& L, U! ?9 i4 y/ G
            self.comboBox.setItemText(1, _translate("Dialog", "苏州"))% W0 u9 r+ y8 b. R  I3 l' T; G

    1 R9 f9 ?% F6 G8 R        self.comboBox.setItemText(2, _translate("Dialog", "上海"))
    6 `2 P5 u  h% g- Z) z, Q
    9 [" [8 ]% l7 ?) U) Q" r3 v5 K        self.queryBtn.setText(_translate("Dialog", "查询"))8 l3 `( c4 b4 H" [+ |3 H! \
    % W+ N& o4 P; y. v7 Q
            self.clearBtn.setText(_translate("Dialog", "清空"))9 q% ~; [+ u2 s* a" o# t  C% d8 d
    * N4 Q' X, q3 L; P" P( j/ B# V$ t
    3、调用MainDialog
    # N3 C$ X5 z8 L  Y+ ^7 F* }- |- f; k* ^0 p
    在MainDialog中调用界面类Ui_Dialog,然后在其中中添加查询天气的业务逻辑代码,这样就做到了界面显示和业务逻辑的分离。新增demo.py文件, 在MainDialog类中定义了两个槽函数queryWeather()和clearText(),以便在界面文件Weather.ui中定义的两个按钮(queryBtn 和clearBtn) 触发clicked 信号与这两个槽函数进行绑定。
    ( f. k1 S2 F) V+ }
    % Z1 X2 ^7 ~; @# D$ i完整代码如下:% d8 H' v( K% ~' \7 ~! H" C
    ) S$ }- W; D5 ^& d/ O3 n# E
    import sys: F, l( R0 X, s9 F4 [: E
    . c) R, h( f2 ?+ B
    import Weather! C7 p7 `0 A2 `/ d; a
    * T& {  m9 @% T" L/ n
    from PyQt5.QtWidgets import QApplication, QDialog
    2 q4 A+ U9 \. m: i& {2 e5 m! z! ~4 E5 G4 H: M# p  i  W) J
    import requests
    . W+ m5 y8 v/ ~4 p5 ~+ \3 q* E! r: S) u
    , Z# G, z; x+ M9 M9 f9 o* z: Wclass MainDialog(QDialog):% V( }7 l& ^+ B, G5 {8 ?3 C
    8 f1 X1 }% _2 T0 O
        def __init__(self, parent=None):2 S$ T8 _) |; @- B% l; d" J

    0 N  E8 x6 |8 `1 ^! {        super(QDialog, self).__init__(parent)' L' @  t+ i9 ]% F4 [2 ~; n6 \

    : a" G' s& d5 [5 H9 I0 h5 \# Z; |        self.ui = Weather.Ui_Dialog(), D, F" n3 h1 H- y4 V! @

    ) X+ ]7 m$ r" J! U        self.ui.setupUi(self)) h. s2 B2 @. B- j  l

    * a/ ^4 j0 x; B0 R, {    def queryWeather(self):; b) c3 s0 k' _4 L* u1 `9 y
    : ~: m0 d& |0 K& L/ v  O" S3 [
            cityName = self.ui.comboBox.currentText()
    ' t$ J, {' M) C. w; K2 x1 S. Q1 r& `3 y+ z
            cityCode = self.getCode(cityName)
    6 `( b' t& a' m% \6 }5 P- c* s1 e. {% Q2 z6 R
            r = requests.get(
    ' Q! o' }" ~6 f: Q1 u7 W  H. b2 e: s6 q. o* T! x
                "https://restapi.amap.com/v3/weather/weatherInfo?key=f4fd5b287b6d7d51a3c60fee24e42002&city={}".format(& S" v: |3 ^! {

    ) D9 e5 x0 A6 y0 o7 S                cityCode))
    . c8 D- N8 `3 K
    * X8 ?) b4 k! L7 O4 h# {& Y2 u        if r.status_code == 200:
    . F) L1 A8 L2 Q3 _
    * c! j# \& t, g            data = r.json()['lives'][0]/ |& s& }& I& v$ K2 k: }: {8 j) b4 e
    + ~4 Z5 w) S0 H1 Z# O8 O
                weatherMsg = '城市:{}\n天气:{}\n温度:{}\n风向:{}\n风力:{}\n湿度:{}\n发布时间:{}\n'.format(
    : U6 S$ w5 @5 m6 c$ U* w, A6 g$ J) y" R/ a  e9 _
                    data['city'],
    & R3 g; K4 K# N0 d6 Z+ M; p% Z- C4 }8 F4 s0 q+ c
                    data['weather'],
    9 W3 \6 r9 u2 i# D; Q! y
    ; [- I0 K0 x1 ~                data['temperature'],
    0 d3 ~. S* n) `/ _
    . a8 l, H% E, p% M# ?, ^                data['winddirection'],, i+ @- d, M- s( V

    * {+ q: I2 L+ p8 l9 ~                data['windpower'],4 c. ]' i5 q  ]  U5 f" d: z
    - q  }. Y6 q+ L$ W6 L2 X
                    data['humidity'],: E0 z9 a! s0 w) u; S+ C

    0 Z( ]/ r8 E+ e                data['reporttime'],
    6 _* D) f; m/ w& p% I* L4 c6 C
    1 A% T  K( A9 Z/ X# A7 B            )
    % Y1 i4 b/ M: S# z& P2 a3 a
    6 M3 N2 m/ N2 b8 I        else:
    % m( O" e( x. s1 d6 v- h
    ( T4 p6 T. K+ B7 t9 z! o            weatherMsg = '天气查询失败,请稍后再试!'( K5 k3 u0 h  ?7 V$ q7 W

    9 V2 D3 N( O+ U        self.ui.textEdit.setText(weatherMsg)
    ' }: a$ r% o6 C. ?( e
    7 r2 v$ }2 V1 m3 @3 o) g    def getCode(self, cityName):
    * L# O8 `5 N$ N7 C0 J
    1 z  A* A; X7 u, Q- ^1 Q. ~        cityDict = {"北京": "110000",
    : }7 v, k5 O5 z. s' ?. X/ K3 D) C
    7 N6 s3 F  N$ X                    "苏州": "320500",
    1 o/ q. |3 R$ N1 R
    7 L2 V) Q& K+ P% M8 e' m                    "上海": "310000"}
    3 R- P1 R# o( y# d2 J) i* F% i9 ^, Z! h. [; D/ A
            **return** cityDict.get(cityName, '101010100')+ q8 a5 D( h$ |. W8 F% V  x7 M2 v

    + t# G2 o8 X4 H    def clearText(self):
    7 H7 A/ z3 s2 |- T# D5 a" U, G7 r7 p
    ) b' v2 n9 h, e! G& `/ z        self.ui.textEdit.clear()
    ' i" {2 @* }; x( r! v% x- @3 N  y# D; Q* J
    if __name__ == '__main__':. W. U! a7 I, u6 B5 h

    $ t8 `2 ?3 |5 P+ n- }4 \' y. t% M    myapp = QApplication(sys.argv): P, f2 A9 R/ L; v7 |& ]! O+ _

    $ p0 X; q* |! ~' e2 q    myDlg = MainDialog()
    0 B/ U3 u& P# d: J, u7 m6 l# A4 v) G: D' _
        myDlg.show()
    * U; F6 m/ x& v& Z& ^
    ; W; X9 K- J* g7 W    sys.exit(myapp.exec_())$ Y8 E9 K' c4 v- {( l( Y
    - n2 W% K: C1 \1 h+ s- ]
    运行demo.py并执行查询后的效果:
    ) g, i) F" O' G4 _- b. O+ u, L% j' W- U7 n4 X. f4 X
    ! C& G  J8 ~3 L4 W

    * R+ k9 [( h/ S7 p* g3 h8 w4、将代码打包成exe文件( E- I. `+ X# g) H7 v' f2 l& J8 |  S
    : L& _& t* }; ~* i; v. S
    将.py文件打包成可执行的exe在Python中称为freezing,常用的工具有:PyInstaller, py2exe, cx_Freeze, bbfreze, py2app等。功能对比:2 W4 ?( r8 u4 j1 g! j
    / P( L7 {5 Y' ?6 \

    + Z6 Z4 G$ P1 |# Z1 U! N( q1 ?- S: W0 w4 X9 ~
    py2exe:软件更新已经不活跃,因此也就略过。
    # e( Y9 ^6 R1 |' X, F- l3 u/ U) k, W; l  y4 P
    pyinstaller:明确支持win8、win10、理论上支持win7,,支持apple Macos, linux。pyinsaller可以打包成文件夹形式内含exe入口执行文件的形式,也可以是一个单独的exe文件。
    ) I: w$ y2 [7 m' {6 f/ j9 V5 i" t/ j. T3 o- K: m8 \0 p) S' |
    fbs:基于PyInstaller,使用起来更加方便) Y2 ~5 A9 M- T  _0 S4 }' W1 |3 a
      Z7 [% E8 [1 F1 z2 q
    这里选择了fbs来打包。fbs的安装方法:  x6 S: l; @3 y$ d' g* V
    / k! P2 P; g/ U  r# X0 }
    pip install fbs
    $ N4 o, g  A$ J/ r- \5 P% q使用方法,在命令行中输入:
    2 G2 {, }& g) _/ O* @; m  M; D
    2 J0 [/ f" Y. ]& o8 W; ~! Tfbs startproject% R- `$ _# q9 G" [& u
    执行完成后需要输入一些APP的名称等。完成后会生成如下目录:1 u! Z9 @1 B2 c% O* x

    3 _4 g5 x+ ?# w/ }% D: O" A* S$ k7 R) A9 T" Q

    " j6 M6 U8 x, A将刚才编写的PyQt5的代码(demo.py和Weather.py)拖到src/main/python文件夹下,删除原有的main.py,并将demo.py修改为main.py。然后打开 main.py,在文件头部添加如下代码:
    7 U; a4 T( P; _/ d1 W5 n* H7 w' e0 g$ ^; i7 R2 e
    from fbs_runtime.application_context.PyQt5 import ApplicationContext4 f7 H! Q  ~" v/ ^1 h% O( m
    ```7 Y8 r$ r& l1 f7 m, J' F
    完成后执行:2 @1 c; ~* A+ f9 c7 @  W  D# H
    ```
    ! F, ?; `4 D) t! o/ Efbs freeze3 r/ M( n* B1 U  g
    ```
    3 Z7 S7 C7 ^) W( x( z) l5 u" ~& Z即可实现打包。生成的exe可执行文件在\target\MyApp文件下。
    9 N1 T  K5 V) ?# t3 _! m$ _9 c7 z% m; {# Y
    ————————————————
    & H7 V( T' I7 M" A1 q& [6 [版权声明:本文为CSDN博主「宋宋讲编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    & |0 Z9 S  v9 u8 M$ n, `8 l4 y+ j原文链接:https://blog.csdn.net/qiqi1220/article/details/126289667
    # I9 b. s. T8 \: L  m6 l, y
    3 `7 W2 B+ @* Y7 `" c6 b& x/ {/ e1 p, T

    0 g9 y. f3 [4 `( ?/ M+ z/ B- L
    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-7-10 09:26 , Processed in 0.352565 second(s), 51 queries .

    回顶部