使用python开发天气预报程序(带gui)

大家好啊!我用Tkinter写了一个天气预报小工具,支持34个省级行政区以及港澳台地区天气,覆盖全面。程序打包好放在了公众号,与大家分享一下。

一.准备工作
使用到的第三方模块有:requests、json、lxml、jieba

如果未安装,可使用命令:pip install module_name 的方式进行安装。

二.预览

1.启动
启动以后自动定位所在城市,展示定位城市的天气。
在这里插入图片描述

2.添加城市

在这里插入图片描述

3.展示多个城市天气
添加天气之后能够显示多个城市天气信息。
在这里插入图片描述

三.设计流程
1.获取城市天气信息过程
用此流程图展示定位城市信息到获取城市天气信息过程。
在这里插入图片描述

四.源代码


1.Weather_Tool-v1.0.py
from tkinter import *
from tkinter import ttk
from PIL import Image,ImageTk
from tkinter import messagebox
from Weather_Spider import Weather_Get
from threading import Thread
import datetime
import time

'''
5-1
1.打开首页定位当前位置获取天气    (ip定位+jieba分词+城市号+城市天气) **5.11实现**
2.用户手动选择,查看当前所选城市天气 (Toplevel+Combobox) **已实现**

5-14
1.加入notepad,显示多个城市天气    (notebook Frame)    **已实现**
2.频繁刷新检测(线程计时10秒)   **已实现**
3.用户选择主题    (Menu.add_radiobutton())    **已实现**
4.一个窗口多个Combobox,怎样处理选择事件  **已实现**

5-15
1.右击notebook frame标题出现“关闭”菜单  **已砍掉**
2.用户添加了城市后,label出现在了最后的Frame中  **未实现**

'''
imgs=['./img/loading.png']
class App:
    def __init__(self):
        self.w=Tk()
        self.w.title('天气预报小工具-v1.0')
        width=600
        height=282
        left=(self.w.winfo_screenwidth()-width)/2
        top=(self.w.winfo_screenheight()-height)/2
        self.w.geometry('%dx%d+%d+%d'%(width,height,left,top))
        self.w.iconbitmap('biticon.ico')
        self.w.resizable(False,False)
        self.cerate_widgets()
        self.first_launch()
        self.set_widgets()
        self.place_widgets()
        self.thread_it(self.show_local_weather)
        self.w.mainloop()

    def cerate_widgets(self):
        self.note=ttk.Notebook()
        self.f1=Frame()
        self.tree=ttk.Treeview(self.f1)
        self.l1_var=StringVar()
        self.l1=ttk.Label(self.f1,textvariable=self.l1_var)
        self.m=Menu(self.w)
        self.w['menu']=self.m
        self.s1=Menu(self.m,tearoff=False)
        self.s2=Menu(self.m,tearoff=False)
        self.s3=Menu(self.m,tearoff=False)

    def set_widgets(self):
        self.location=[]
        style = ttk.Style(self.w)
        style.theme_use("default")
        columns=('rq','tq','flfx','zdqw','zgqw')
        self.tree.config(show='headings',columns=columns)
        self.tree.column(columns[0],anchor=CENTER,minwidth=95,width=110)
        self.tree.column(columns[1],anchor=CENTER,minwidth=60,width=70)
        self.tree.column(columns[2],anchor=CENTER,minwidth=90,width=100)
        self.tree.column(columns[3],anchor=CENTER,minwidth=90,width=100)
        self.tree.column(columns[4],anchor=CENTER,minwidth=90,width=100)
        self.tree.heading('rq', text='日期')
        self.tree.heading('tq', text='天气')
        self.tree.heading('flfx', text='风向风力')
        self.tree.heading('zdqw', text='最低气温')
        self.tree.heading('zgqw', text='最高气温')
        self.m.add_cascade(label='开始',menu=self.s1)
        self.s1.add_command(label='aaa',command='')
        self.s1.add_separator()
        self.s1.add_command(label='退出',command=self.quit_window)
        self.m.add_cascade(label='操作',menu=self.s2)
        self.s2.add_command(label='刷新',command=lambda:self.thread_it(self.refresh_weather))
        self.s2.add_command(label='添加城市',command=lambda:self.thread_it(self.select_city),state='disable')
        s2_sub = Menu(self.s2, tearoff=0)
        self.s2.add_separator()
        self.s2.add_cascade(label='更换主题',menu=s2_sub)
        self.m.add_cascade(label='关于',menu=self.s3)
        self.s3.add_command(label='关于作者',command=lambda :messagebox.showinfo('关于作者','作者很神秘,什么都没留下'))
        self.tree.tag_configure('evenColor',background='lightblue')
        self.w.protocol('WM_DELETE_WINDOW',self.quit_window)
        themes=[ 'default','clam', 'alt', 'classic']
        self.themevar=StringVar()
        for i,t in enumerate(themes):
            s2_sub.add_radiobutton(label=t,variable=self.themevar,command=lambda:self.thread_it(self.change_theme),value=t)
        self.themevar.set('default')

    def place_widgets(self):
        self.note.place(x=0,y=0,width=600,height=282)
        self.tree.place(x=0,y=0,width=600,height=150)
        self.l1.place(x=0,y=150,height=85,width=600)

    def first_launch(self):
        '''
        第一次启动,展示加载图片提示信息
        :return:
        '''
        self.start_time=time.time()
        paned = PanedWindow(self.w)
        self.img = imgs
        img = Image.open(self.img[0])
        paned.image = ImageTk.PhotoImage(img)
        self.load_img = Label(self.w, image=paned.image)
        self.load_lab = Label(self.w, text='Loading...')
        self.load_img.pack()
        self.load_lab.pack()

    def show_local_weather(self):
        '''
        展示定位天气信息
        :return:
        '''
        self.l1_var.set('正在刷新天气......')
        items = self.tree.get_children()
        for item in items:
            self.tree.delete(item)
        try:
            city,item=Weather_Get().get_local_weather()
            self.load_img.destroy()
            self.load_lab.destroy()
            self.s2.entryconfig('添加城市', state='normal')
            self.note.add(self.f1,text=city)
            i=0
            for data in item['recent']:
                self.tree.insert('', i, values=(
                data.get('日期'), data.get('天气'), data.get('风力风向'), data.get('最低气温'), data.get('最高气温')))
                i+=1
            self.l1_var.set(f'今天:{self.show_date()}\n当前所在地区:{city}\n当前气温:{item["now"]}\n感冒指数:{item["ganmao"]}')
        except TypeError:
            messagebox.showerror('错误','天气信息加载失败!')
            self.l1_var.set('天气信息加载失败!')
            self.s2.entryconfig('添加城市', state='normal')

    def refresh_weather(self):
        """
        刷新天气后,10秒内不能点击刷新
        :return:
        """
        self.s2.entryconfig('刷新', state='disable')
        self.show_local_weather()
        self.thread_it(self.wait_time)

    def wait_time(self):
        '''
        线程计时10s,十秒后刷新按钮可点击
        :return:
        '''
        time.sleep(10)
        self.s2.entryconfig('刷新', state='normal')



    def show_date(self):
        """
        展示日期信息,便于天气展示
        :return:
        """
        date = str(datetime.date.today())
        year,month,day=date.split('-')
        week_day_dict = {
            0: '星期一',
            1: '星期二',
            2: '星期三',
            3: '星期四',
            4: '星期五',
            5: '星期六',
            6: '星期日 ',
        }
        now=datetime.datetime.now()
        date_index = now.weekday()
        return f'{year}{month}{day}{week_day_dict[date_index]}'

    def select_city(self):
        '''
        Toplevel让用户选择城市,后台获取城市号
        :return:
        '''
        self.t=Toplevel()
        self.t.resizable(0,0)
        width=300
        height=140
        left=(self.t.winfo_screenwidth()-width)/2
        top=(self.t.winfo_screenheight()-height)/2
        self.t.geometry('%dx%d+%d+%d'%(width,height,left,top))
        self.t.title('选择城市')
        self.tl1=ttk.Label(self.t,text='请选择城市:')
        self.tl1.pack()
        provinces=Weather_Get().get_provinces()
        self.tc1=ttk.Combobox(self.t,justify='center',state='readonly',value=provinces)
        self.tc2=ttk.Combobox(self.t,justify='center',state='readonly')
        self.tc1.pack()
        self.tc1.bind('<<ComboboxSelected>>',self.show_tc2_value)
        self.tc2.bind('<<ComboboxSelected>>',self.show_tc3_value)
        self.tc2.pack()
        self.tc3=ttk.Combobox(self.t,justify='center',state='readonly')
        self.tc3.pack()
        self.tb1=ttk.Button(self.t,text='选择',command=lambda :self.thread_it(self.ack_city))
        self.tb1.pack(pady=10)
#----待完善
    def ack_city(self):
        '''
        Toplevel中选择了城市,选择使用notebook中建立Frame展示所选城市信息
        :return:
        '''
        cityno=self.get_city_no()
        weather_item=Weather_Get().get_weather(cityno)
        location=self.province_name+self.city_name+self.region
        if location in self.location:
            messagebox.showwarning('警告','此城市已添加,请勿重复添加!')
        else:
            self.location.append(location)
            self.f2= Frame(takefocus=True)
            self.note.add(self.f2, text=location)
            self.tree2 = ttk.Treeview(self.f2)
            columns = ('rq', 'tq', 'flfx', 'zdqw', 'zgqw')
            self.tree2.config(show='headings', columns=columns)
            self.tree2.column(columns[0], anchor=CENTER, minwidth=95, width=110)
            self.tree2.column(columns[1], anchor=CENTER, minwidth=60, width=70)
            self.tree2.column(columns[2], anchor=CENTER, minwidth=90, width=100)
            self.tree2.column(columns[3], anchor=CENTER, minwidth=90, width=100)
            self.tree2.column(columns[4], anchor=CENTER, minwidth=90, width=100)
            self.tree2.heading('rq', text='日期')
            self.tree2.heading('tq', text='天气')
            self.tree2.heading('flfx', text='风向风力')
            self.tree2.heading('zdqw', text='最低气温')
            self.tree2.heading('zgqw', text='最高气温')
            self.tree2.place(x=0,y=0,width=600,height=150)
            # label_='label'+str(self.click_no)
            # label_var='label'+str(self.click_no)+'_var'
            self.fl1_var=StringVar()
            self.fl1=ttk.Label(self.f2,textvariable=self.fl1_var)
            self.fl1.place(x=0,y=150,height=85,width=600)
            items = self.tree2.get_children()
            for item in items:
                self.tree2.delete(item)
            try:
                item = weather_item
                city=location
                i = 0
                for data in item['recent']:
                    self.tree2.insert('', i, values=(
                        data.get('日期'), data.get('天气'), data.get('风力风向'), data.get('最低气温'), data.get('最高气温')))
                    i += 1
                self.fl1_var.set(f'今天:{self.show_date()}\n当前所在地区:{city}\n当前气温:{item["now"]}\n感冒指数:{item["ganmao"]}')
            except TypeError:
                messagebox.showerror('错误','天气信息加载失败!')
                self.fl1_var.set(f'{city}天气信息加载失败!')
        self.t.destroy()

    def change_tab(self,*args):
        pass

    def show_tc2_value(self,event):
        '''
        展示"市"级信息
        :param event:
        :return:
        '''
        self.tc2.config(value=[])
        self.tc3.config(value=[])
        self.province_name=self.tc1.get()
        cities=Weather_Get().get_cities(self.province_name)
        self.tc2.config(value=cities)

    def show_tc3_value(self,event):
        '''
        展示"区/县"级信息
        :param event:
        :return:
        '''
        self.city_name=self.tc2.get()
        regions=Weather_Get().get_regions(self.province_name,self.city_name)
        self.tc3.config(value=regions)

    def get_city_no(self):
        """
        根据省、市、区、县 获取城市号
        :return: 城市号
        """
        self.region=self.tc3.get()
        city_no=Weather_Get().get_city_id_by_add(self.province_name,self.city_name,self.region)
        return city_no

    def change_theme(self,):
        '''
        更换主题
        :return:
        '''
        theme=self.themevar.get()
        style = ttk.Style(self.w)
        style.theme_use(theme)


    def quit_window(self):
        ret=messagebox.askyesno('退出','是否要退出?')
        if ret:
            self.w.destroy()

    def thread_it(self,func,*args):
        '''
        防止线程冲突
        :param func:
        :param args:
        :return:
        '''
        t=Thread(target=func,args=args)
        t.setDaemon(True)
        t.start()
        

if __name__ == '__main__':
    a=App()

五.总结
本次使用Tkinter写了一款天气预报小工具,基本支持全国每个省市的天气预报,支持历史天气(昨天)查看,虽然基本功能能够实现,但是仍旧存在两个小问题:
1.添加超过两个城市天气后,具体城市信息会显示在最新添加的Freame中。
2.ip定位不准确。
本程序还有两个特色:

1.支持更换主题。
2.程序首次启动加入了加载过渡。
其他的彩蛋,您自己去发现吧!

以上就是python制作的天气预报小工具(gui界面)的详细内容
获取更多python干货,请关注微信公众号:
在这里插入图片描述

  • 8
    点赞
  • 113
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
# 一、项目介绍 **项目名称:天气预测和天气可视化** 天气预测和天气可视化是一个基于python机器学习(ml)的长春地区的天气预报项目,它实现了天气数据的爬取,预测和可视化。 项目结构如下: ![img](image/wps26.jpg) * 天气数据的来源 GetData文件使用python爬虫技术,爬取长春和全国的天气信息数据 爬取网站:http://tianqi.2345.com/wea_history/54161.htm ProcessDate文件对爬取的天气数据进行了预处理 几个CSV文件保存的是爬取后并经过处理的数据 * 天气数据的预测 GetModel文件通过训练预测模型来预测长春近一周的天气,该文件利用Joblib将模型保存到本地 Main文件是项目主文件,通过运行该文件即可运行整个项目,该文件前部分获取保存到本地的预测模型来进行预测,并将预测结果打印到控制台 * 天气数据的可视化 Main文件后部分实现了天气数据的可视化 # 二、详细介绍 本项目分为三个部分,即爬取和处理数据,数据预测(包含评价方法)和数据可视化 ## 1. 爬取和处理数据 数据爬取代码: ````py resq = requests.get(url, headers=headers, params=params) data = resq.json()["data"] # data frame df = pd.read_html(data)[0] ```` 即使用python爬取网站的json数据 ### **数据预处理:** 获取到的天气信息包括最高温,最低温都不是int格式的数字,通过对数据截取,将部分指标的数据变换为int类型 并对缺失值进行了处理 ````py my_imputer = SimpleImputer() imputed_X_train = pd.DataFrame(my_imputer.fit_transform(X_train)) imputed_X_valid = pd.DataFrame(my_imputer.transform(X_valid)) ```` 通过SimpleImputer ,可以将现实数据中缺失的值通过同一列的均值、中值、或者众数补充起来,本项目使用了SimpleImputer的fit_transform对缺失值进行填充 ## 2. 数据预测和模型评价方法 预测数据采用了机器学习算法——线性回归 模型使用过程: ### A. 提取数据 ````py 获取测试集、训练集、验证集 [X_train, X_valid, y_train, y_valid, X_test] = ProcessData.ProcessData() ```` 其中ProcessData()函数里使用了如下语句: ````py X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, test_size=0.2, random_state=0) ```` train_test_split()是sklearn包的model_selection模块中提供的随机划分训练集和验证集的函数;使用train_test_split函数将完整的数据集和验证集以同等的比例分成2组不同的数据集和验证集 ### B. 训练模型 选择了随机树森林模型(randomforest),然后用fit来训练模型 ````py # 随机树森林模型 model = RandomForestRegressor(random_state=0, n_estimators=1001) # 训练模型 model.fit(X_train, y_train) ```` ### C. 根据数据预测 ````py # 最终预测结果 preds = model.predict(r[1]) -------- 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! <项目介绍> 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 --------

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值