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


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

一.准备工作

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

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

二.预览

1.启动

请添加图片描述
启动后,会自动定位当前所在城市,展示所在城市前后五天的天气信息。

2.添加城市

请添加图片描述
点击“添加城市”,向主界面添加城市,遂展示所选城市天气信息,每个选项卡是能够关闭的,工具栏可以自由移动。

三.设计流程

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

1.UI设计(草图)

整体由QToolBar、QTabWidget、QTableWidget、Qlabel组成
在这里插入图片描述

2.UI设计(QT设计师)

在这里插入图片描述

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确实强大!今后我还要多加练习,实现更多复杂的功能!
软件打包好,放在了蓝奏云。思路、代码方面有什么不足欢迎各位大佬指正、批评!能点个赞给我个鼓励吗?请添加图片描述

猜你喜欢

转载自blog.csdn.net/a1397852386/article/details/120327896