python3GUI–天气预报小工具By:PyQt5(附源码)

@

之前用tk写过一款python3GUI–天气预报小工具实现了所在天气定位,以及指定城市天气预报的查询,这次使用PyQt5在之前tk的基础上加以改进,虽然功能没有新的增加,但是软件整体速度上有明显的变化,开整吧。

一.准备工作

基于PyQt5的QT设计师,安装、配置详见:

PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)详细教程

二.预览

1.启动

python3GUI--天气预报小工具By:PyQt5(附源码)
启动后,会自动定位当前所在城市,展示所在城市前后五天的天气信息。

2.添加城市

python3GUI--天气预报小工具By:PyQt5(附源码)
点击”添加城市”,向主界面添加城市,遂展示所选城市天气信息,每个选项卡是能够关闭的,工具栏可以自由移动。

三.设计流程

天气数据还是基于spider,重点在于界面的设计以及信号和槽的使用。

1.UI设计(草图)

整体由QToolBar、QTabWidget、QTableWidget、Qlabel组成

python3GUI--天气预报小工具By:PyQt5(附源码)

2.UI设计(QT设计师)

python3GUI--天气预报小工具By:PyQt5(附源码)

3.解释

这里解释一下,为什么有些组件最后没有展示:首次打开软件时,软件进行定位,会显示一张图片一个进度条以及一个带loading的标签,这时候QTableWidget是隐藏的,整体布局为垂直布局,当定位完成后,将QTableWidget设为可见并载入数据,loading结束,隐藏图片、进度条、以及加载提示,整体仍为垂直布局。

四.源代码

这里放的是UI与爬虫的交互代码

#-*-coding:utf-8-*-
import sys
import  datetime
import threading
import webbrowser
from PyQt5.uic import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt as qqt
from Weather_Spider import Weather_Get
import add_city
import weather

"""
天气信息刷新时,label不能更新**已解决**
"添加城市"窗口,关闭后,主窗口不可用setEnable(True)**未解决**   **0914已解决** 使用自定义信号槽
 #天气信息待加载,与label不能对应______________________**已解决**

热键注册
"""
class add_city_window(QWidget):
    Signal_parp = pyqtSignal(bool)
    def __init__(self):
        # 信号的定义
        super().__init__()
        #这里有些不解,为什么调用时,要用两侧add_ui
        self.add_ui=add_city.Ui_add_city_window()
        self.add_ui.setupUi(self)

    def closeEvent(self, event):
        self.close()
        self.Signal_parp.emit(True)

class Weather_Report(QMainWindow):
    Signal_parp = pyqtSignal(str)
    def __init__(self):
        super().__init__()
        self.first_start_flag=True
        self.tab_index=0
        self.label_widget_list=[]
        self.table_widget_list=[]
        self.ui =weather.Ui_MainWindow()
        self.ui.setupUi(self)
        self.setFixedSize(self.width(), self.height())#禁止最大化
        self.setFixedSize(695, 445)  # 天气信息加载成功之后,窗口的大小
        self.adjustSize()
        self.ui.tabWidget.hide()
        self.ui.action_open_China_weather.setEnabled(False)
        self.ui.action_add_city.setEnabled(False)
        self.W=Weather_Get()
        self.current_china_weather_url=''
        self.city_number_list=[]
        self.city_list=[]
        self.ui.action_open_China_weather.triggered.connect(self.open_china_weather_web)
        self.ui.actiont_quit_window.triggered.connect(self.close)
        self.ui.action_refresh.triggered.connect(self.refreash_weather_infos)
        self.ui.action_about_author.triggered.connect(self.show_about_author)
        self.ui.action_add_city.triggered.connect(self.do_select_city)
        self.ui.tabWidget.tabCloseRequested.connect(self.close_tab)
        self.ui.tabWidget.currentChanged.connect(self.change_index)
        self.thread_it(self.show_local_weather)

    def change_main_ui_status(self, status):
        self.setEnabled(status)

    def show_local_weather(self):
        '''
        展示定位天气信息
        :return:
        '''
        self.ui.label_weather_infos.setText('正在刷新......')
        self.ui.tableWidget.clearContents()
        try:
            if self.first_start_flag:
                city,item,number=self.W.get_local_weather()
                self.local_city_number=number
                self.local_city_=city
            else:
                item=self.W.get_weather(self.local_city_number)
                city=self.local_city_
                number=self.local_city_number
            self.ui.tabWidget.setTabText(0,city)    #将默认的定位更改为当前所在城市名
            datas = item['recent']
            self.ui.action_open_China_weather.setEnabled(True)
            self.ui.action_add_city.setEnabled(True)
            self.ui.label_loading_pic.hide()
            self.ui.label_loading_now.hide()
            self.ui.BlueProgressBar.hide()
            self.ui.tabWidget.setVisible(True)
            self.ui.label_weather_infos.setVisible(True)
            for index,data in enumerate(datas):
                newItem = QTableWidgetItem(data["日期"])
                newItem.setTextAlignment(Qt.AlignCenter )
                self.ui.tableWidget.setItem(index, 0, newItem)
                newItem = QTableWidgetItem(data["天气"])
                newItem.setTextAlignment(Qt.AlignCenter )
                self.ui.tableWidget.setItem(index, 1, newItem)
                newItem = QTableWidgetItem(data["风力风向"])
                newItem.setTextAlignment(Qt.AlignCenter)
                self.ui.tableWidget.setItem(index, 2, newItem)
                newItem = QTableWidgetItem(data["最低气温"])
                newItem.setTextAlignment(Qt.AlignCenter )
                self.ui.tableWidget.setItem(index, 3, newItem)
                newItem = QTableWidgetItem(data["最高气温"])
                newItem.setTextAlignment(Qt.AlignCenter)
                self.ui.tableWidget.setItem(index, 4, newItem)
            self.ui.tableWidget.setColumnWidth(0, 160)
            self.ui.tableWidget.setColumnWidth(4, 125)
            now_time = str(datetime.datetime.now()).split('.')[0].split(' ')[-1]
            self.ui.label_weather_infos.setText(f'今天:{self.show_date()}\n当前所在地区:{city}\n当前气温:{item["now"]}({now_time}更新)\n感冒指数:{item["ganmao"]}')
            #将定位城市加入 已展示城市列表self.location中
            self.current_china_weather_url= f'http://www.weather.com.cn/weather/{number}.shtml'
            if self.first_start_flag:
                self.city_number_list.append(number)
                self.city_list.append(city)
                self.first_start_flag=False
        except TypeError:
            QMessageBox.warning(self,'错误','天气信息加载失败!')
            self.statusBar().showMessage('天气信息加载失败!', 3000)
            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()
        date_time=f'{year}年{month}月{day}日 {week_day_dict[date_index]}'
        return date_time

    def do_select_city(self):
        #选择省份 城市 所在地
        self.setEnabled(False)
        self.add_ui=add_city_window()
        self.add_ui.Signal_parp.connect(self.change_main_ui_status)
        self.add_ui.setFixedSize(self.add_ui.width(), self.add_ui.height())#禁止最大化
        provences=self.W.get_provinces()
        self.add_ui.add_ui.comboBox_provence.addItem('--请选择--')
        self.add_ui.add_ui.comboBox_provence.addItems(provences)
        self.add_ui.add_ui.comboBox_provence.currentIndexChanged.connect(self.get_citys)
        self.add_ui.add_ui.comboBox_city.currentIndexChanged.connect(self.get_regions)
        self.add_ui.add_ui.pushButton_add_the_city.clicked.connect(self.do_add_city)
        self.add_ui.show()

    def closeEvent(self,event):
        reply = QMessageBox.question(self, '关闭', "确定要退出吗?",
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
        # 判断返回值,如果点击的是Yes按钮,我们就关闭组件和应用,否则就忽略关闭事件
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def get_citys(self):
        self.add_ui.add_ui.comboBox_city.clear()
        self.add_ui.add_ui.comboBox_region.clear()
        self.curr_provence=self.add_ui.add_ui.comboBox_provence.currentText()
        ciyies=self.W.get_cities(self.curr_provence)
        self.add_ui.add_ui.comboBox_city.addItems(ciyies)

    def get_regions(self):
        try:
            self.add_ui.add_ui.comboBox_region.clear()
            self.curr_city=self.add_ui.add_ui.comboBox_city.currentText()
            ciyies=self.W.get_regions(self.curr_provence,self.curr_city)
            self.add_ui.add_ui.comboBox_region.addItems(ciyies)
        except KeyError:
            pass

    def do_add_city(self):
        if self.add_ui.add_ui.comboBox_provence.currentText()=='--请选择--':
            QMessageBox.warning(self,'警告','请选择城市!')
        else:
            self.curr_region=self.add_ui.add_ui.comboBox_region.currentText()
            self.curr_city_no=0
            if self.curr_region!='':
                self.curr_city_data=self.curr_provence+self.curr_city+self.curr_region
                self.curr_city_no=self.W.get_city_id_by_add(self.curr_provence,self.curr_city,self.curr_region)
            else:
                self.curr_city_data=self.curr_provence+self.curr_city
                self.curr_city_no=self.W.get_city_id_by_add(self.curr_provence,self.curr_city)
            if self.curr_city_no==0:
                QMessageBox.information(self,"提示",'未找到相关城市天气信息,请尝试更换城市!')
            else:
                if self.curr_city_no in self.city_number_list:
                    QMessageBox.warning(self, "警告", '此城市已经添加,请勿重复添加!')
                else:
                    self.tab=QWidget(self)
                    self.ui.tabWidget.addTab(self.tab,self.curr_city_data)
                    tble_widget_new=QTableWidget(self.ui.tabWidget)
                    tble_widget_new.setEnabled(True)
                    tble_widget_new.setContextMenuPolicy(qqt.NoContextMenu)#没有右键菜单
                    tble_widget_new.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow)#自动添加滚动条
                    tble_widget_new.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)#不可编辑
                    tble_widget_new.setAlternatingRowColors(True)
                    tble_widget_new.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)#选择模式:单选
                    tble_widget_new.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)#选择行为:整行选择
                    tble_widget_new.setTextElideMode(qqt.ElideMiddle)#省略号出现在长文本中间
                    tble_widget_new.setShowGrid(True)#显示网格
                    tble_widget_new.setGridStyle(qqt.SolidLine)#网格风格
                    tble_widget_new.setWordWrap(True)
                    tble_widget_new.setRowCount(5)
                    tble_widget_new.setColumnCount(5)
                    tble_widget_new.horizontalHeader().setCascadingSectionResizes(False)
                    tble_widget_new.horizontalHeader().setDefaultSectionSize(95)
                    tble_widget_new.horizontalHeader().setMinimumSectionSize(30)
                    tble_widget_new.verticalHeader().setVisible(False)
                    tble_widget_new.verticalHeader().setCascadingSectionResizes(False)
                    tble_widget_new.verticalHeader().setDefaultSectionSize(36)
                    tble_widget_new.verticalHeader().setMinimumSectionSize(30)
                    tble_widget_new.verticalHeader().setSortIndicatorShown(False)
                    tble_widget_new.verticalHeader().setStretchLastSection(True)
                    tble_widget_new.horizontalHeader().setStretchLastSection(True)
                    tble_widget_new.setColumnWidth(0, 160)
                    tble_widget_new.setColumnWidth(4, 125)
                    tble_widget_new.setHorizontalHeaderLabels(['日期', '天气', '风向风力', '最低气温', '最高气温'])
                    new_label=QLabel(self)
                    # 渲染到页面
                    Layout = QVBoxLayout(self.tab)
                    Layout.setContentsMargins(0, 0, 0, 0)
                    self.setEnabled(True)
                    self.add_ui.close()#关闭"添加城市"窗口
                    weather_infos=self.W.get_weather(self.curr_city_no)
                    datas = weather_infos['recent']
                    for index, data in enumerate(datas):
                        newItem = QTableWidgetItem(data["日期"])
                        newItem.setTextAlignment(Qt.AlignCenter)
                        tble_widget_new.setItem(index, 0, newItem)
                        newItem = QTableWidgetItem(data["天气"])
                        newItem.setTextAlignment(Qt.AlignCenter)
                        tble_widget_new.setItem(index, 1, newItem)
                        newItem = QTableWidgetItem(data["风力风向"])
                        newItem.setTextAlignment(Qt.AlignCenter)
                        tble_widget_new.setItem(index, 2, newItem)
                        newItem = QTableWidgetItem(data["最低气温"])
                        newItem.setTextAlignment(Qt.AlignCenter)
                        tble_widget_new.setItem(index, 3, newItem)
                        newItem = QTableWidgetItem(data["最高气温"])
                        newItem.setTextAlignment(Qt.AlignCenter)
                        tble_widget_new.setItem(index, 4, newItem)
                    tble_widget_new.setColumnWidth(0, 160)
                    tble_widget_new.setColumnWidth(4, 162)
                    now_time = str(datetime.datetime.now()).split('.')[0].split(' ')[-1]
                    new_label.setText(
                        f'今天:{self.show_date()}\n当前所选地区:{self.curr_city_data}\n当前气温:{weather_infos["now"]}({now_time}更新)\n感冒指数:{weather_infos["ganmao"]}')
                    # 将定位城市加入 已展示城市列表self.location中
                    Layout.addWidget(tble_widget_new)
                    Layout.addWidget(new_label)
                    self.label_widget_list.append(new_label)
                    self.table_widget_list.append(tble_widget_new)
                    self.city_number_list.append(self.curr_city_no)
                    self.city_list.append(self.curr_city)

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

    def refreash_weather_infos(self):
        if self.tab_index==0:
            self.ui.label_weather_infos.setText('正在刷新天气信息......')
            self.thread_it(self.show_local_weather)
        else:
            curr_city_no=self.city_number_list[self.tab_index]
            table_widget=self.table_widget_list[self.tab_index-1]
            new_label=self.label_widget_list[self.tab_index-1]
            table_widget.clearContents()
            weather_infos = self.W.get_weather(curr_city_no)
            weather_data=weather_infos['recent']
            for index, data in enumerate(weather_data):
                newItem = QTableWidgetItem(data["日期"])
                newItem.setTextAlignment(Qt.AlignCenter)
                table_widget.setItem(index, 0, newItem)
                newItem = QTableWidgetItem(data["天气"])
                newItem.setTextAlignment(Qt.AlignCenter)
                table_widget.setItem(index, 1, newItem)
                newItem = QTableWidgetItem(data["风力风向"])
                newItem.setTextAlignment(Qt.AlignCenter)
                table_widget.setItem(index, 2, newItem)
                newItem = QTableWidgetItem(data["最低气温"])
                newItem.setTextAlignment(Qt.AlignCenter)
                table_widget.setItem(index, 3, newItem)
                newItem = QTableWidgetItem(data["最高气温"])
                newItem.setTextAlignment(Qt.AlignCenter)
                table_widget.setItem(index, 4, newItem)
            now_time = str(datetime.datetime.now()).split('.')[0].split(' ')[-1]
            new_label.setText(
                f'今天:{self.show_date()}\n当前所选地区:{self.curr_city_data}\n当前气温:{weather_infos["now"]}({now_time}更新)\n感冒指数:{weather_infos["ganmao"]}')

    def open_china_weather_web(self):
        webbrowser.open(self.current_china_weather_url)

    def close_tab(self,index):
        if self.ui.tabWidget.count()>1:
            self.ui.tabWidget.removeTab(index)
            #同步更新两个列表
            self.city_number_list.pop(index)
            self.city_list.pop(index)
        else:
            self.close()

    def change_index(self,index):
"""
        tabwidget 索引发生改变触发的事件,
        改变当前中国天气URL地址
        :param index: 当前tab所选索引
        :return:
"""
        self.current_china_weather_url= f'http://www.weather.com.cn/weather/{self.city_number_list[index]}.shtml'
        self.tab_index=index

    def show_about_author(self):
        QMessageBox.information(self,'关于','作者:懷淰メ\nBy:PyQT5')

if __name__ == '__main__':
    app=QApplication(sys.argv)
    ui=Weather_Report()
    ui.show()
    sys.exit(app.exec_())

五.总结

QT设计师是真的好用,帮助我少写了很多的代码,算了一下,这个界面大概少写了300行代码,大部分时间都花在了界面的设计以及界面交互槽函数的实现,对比tk,QT确实强大!今后我还要多加练习,实现更多复杂的功能!
软件打包好,放在了蓝奏云。思路、代码方面有什么不足欢迎各位大佬指正、批评!能点个赞给我个鼓励吗?

python3GUI--天气预报小工具By:PyQt5(附源码)

Original: https://www.cnblogs.com/a1397852386/p/15729838.html
Author: 懷淰メ
Title: python3GUI–天气预报小工具By:PyQt5(附源码)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/643574/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 持续集成

    本文简要介绍持续集成的概念和做法。 一、概念 持续集成指的是,频繁地(一天多次)将代码集成到主干。 它的好处主要有两个。 (1)快速发现错误。每完成一点更新,就集成到主干,可以快速…

    技术杂谈 2023年5月31日
    084
  • 上周热点回顾(7.11-7.17)

    热点随笔: · 一次线上事故,我顿悟了异步的精髓 (勇哥编程游记)· 跟HR在大群吵架是什么体验? (叶小钗)· 利用噪声构建美妙的 CSS 图形 (ChokCoco)· .NET…

    技术杂谈 2023年5月31日
    076
  • 贝克莱悖论

    17世纪后期,牛顿、莱布尼茨创立微积分学,成为解决众多问题的重要而有力的工具,并在实际应用中获得了巨大成功,然而,微积分学产生伊始,迎来的并非全是掌声,在当时它还遭到了许多人的强烈…

    技术杂谈 2023年5月31日
    074
  • Jni OnLoad()和OnUnload()

    除了前面说的自定义JNI函数之外,JNI还提供了两个特殊函数,它们是JNI_OnLoad()和JNI_OnUnload(),分别在加载库和卸载库的时候调用。 1、JNI_OnLoa…

    技术杂谈 2023年5月30日
    079
  • mean-shift算法详解(转)

    MeanShift最初由Fukunaga和Hostetler在1975年提出,但是一直到2000左右这篇PAMI的论文Mean Shift: A Robust Approach T…

    技术杂谈 2023年6月1日
    079
  • 利用JVM钩子函数优雅关闭线程池

    核心API: shutDown shutDownNow awaitTermination 利用JVM钩子函数,在虚拟机关闭时调用相关方法即”优雅关闭线程池”…

    技术杂谈 2023年7月25日
    050
  • 霍金斯能量层级图解析

    https://www.jianshu.com/p/9069cc1a5c9d Original: https://www.cnblogs.com/dhcn/p/16355265.h…

    技术杂谈 2023年5月31日
    0104
  • H3C STA>PC的数据转发

    posted @2019-09-23 21:02 樊伟胜 阅读(677 ) 评论() 编辑 Original: https://www.cnblogs.com/fanweishen…

    技术杂谈 2023年5月30日
    093
  • 23种设计模式之访问者模式(Visitor Pattern)

    文章目录 概述 访问者模式的优缺点 访问者模式的使用场景 访问者模式的结构和实现 * 模式结构 模式实现 总结 概述 访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可…

    技术杂谈 2023年7月24日
    061
  • vlc media下载路径

    vlc media下载路径http://download.videolan.org/pub/videolan/vlc/ posted on2022-06-07 09:40 shao…

    技术杂谈 2023年6月1日
    092
  • 「猪齿鱼」助力汉得信息智能制造集中交付高效协同

    导语 IT咨询行业面临着人天单价难以提高,而员工待遇和营运成本持续提升的压力,这大大压缩了咨询公司的利润空间,逼迫着咨询公司要想办法提高项目的交付效率,进行业务模式的变革。采用远程…

    技术杂谈 2023年7月24日
    0102
  • SpringBoot整合参数校验的两种方式应用实践

    背景:SpringBoot秒杀小项目实现了两种参数校验方式1.原登录业务逻辑处理使用的正则表达式校验手机号格式输入(未使用Validation参数校验,只是简单实现)2.更改业务逻…

    技术杂谈 2023年7月25日
    067
  • Linux系统创建可执行文件软链接

    由于创建软链接这个事情,在算法开发的日常中使用到的并不是很多,因此本文也是做一个简单的回顾。这里我们使用的案例是通过TMalign这个蛋白质打分文件,在编译好可执行文件之后,可以使…

    技术杂谈 2023年7月24日
    076
  • 【赵渝强】使用二进制包部署Kubernetes集群

    在一些企业的私有环境中可能无法连接外部的网络。如果要在这样的环境中部署Kubernetes集群,可以采集Kubernetes离线安装的方式进行部署。即:使用二进制安装包部署Kube…

    技术杂谈 2023年7月24日
    092
  • 危险的赌注

    低代码应用平台(LCAP – Low Code Application Platforms)在多样、复杂的现代软件开发情势下应运而生。根据 Gartner 的数据,Me…

    技术杂谈 2023年6月21日
    0151
  • 基于TCP/IP协议,定义原始的字节流协议传输Student类

    在分布式系统中,不同节点之间需要进行通信来实现一致性,例如:在投票选举阶段,候选者需要为所有其他节点发送拉票请求,拉票请求中包含着自己的网络地址和任期号,也就是说,我们需要发送一个…

    技术杂谈 2023年7月23日
    063
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球