日歷(QCalendarWidget)+爬蟲API調用+自定義發送信號(傳入2個參數)
總體介紹
QCalendarWidget類提供了一個基日歷小部件,允許用戶選擇一個日期。
該小部件使用當前的月份和年份進行初始化,但是QCalendarWidget提供了幾個公共槽函數來更改顯示的年份和月份。
默認情況下,選擇今天的日期,用戶可以使用鼠標和鍵盤選擇日期。當前選擇的日期可以使用selectedDate()函數進行檢索。
通過設置minimumDate和maximumDate屬性,可以將用戶選擇約束到給定的日期范圍。或者,可以使用setDateRange()函數一次性設置這兩個屬性。
將selectionMode屬性設置為NoSelection以禁止用戶選擇。請注意,還可以使用setSelectedDate()可以讓程序選擇日期。
當前顯示的月份和年份可分別使用monthShown()和yearShown()函數進行檢索。
新創建的日歷小部件使用縮短的日期名稱,星期六和星期日都標記為紅色。日歷網格不可見。顯示星期編號,第一個列。日是日歷區域設置的第一天。
通過將horizontalHeaderFormat屬性設置為QCalendarWidget.SingleLetterDayNames,可以將日期的符號更改為單個字母縮寫(“M”代表“Monday”)。將相同的屬性設置為QCalendarWidget.LongDayNames將使標題顯示完整的日期名稱。可以通過將verticalHeaderFormat屬性設置為QCalendarWidget. NoVerticalHeader來刪除周數。日歷網格可以通過使用setGridVisible()函數將gridVisible屬性設置為True來開啟。
calendar = QCalendarWidget(self)
calendar.setGridVisible(True)
最后,可以使用setFirstDayOfWeek()函數更改第一列中的日期。
QCalendarWidget類還提供了三個信號,selectionChanged(),activated()和currentPageChanged(),可以響應用戶交互。
通過設置QTextCharFormat的一些特殊的工作日,特殊的日期或頭文件的渲染,可以在很大程度上定制標題,工作日或單日的渲染。
日歷小部件只使用QTextCharFormat中的一部分屬性。目前,使用前景,背景和字體屬性來確定窗口小部件中單個單元格的渲染。
一些QCalendarWidget設置的介紹
QCalendarWidget.HorizontalHeaderFormat
定義了水平頭可以顯示的各種格式。
QCalendarWidget.SelectionMode
描述了提供給用戶在日歷中選擇日期的選擇類型
QCalendarWidget.VerticalHeaderFormat
定義了垂直標題可以顯示的各種格式。
更多詳細的介紹,請見官方文檔:QCalendarWidget Class
類的歸屬
PyQt5->QtWidgets->QCalendarWidget
繼承:QWidget
小例子
我們先通過一個小動畫來看一下今天的完成效果:

核心代碼
程序的界面是由Qt設計師完成的,具體的設計大家可以自行去看源碼就知道了,這里主要把功能介紹一下。
class Dialog_selected(QDialog, Ui_Dialog): """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(Dialog_selected, self).__init__(parent) self.setupUi(self) self. appkey = "你的appkey" @pyqtSlot(QDate) def on_calendarWidget_clicked(self, date): """ Slot documentation goes here. @param date DESCRIPTION @type QDate """ date = self.calendarWidget.selectedDate().toString("yyyy-MM-dd dddd") self.request1(self.appkey, date) def request1(self, appkey, date): url = "http://v.juhe.cn/laohuangli/d" params = { "key" : appkey, #應用APPKEY(應用詳細頁查詢) "date" : date #日期,格式2014-09-09 } f = requests.get(url, params=params) content = f.text res = json.loads(content) if res: error_code = res["error_code"] data = res["result"] if error_code == 0: #成功請求 self.label.setText("陽歷:" + date) self.label_2.setText("陰歷:" + data["yinli"]) self.label_3.setText("忌:" + data["ji"]) self.label_4.setText("宜:" + data["yi"]) else: QMessageBox.Warning(self, "警告", "錯誤代碼:" + res["error_code"] + "錯誤原因:" + res["reason"]) else: QMessageBox.Warning(self,"警告","API請求失敗")
這段代碼有一半是有eric6自動生成的。on_calendarWidget_clicked(self, date)的部分和request1(self, appkey, date)是我自己改寫的。
主要功能就是我們單擊日歷上的日期然后會出現對應的陽歷、陰歷、忌、宜等黃歷信息。這只是一個示例程序,實現上也比較簡單。
這里我不用eric6又重新完全用代碼寫了一遍,
效果如下:
完整代碼如下:

1 from PyQt5.QtWidgets import (QApplication,QWidget,QCalendarWidget,QLabel,QSlider,QGridLayout) 2 from PyQt5.QtCore import Qt,pyqtSignal 3 import sys,requests,json 4 5 class Example(QWidget): 6 _signal = pyqtSignal(str,str) 7 def __init__(self): 8 super(Example, self).__init__() 9 self.initUI() 10 11 def initUI(self): 12 self.setGeometry(300,300,450,380) 13 self.setWindowTitle("QCalendarWidget日歷+爬蟲") 14 gridLayout = QGridLayout() 15 self.calendar = QCalendarWidget() 16 self.calendar.setGridVisible(True) 17 self.lb11 = QLabel("陽歷:") 18 self.lb12 = QLabel("") 19 self.lb21 = QLabel("陰歷:") 20 self.lb22 = QLabel("") 21 self.lb31 = QLabel("五行:") 22 self.lb32 = QLabel("") 23 self.lb41 = QLabel("沖煞:") 24 self.lb42 = QLabel("") 25 self.lb51 = QLabel("彭祖百忌:") 26 self.lb52 = QLabel("") 27 self.lb61 = QLabel("吉神:") 28 self.lb62 = QLabel("") 29 self.lb71 = QLabel("宜:") 30 self.lb72 = QLabel("") 31 self.lb81 = QLabel("凶神:") 32 self.lb82 = QLabel("") 33 self.lb91 = QLabel("忌:") 34 self.lb92 = QLabel("") 35 gridLayout.addWidget(self.calendar,0,0,1,3) 36 gridLayout.addWidget(self.lb11,1,0,1,1) 37 gridLayout.addWidget(self.lb12,1,1,1,2) 38 gridLayout.addWidget(self.lb21,2,0,1,1) 39 gridLayout.addWidget(self.lb22,2,1,1,2) 40 gridLayout.addWidget(self.lb31,3,0,1,1) 41 gridLayout.addWidget(self.lb32,3,1,1,2) 42 gridLayout.addWidget(self.lb41, 4, 0, 1, 1) 43 gridLayout.addWidget(self.lb42, 4, 1, 1, 2) 44 gridLayout.addWidget(self.lb51, 5, 0, 1, 1) 45 gridLayout.addWidget(self.lb52, 5, 1, 1, 2) 46 gridLayout.addWidget(self.lb61, 6, 0, 1, 1) 47 gridLayout.addWidget(self.lb62, 6, 1, 1, 2) 48 gridLayout.addWidget(self.lb71, 7, 0, 1, 1) 49 gridLayout.addWidget(self.lb72, 7, 1, 1, 2) 50 gridLayout.addWidget(self.lb81, 8, 0, 1, 1) 51 gridLayout.addWidget(self.lb82, 8, 1, 1, 2) 52 gridLayout.addWidget(self.lb91, 9, 0, 1, 1) 53 gridLayout.addWidget(self.lb92, 9, 1, 1, 2) 54 self.setLayout(gridLayout) 55 56 self.calendar.selectionChanged.connect(self.mySignal) 57 self._signal.connect(self.request1) 58 59 def mySignal(self): 60 # print(self.calendar.selectedDate()) 61 self.date = self.calendar.selectedDate().toString("yyyy-MM-dd") 62 self.appkey = "3f669268cbe38f049f9f20877c127bcf" 63 self._signal.emit(self.appkey,self.date) 64 65 # 日歷 66 def request1(self,appkey,date): 67 try: 68 url = "http://v.juhe.cn/laohuangli/d" 69 params = { 70 "key": appkey, # 應用APPKEY(應用詳細頁查詢) 71 "date": date, # 日期,格式2014-09-09 72 } 73 req = requests.get(url, params=params) 74 req.encoding = 'utf8' 75 content = req.text # 得到的content是str格式,使用json.loads() 將其轉為dict字典格式 76 # print(content) 77 res = json.loads(content) 78 if res: 79 error_code = res["error_code"] 80 if error_code == 0: 81 # 成功請求 82 self.lb12.setText(res["result"]["yangli"]) 83 self.lb22.setText(res["result"]["yinli"]) 84 self.lb32.setText(res["result"]["wuxing"]) 85 self.lb42.setText(res["result"]["chongsha"]) 86 self.lb52.setText(res["result"]["baiji"]) 87 self.lb62.setText(res["result"]["jishen"]) 88 self.lb72.setText(res["result"]["yi"]) 89 self.lb82.setText(res["result"]["xiongshen"]) 90 self.lb92.setText(res["result"]["ji"]) 91 else: 92 print("%s:%s" % (res["error_code"], res["reason"])) 93 else: 94 print("request api error") 95 except: 96 pass 97 98 99 if __name__ == '__main__': 100 app = QApplication(sys.argv) 101 ex = Example() 102 ex.show() 103 sys.exit(app.exec_())
======================================================================================================================================================================================================
@pyqtSlot(QDate)def on_calendarWidget_clicked(self, date): """ Slot documentation goes here. @param date DESCRIPTION @type QDate """ date = self.calendarWidget.selectedDate().toString("yyyy-MM-dd dddd") self.request1(self.appkey, date)
為什么要加上@pyqtSlot(QDate)可以參考
學點編程吧:PyQt5番外篇(2-2):沖頂大會語音答題輔助小工具之解析篇——界面搭建
理解起來差不多。
date = self.calendarWidget.selectedDate().toString("yyyy-MM-dd") self.request1(self.appkey, date)
- 第一句就是將我們選擇的日期格式轉換成字符串,並將它的格式設置為:2018-02-11。
- 第二句就是調用request1()這個函數,並將appkey和date傳值過去。
def request1(self, appkey, date): url = "http://v.juhe.cn/laohuangli/d" params = { "key" : appkey, #應用APPKEY(應用詳細頁查詢) "date" : date #日期,格式2014-09-09 } f = requests.get(url, params=params) content = f.text res = json.loads(content) if res: error_code = res["error_code"] data = res["result"] if error_code == 0: #成功請求 self.label.setText("陽歷:" + date) self.label_2.setText("陰歷:" + data["yinli"]) self.label_3.setText("忌:" + data["ji"]) self.label_4.setText("宜:" + data["yi"]) else: QMessageBox.Warning(self, "警告", "錯誤代碼:" + res["error_code"] + "錯誤原因:" + res["reason"]) else: QMessageBox.Warning(self,"警告","API請求失敗")
這個就是根據我們選擇的日期得到對應的黃歷信息。那么這個黃歷信息怎么來的呢?我不知道!
這里使用的聚合數據的老黃歷API:
https://www.juhe.cn/docs/api/id/65
提供了Python語言的調用方式(我看了一下是Python2的),對於測試而言使用比較方便。但是要經常使用的只能付費了,但是對我們來說夠用了。
Python3的調用方式如下:

1 import json,requests 2 3 # ---------------------------------- 4 # 老黃歷調用示例代碼 - 聚合數據 5 # 在線接口文檔:http://www.juhe.cn/docs/65 6 # ---------------------------------- 7 8 def main(): 9 # 配置您申請的APPKey 10 appkey = "3f669268cbe38f049f9f20877c127bcf" 11 # 1.日歷 12 request1(appkey,"2019-1-4") 13 # 2.時辰 14 request2(appkey) 15 16 # 日歷 17 def request1(appkey,date): 18 url = "http://v.juhe.cn/laohuangli/d" 19 params = { 20 "key": appkey, # 應用APPKEY(應用詳細頁查詢) 21 "date": date, # 日期,格式2014-09-09 22 } 23 req = requests.get(url,params=params) 24 req.encoding = 'utf8' 25 content = req.text #得到的content是str格式,使用json.loads() 將其轉為dict字典格式 26 print(content) 27 res = json.loads(content) 28 if res: 29 error_code = res["error_code"] 30 if error_code == 0: 31 # 成功請求 32 print(res["result"]) 33 else: 34 print("%s:%s" % (res["error_code"], res["reason"])) 35 else: 36 print("request api error") 37 38 # 時辰 39 def request2(appkey): 40 url = "http://v.juhe.cn/laohuangli/h" 41 params = { 42 "key": appkey, # 應用APPKEY(應用詳細頁查詢) 43 "date": "2019-1-4", # 日期,格式2014-09-09 44 } 45 req = requests.get(url,params=params) 46 content = req.text 47 res = json.loads(content) 48 if res: 49 error_code = res["error_code"] 50 if error_code == 0: 51 # 成功請求 52 print(res["result"]) 53 else: 54 print("%s:%s" % (res["error_code"], res["reason"])) 55 else: 56 print("request api error") 57 58 59 if __name__ == '__main__': 60 main()
這里我使用requests這個優秀的第三方庫進行HTTP請求,它的返回值是json格式的,我們可以將其轉換成Python的字典。
if res: error_code = res["error_code"] data = res["result"] if error_code == 0: #成功請求 self.label.setText("陽歷:" + date) self.label_2.setText("陰歷:" + data["yinli"]) self.label_3.setText("忌:" + data["ji"]) self.label_4.setText("宜:" + data["yi"]) else: QMessageBox.Warning(self, "警告", "錯誤代碼:" + res["error_code"] + "錯誤原因:" + res["reason"]) else: QMessageBox.Warning(self,"警告","API請求失敗")
這里我們根據返回值的情況將其與界面上的4個Label標簽關聯並加以顯示出來。如果遇到問題則彈出相應的對話框加以顯示。
最后
這里有一個小問題,算是給大家留一個作業吧!
我們開始打開程序的時候是這樣的,什么陽歷、陰歷、忌、宜這些信息都沒有。
那么我們如何讓它們一打開程序就能顯示出來呢?