12月03, 2019

Python 做 UI 超 easy!(3.1)——天气预报小工具

前面我们做了一个简单的视窗应用,已经对 PySimpleGUI 有了大概的 “感觉”,做出来的东西别管多简单吧,起码有点 “产品” 的意思了。

title

其实这个简单的作品,已经具备了一个典型视窗的绝大多数要素:

  • 蓝图,上一节中的 layout,它是一个 成员为 list 的 list,定义了窗口的长相;
  • window;
  • 响应用户事件,那个 event,希望你还记得它;
  • 获得用户输入,当然是上一节里的 values。

event 和 values 只是约定的名称,你当然可以将 window.read() 的返回值解包为其他变量。
约定为 event、values,我们就都明白说的是 read 函数返回值的第一项和第二项。

再罗列一下目前已经实用过的组件:

title

图中有些内容有点多,再罗列一下:

  • Text,显示文本标签;
  • Input,输入框
  • Button,按钮

基于这些简单素材,就足够我们制作一些有相当实用价值的工具了。

一起加油,做个天气预报小工具。

你也可以在线运行本期代码

https://repl.it/@alvendarthy/PySimpleGUIDemo3

绘制蓝图

依照惯例,第一步确定天气预报小程序需要什么信息:

  • 城市(只做国内主要城市),用熟悉的 Input;
  • 一个按钮,点击查询天气;
  • 还需要一个地方展示天气,依然使用 Input,将天气填进去就好。
  • 在两个输入框左侧,还会有两个 Text 作为输入框的标题。

总共 5 个组件,其实都是比较熟悉的组件了,还蛮简单的。

按照自己的审美,绘制一个效果图,你可以用纸笔绘制。希望你可以将图中的组件类型标注出来。

title

参考这个图纸,可以开始完成一部分代码,实现蓝图,并把它显示出来。

如果你用的是 https://repl.it/ 在线编程环境,它不支持中文,所有显示内容必须是英文。

import PySimpleGUI as sg

# 让所有文本居中
sg.SetOptions(text_justification='center') 

layout = [ 
           [ sg.Text("City", size = (20, 1)), sg.Input(key = "-CITY-") ],
           [ sg.Text("Weather", size = (20, 1)), sg.Input(key = "-WEATHER-") ],
           [ sg.Button("Submit")]
         ]

window = sg.Window("Weather App", layout)

event, values = window.read()

print(event, values)

window.close()

注意到 Text 被指定了 size 参数,用一个 tuple 表示组件的大小。size = (20, 1) 表示 20 长,高为 1,单位不详。

点击 run 就会看到界面了, title

在视图窗口中 City 栏输入 “Beijing”,点击 Submit,会在下面的命令行输出:

Submit {'-CITY-': 'Beijing', '-WEATHER-': ''}

不出意外的话,城市名称通过 values["-CITY-"] 就能得到。

获取天气信息

下来的问题就是怎么获得天气预报了,计算机本身是不可能知道天气的,怎么办呢?上网啊!通过互联网可以找到开放的天气预报接口。

什么是接口
不同于面向用户的网址(URL),接口返回的是单纯的数据,而非花花绿绿的网页。这样的 URL 就是接口,面向的是开发人员,而非最终用户。如果你开始接触网络接口,恭喜你已经是开发者的一员了。

我已经为大家找到两个接口可用:

你可以将上面的 URL 在浏览器中打开,数据会被下载为文件,打开会看到:

title

它们就是网络接口返回的数据,不是网页而是单纯的数据,这样的数据格式称为 Json。

将内容复制到在线 json 格式化工具 https://www.json.cn/ 左侧窗口,数据会更易读: title

{
    "data":{
        "yesterday":{
            "date":"2日星期一",
            "high":"高温 4℃",
            "fx":"西南风",
            "low":"低温 -4℃",
            "fl":"<![CDATA[3-4级]]>",
            "type":"晴"
        },
        "city":"北京",
        "forecast":[
            {
                "date":"3日星期二",
                "high":"高温 8℃",
                "fengli":"<![CDATA[<3级]]>",
                "low":"低温 -4℃",
                "fengxiang":"西南风",
                "type":"晴"
            },
            {
                "date":"4日星期三",
                "high":"高温 8℃",
                "fengli":"<![CDATA[<3级]]>",
                "low":"低温 -5℃",
                "fengxiang":"西南风",
                "type":"晴"
            },
            {
                "date":"5日星期四",
                "high":"高温 3℃",
                "fengli":"<![CDATA[<3级]]>",
                "low":"低温 -6℃",
                "fengxiang":"东风",
                "type":"晴"
            },
            {
                "date":"6日星期五",
                "high":"高温 3℃",
                "fengli":"<![CDATA[<3级]]>",
                "low":"低温 -6℃",
                "fengxiang":"西南风",
                "type":"晴"
            },
            {
                "date":"7日星期六",
                "high":"高温 4℃",
                "fengli":"<![CDATA[<3级]]>",
                "low":"低温 -6℃",
                "fengxiang":"东北风",
                "type":"晴"
            }
        ],
        "ganmao":"昼夜温差很大,易发生感冒,请注意适当增减衣服,加强自我防护避免感冒。",
        "wendu":"8"
    },
    "status":1000,
    "desc":"OK"
}

这样清晰多了吧,看起来很像 Python 中的字典是吧!这就是网络接口返回的数据。如果这些数据保存在 ret 变量中,那肯定可以通过 ret["data"]["forecast"][0] 获得明天的天气了!没错,但是需要先借助 json 库将它转换为 Python 字典才行,现在它还是 String。

我们的小程序怎么获得这个网络接口的数据呢?感谢 Python 强大的生态,request 库可以帮助我们,不借助浏览器也能访问网络接口。

总结

根据上面掌握的信息,就有了获取天气的基本思路

  • 用 requests 库请求网络接口;
  • 用 json 库将返回的内容转换为 Python 字典;
  • 访问字典得到天气预报
  • 将天气字符串显示到视窗中的 Input 中,到时候会调用 Input 组件的 update 函数。

做到这一步,已经可以根据图纸实现包含 5 个组件的窗口,我们离成功只有一步之遥了!

下面是 requests 库的文档,可以提前了解基本用法,预习是个好习惯。

http://2.python-requests.org/zh_CN/latest/user/quickstart.html

劳逸结合,不要太累,明天继续咯!

本文链接:http://www.thinkinpython.com/post/PySimpleGUI_3_1.html

-- EOF --