文章目录
本次使用PyQt5制作一款历史上的今天查看器,支持查看任一日期的历史事件,包括大事记、逝世事记、出生事记,简单又小巧,开始吧~
一.准备工作
请确保已经安装了Python3.X,安装以下第三方库。
- PyQt5
用于QT代码的撰写
pip install PyQt5
2.PyQt5-tools
使用其中的QT设计师,进行QT界面设计
pip install PyQt5-tools
二.预览
1.启动
启动以后软件自动加载当天的历史大事记,点击左侧的事件即可查看对应的事件详情。
2.日期切换
在旋钮组件(SpinBox)中选择一个日期,就会转到所选日期的大事件(字体、字体颜色、背景色可单独设置)
三.设计流程
1.整体流程
2.UI设计(草图)
3.UI设计(QT设计师)
四.源代码
1.History_Today_GUI.py(主程序)
import socket
import sys
import requests
import webbrowser
from PyQt5.uic import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from history_today import Ui_MainWindow
from history_event_get import Event_Get
"""
希望对按照时间升序排列事件 **已实现**
单击label改变颜色
异常处理优化 如:启动等待时间长 **判断网络连接状态**
"""
class Big_Eventts(QMainWindow):
def __init__(self):
super().__init__()
self.ui=Ui_MainWindow()
self.ui.setupUi(self)
current_date = QDate.currentDate()
if self.check_network():
self.load_events(current_date)#首次启动初始化
else:
QMessageBox.warning(self, "警告", "请先连接到互联网,再使用本软件!")
self.destroy(self)
self.ui.dateTimeEdit.setDate(current_date)#初始化时间
self.ui.dateTimeEdit.dateChanged.connect(self.load_events)
self.ui.tableWidget_1.cellClicked.connect(self.show_event_detail)
self.ui.tableWidget_2.cellClicked.connect(self.show_event_detail)
self.ui.tableWidget_3.cellClicked.connect(self.show_event_detail)
self.ui.action_about_software.triggered.connect(lambda :QMessageBox.information(self,"关于软件","以铜为镜,可以正衣冠。\n以史为镜,可以知兴替。\n以人为镜,可以明得失。\n\t\t——李世民 《旧唐书·魏徵传》"))
self.ui.action_about_author.triggered.connect(lambda :QMessageBox.information(self,"关于作者","作者:懷淰メ\nBy:PyQT5"))
self.ui.action_setFont.triggered.connect(self.set_font)
self.ui.action_quit.triggered.connect(lambda :self.close())
self.ui.action_home_page.triggered.connect(lambda :webbrowser.open('https://blog.csdn.net/a1397852386'))
self.ui.action_set_fg_color.triggered.connect(self.set_fg_color)
self.ui.action_set_bg_color.triggered.connect(self.set_bg_color)
self.ui.pushButton.clicked.connect(lambda :self.load_events(current_date))
self.ui.tableWidget_2.verticalHeader().setVisible(True)#这里出现了bug,在QT设计师设计保存了,还是会改变
def check_network(self):
#检查设备是否连接互联网
try:
r=requests.get('http://www.baidu.com',timeout=3)
if r.status_code==200:
return True
else:
return False
except:
return False
def load_events(self,date):
"""
加载三部分的事件
:return:
"""
try:
if date==QDate.currentDate():
self.ui.pushButton.setEnabled(False)
else:
self.ui.pushButton.setEnabled(True)
self.ui.tabWidget.setCurrentIndex(0)
self.ui.textEdit.clear()
month,day=date.toString('MM-dd').split('-')
self.spider=Event_Get(month,day)
big_events=self.spider.get_evnets(1)
self.big_events=big_events
self.ui.tableWidget_1.setRowCount(len(big_events))
for index,data1 in enumerate(big_events):
new_item1=QTableWidgetItem(data1['event'])
self.ui.tableWidget_1.setItem(index, 0, new_item1)
cs_events=self.spider.get_evnets(2)
self.cs_events=cs_events
self.ui.tableWidget_2.setRowCount(len(cs_events))
for index, data2 in enumerate(cs_events):
new_item2 = QTableWidgetItem(data2['event'])
self.ui.tableWidget_2.setItem(index, 0, new_item2)
ss_events=self.spider.get_evnets(3)
self.ss_events=ss_events
self.ui.tableWidget_3.setRowCount(len(ss_events))
for index, data3 in enumerate(ss_events):
new_item3 = QTableWidgetItem(data3['event'])
self.ui.tableWidget_3.setItem(index, 0, new_item3)
except:
QMessageBox.critical(self,"错误",'数据加载错误,请检查网络!')
def show_event_detail(self,row,_)->None:
"""
显示所选事件详情
:param row: 行
:param _: 列,在此处无用
:return: None
"""
tablewidget_index=int(self.sender().objectName().split('_')[-1])
if tablewidget_index==1:
data=self.big_events[row]
elif tablewidget_index==2:
data=self.cs_events[row]
elif tablewidget_index==3:
data=self.ss_events[row]
event_link=data['link']
detail=self.spider.get_event_detail(event_link)
self.ui.textEdit.setPlainText(detail)
def set_font(self):
"""
设置字体、大小、特殊
:return:
"""
font,ok=QFontDialog.getFont()
if ok :
self.ui.textEdit.setFont(font)
def set_fg_color(self):
"""
设置字体颜色
:return:
"""
color=QColorDialog.getColor()
self.ui.textEdit.setTextColor(color)
def set_bg_color(self):
"""
使用QSS 设置textedit背景色
:return:
"""
color=QColorDialog.getColor()
self.ui.textEdit.setStyleSheet("QTextEdit{background-color:%s;}"%color.name())
def closeEvent(self,event):
ret=QMessageBox.question(self,'退出','确定要退出?',QMessageBox.Yes|QMessageBox.No,QMessageBox.Yes)
if ret==QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app=QApplication(sys.argv)
ui=Big_Eventts()
ui.show()
sys.exit(app.exec_())
2.history_today.py(UI)
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'history_today.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(805, 624)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setContentsMargins(-1, 10, -1, -1)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem)
self.label_title = QtWidgets.QLabel(self.centralwidget)
self.label_title.setStyleSheet("QLabel{\n"
"color:rgb(170, 85, 0);\n"
"font-size:30px;\n"
"font-family:\"Times New Roman\"\n"
"}")
self.label_title.setObjectName("label_title")
self.horizontalLayout_2.addWidget(self.label_title)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem1)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem2)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.dateTimeEdit = QtWidgets.QDateTimeEdit(self.centralwidget)
self.dateTimeEdit.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
self.dateTimeEdit.setReadOnly(False)
self.dateTimeEdit.setCurrentSection(QtWidgets.QDateTimeEdit.MonthSection)
self.dateTimeEdit.setCalendarPopup(True)
self.dateTimeEdit.setTimeSpec(QtCore.Qt.LocalTime)
self.dateTimeEdit.setObjectName("dateTimeEdit")
self.horizontalLayout.addWidget(self.dateTimeEdit)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem3)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setMinimumSize(QtCore.QSize(30, 0))
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem4)
self.verticalLayout.addLayout(self.horizontalLayout)
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
self.tabWidget.setTabPosition(QtWidgets.QTabWidget.North)
self.tabWidget.setTabShape(QtWidgets.QTabWidget.Triangular)
self.tabWidget.setTabBarAutoHide(False)
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.tableWidget_1 = QtWidgets.QTableWidget(self.tab)
self.tableWidget_1.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.tableWidget_1.setAlternatingRowColors(True)
self.tableWidget_1.setWordWrap(False)
self.tableWidget_1.setObjectName("tableWidget_1")
self.tableWidget_1.setColumnCount(1)
self.tableWidget_1.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_1.setHorizontalHeaderItem(0, item)
self.tableWidget_1.horizontalHeader().setVisible(False)
self.tableWidget_1.horizontalHeader().setCascadingSectionResizes(False)
self.tableWidget_1.horizontalHeader().setStretchLastSection(True)
self.verticalLayout_2.addWidget(self.tableWidget_1)
self.tabWidget.addTab(self.tab, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.tab_2)
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.tableWidget_2 = QtWidgets.QTableWidget(self.tab_2)
self.tableWidget_2.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.tableWidget_2.setAlternatingRowColors(True)
self.tableWidget_2.setWordWrap(False)
self.tableWidget_2.setObjectName("tableWidget_2")
self.tableWidget_2.setColumnCount(1)
self.tableWidget_2.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_2.setHorizontalHeaderItem(0, item)
self.tableWidget_2.horizontalHeader().setVisible(False)
self.tableWidget_2.horizontalHeader().setStretchLastSection(True)
self.tableWidget_2.verticalHeader().setVisible(False)
self.horizontalLayout_6.addWidget(self.tableWidget_2)
self.tabWidget.addTab(self.tab_2, "")
self.tab_3 = QtWidgets.QWidget()
self.tab_3.setObjectName("tab_3")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.tab_3)
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.tableWidget_3 = QtWidgets.QTableWidget(self.tab_3)
self.tableWidget_3.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.tableWidget_3.setAlternatingRowColors(True)
self.tableWidget_3.setWordWrap(False)
self.tableWidget_3.setObjectName("tableWidget_3")
self.tableWidget_3.setColumnCount(1)
self.tableWidget_3.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_3.setHorizontalHeaderItem(0, item)
self.tableWidget_3.horizontalHeader().setVisible(False)
self.tableWidget_3.horizontalHeader().setStretchLastSection(True)
self.horizontalLayout_4.addWidget(self.tableWidget_3)
self.tabWidget.addTab(self.tab_3, "")
self.horizontalLayout_5.addWidget(self.tabWidget)
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox.setObjectName("groupBox")
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.groupBox)
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.textEdit = QtWidgets.QTextEdit(self.groupBox)
self.textEdit.setStyleSheet("")
self.textEdit.setObjectName("textEdit")
self.horizontalLayout_3.addWidget(self.textEdit)
self.horizontalLayout_5.addWidget(self.groupBox)
self.verticalLayout.addLayout(self.horizontalLayout_5)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 805, 26))
self.menubar.setObjectName("menubar")
self.menu = QtWidgets.QMenu(self.menubar)
self.menu.setObjectName("menu")
self.menu_2 = QtWidgets.QMenu(self.menubar)
self.menu_2.setObjectName("menu_2")
self.menu_3 = QtWidgets.QMenu(self.menubar)
self.menu_3.setObjectName("menu_3")
MainWindow.setMenuBar(self.menubar)
self.action_about_software = QtWidgets.QAction(MainWindow)
self.action_about_software.setObjectName("action_about_software")
self.action_about_author = QtWidgets.QAction(MainWindow)
self.action_about_author.setObjectName("action_about_author")
self.action_quit = QtWidgets.QAction(MainWindow)
self.action_quit.setObjectName("action_quit")
self.action_setFont = QtWidgets.QAction(MainWindow)
self.action_setFont.setObjectName("action_setFont")
self.action_home_page = QtWidgets.QAction(MainWindow)
self.action_home_page.setObjectName("action_home_page")
self.action_set_bg_color = QtWidgets.QAction(MainWindow)
self.action_set_bg_color.setObjectName("action_set_bg_color")
self.action_set_fg_color = QtWidgets.QAction(MainWindow)
self.action_set_fg_color.setObjectName("action_set_fg_color")
self.menu.addAction(self.action_home_page)
self.menu.addSeparator()
self.menu.addAction(self.action_quit)
self.menu_2.addAction(self.action_about_software)
self.menu_2.addAction(self.action_about_author)
self.menu_3.addAction(self.action_setFont)
self.menu_3.addAction(self.action_set_fg_color)
self.menu_3.addAction(self.action_set_bg_color)
self.menubar.addAction(self.menu.menuAction())
self.menubar.addAction(self.menu_3.menuAction())
self.menubar.addAction(self.menu_2.menuAction())
self.retranslateUi(MainWindow)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "历史上的今天"))
self.label_title.setText(_translate("MainWindow", "历史上的今天"))
self.label.setText(_translate("MainWindow", "选择一个日期:"))
self.dateTimeEdit.setDisplayFormat(_translate("MainWindow", "MM月dd日"))
self.pushButton.setText(_translate("MainWindow", "回今天"))
item = self.tableWidget_1.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "事件"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "大事记"))
item = self.tableWidget_2.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "事件"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "出生"))
item = self.tableWidget_3.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "事件"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "逝世"))
self.groupBox.setTitle(_translate("MainWindow", "事件详情"))
self.menu.setTitle(_translate("MainWindow", "开始"))
self.menu_2.setTitle(_translate("MainWindow", "关于"))
self.menu_3.setTitle(_translate("MainWindow", "设置"))
self.action_about_software.setText(_translate("MainWindow", "关于软件"))
self.action_about_author.setText(_translate("MainWindow", "关于作者"))
self.action_quit.setText(_translate("MainWindow", "退出"))
self.action_setFont.setText(_translate("MainWindow", "设置字体"))
self.action_home_page.setText(_translate("MainWindow", "访问作者主页"))
self.action_set_bg_color.setText(_translate("MainWindow", "设置背景颜色"))
self.action_set_fg_color.setText(_translate("MainWindow", "设置字体颜色"))
3.history_event_get.py(获取数据)
import requests
import json
import re
from urllib.parse import urljoin
from lxml import etree
class Event_Get:
def __init__(self,month,day):
self.month=month
self.day=day
def title_clean(self,title):
if "\xa0"in title:
title=title.replace('\xa0','')
if '·'in title :
title=title.replace('·','')
title_new=title
return title_new
def get_html(self,url):
"""
获取文本代码
:param url:
:return:
"""
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4662.6 Safari/537.36',
'Host': 'jintian.160.com',
'Referer': url
}
r=requests.get(url,headers=headers)
if r.status_code==200:
r.encoding='utf-8'
html=r.text
return html
else:
return None
def get_sum_page_num(self,url):
"""
获取数据总页数
:param url:
:return:
"""
html = self.get_html(url)
if html:
_json=json.loads(html)
recordCount=_json.get('recordCount')
if recordCount<=14:
page_num=1
else:
i,r=divmod(recordCount,14)
if r==0:
page_num=i
else:
page_num=1+1
return page_num
else:
return False
def get_evnets(self,type):
"""
获取事件
:param type:
:return:
"""
if type == 1:
# 大事记
url = f'http://jintian.160.com/ashx/GreatThing.ashx?act=getgreatthinglist&page=1&m={self.month}&d={self.day}&c=dsj'
elif type == 2:
# 出生
url = f'http://jintian.160.com/ashx/GreatThing.ashx?act=getgreatthinglist&page=1&m={self.month}&d={self.day}&c=cs'
elif type == 3:
# 逝世
url = f'http://jintian.160.com/ashx/GreatThing.ashx?act=getgreatthinglist&page=1&m={self.month}&d={self.day}&c=ss'
sum_page_num=self.get_sum_page_num(url)
event_list = []
for i in range(1,sum_page_num+1):
new_url=url.replace('&page=1',f'&page={i}')
html = self.get_html(new_url)
if html:
_json=json.loads(html)
data=_json.get('data')
res=etree.HTML(data)
selector=res.xpath('//body/li')
for data in selector:
item={}
title1=data.xpath('./a/@title')
if title1:
event=self.title_clean(''.join(title1))
link = data.xpath('./a/@href')
item['link'] = urljoin(url, ''.join(link))
else:
event=data.xpath('./text()')
item['link'] = None
item['event'] = self.title_clean(''.join(event))
event_list.append(item)
try:
new_list=sorted(event_list,key=lambda a:int(a['event'].split('年')[0]),reverse=False)
return new_list
except:
return event_list
def get_event_detail(self,url):
# url='http://jintian.160.com/dsj/10/6/p2/19467.html#wz'
if url==None:
return "没有详细介绍哦~"
html=self.get_html(url)
res=etree.HTML(html)
content=res.xpath('//div[@class="news_box2"]/div[@id="gContent"]/p/text()')
if len(content)!=0:
return '\n'.join(content)
else:
return "没有详细介绍哦~"
五.总结
使用PyQT5制作了一款GUI,用于查看历史上某天发生的重大事件,程序打包好,放在了蓝奏云,欢迎各位使用、测试!思路、代码方面有什么不足欢迎各位大佬指正、批评!