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


文章目录

  • 一.准备工作
  • 二.预览
    • 1.启动
    • 2.添加城市
  • 三.设计流程
    • 1.UI设计(草图)
    • 2.UI设计(QT设计师)
    • 3.解释
  • 四.源代码
  • 五.总结

之前用tk写过一款python3GUI–天气预报小工具实现了所在天气定位,以及指定城市天气预报的查询,这次使用PyQt5在之前tk的基础上加以改进,虽然功能没有新的增加,但是软件整体速度上有明显的变化,开整吧。
一.准备工作 基于PyQt5的QT设计师,安装、配置详见:
PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)详细教程
二.预览 1.启动 PyQt5|python3GUI--天气预报小工具By:PyQt5(附源码)
文章图片

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

点击“添加城市”,向主界面添加城市,遂展示所选城市天气信息,每个选项卡是能够关闭的,工具栏可以自由移动。
三.设计流程 天气数据还是基于spider,重点在于界面的设计以及信号和槽的使用。
1.UI设计(草图) 整体由QToolBar、QTabWidget、QTableWidget、Qlabel组成
PyQt5|python3GUI--天气预报小工具By:PyQt5(附源码)
文章图片

2.UI设计(QT设计师) PyQt5|python3GUI--天气预报小工具By:PyQt5(附源码)
文章图片

3.解释 这里解释一下,为什么有些组件最后没有展示:首次打开软件时,软件进行定位,会显示一张图片一个进度条以及一个带loading的标签,这时候QTableWidget是隐藏的,整体布局为垂直布局,当定位完成后,将QTableWidget设为可见并载入数据,loading结束,隐藏图片、进度条、以及加载提示,整体仍为垂直布局。
四.源代码 这里放的是UI与爬虫的交互代码
#-*-coding:utf-8-*- import sys importdatetime 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_timedef 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: passdef 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=https://www.it610.com/article/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=https://www.it610.com/article/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=indexdef 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_())

五.总结 【PyQt5|python3GUI--天气预报小工具By:PyQt5(附源码)】QT设计师是真的好用,帮助我少写了很多的代码,算了一下,这个界面大概少写了300行代码,大部分时间都花在了界面的设计以及界面交互槽函数的实现,对比tk,QT确实强大!今后我还要多加练习,实现更多复杂的功能!
软件打包好,放在了蓝奏云。思路、代码方面有什么不足欢迎各位大佬指正、批评!能点个赞给我个鼓励吗?PyQt5|python3GUI--天气预报小工具By:PyQt5(附源码)
文章图片

    推荐阅读