【前言】前幾日通過編寫命令行通訊錄,掌握了Python的基本語法結構,於是開始向更高水平沖擊,利用Eric與Qt Designer 編寫一個帶界面的小程序。本次實操中也確實遇到了不少問題,通過學習也都解決了,達到了學習進步的目的。
【吐槽】寫博客比編程序難多了,程序寫了一下午,博客寫了一整天,這么費力的寫出來,希望可以幫助到一些剛開始學習Python的朋友。由於我不是科班出身,編程純屬業余愛好,所以也是一邊學一邊編的,有不足的地方還請批評指正。
1.目標
編寫一個倒計時時鍾程序,用餅圖的形式顯示一天、一周、一個月以及一年已經過了多少時間還剩多少時間,用於提醒人珍惜時間。
2.實現方法
- 由於准庫time模塊不能繼承,創建一個新的時間的類,使用標准庫time模塊來進行時間的相關操作。
- 使用Eric與Qt Designer開發
- 使用matplotlib的pie函數繪制餅圖
3.菜鳥難點
- 對time模塊不熟悉,不知如何使用。
- Qt Designer的使用。
- Qt中添加matplotlib組件窗口。
3.1 time模塊
time 模塊提供了一些處理日期和一天內時間的函數。它是建立在 C 運行時庫的簡單封裝。
給定的日期和時間可以被表示為浮點型(從參考時間, 通常是 1970.1.1 到現在經過的秒數,即 Unix 格式),或者一個表示時間的 struct (類元組)。
方法
3.1.1 time()
返回從1970.1.1 到現在經過的秒數
>>> import time
>>> time.time()
1471794516.136771
3.1.2 localtime()
返回元組形式的時間,
>>> import time
>>> time.localtime()
time.struct_time(tm_year=2016, tm_mon=8, tm_mday=21, tm_hour=23, tm_min=49, tm_sec=57, tm_wday=6, tm_yday=234, tm_isdst=0)
名稱 | 含義 |
---|---|
tm_year | 年 |
tm_mon | 月 |
tm_mday | 日 |
tm_hour | 時 |
tm_min | 分 |
tm_sec | 秒 |
tm_wday | 周幾(0-6) |
tm_yday | 一年中的第幾天 |
tm_isdst | -1代表系統判斷是否為夏時令 0代表非夏時令 1代表夏時令 |
3.1.3 ctime()
返回字符串形式的時間
>>> import time
>>> time.ctime()
'Sun Aug 21 23:50:56 2016'
3.1.4 strptime()
將字符串形式的時間轉換成元組形式的時間
符號 | 含義 |
---|---|
%y | 兩位數年份(00-99 ) |
%Y | 四位數年份(000-9999 ) |
%m | 月份(01-12) |
%d | 日期 0-31 |
%H | 24小時制小時數( 0-23 ) |
%I | 12小時制小時數( 01-12 ) |
%M | 分鍾數(00-59) |
%S | 秒(00-59) |
%a | 本地星期簡化名稱 |
%A | 本地星期完整名稱 |
%b | 本地月份簡化名稱 |
%B | 本地月份完整名稱 |
%c | 本地相應的日期表示和時間表示 |
%j | 年內的第幾天(001-366) |
%p | 本地A.M.或 P.M. |
%U | 一年中的星期數(00-53),星期天為星期的開始 |
%w | 星期(0-6),星期天為星期的開始 |
%W | 一年中的星期數(00-53),星期一為星期的開始 |
%x | 本地相應的日期表示 |
%X | 本地相應的時間表示 |
%Z | 當前時區名稱 |
%% | %號 |
>>> import time
>>> time.strptime('20160821','%Y%m%d')
time.struct_time(tm_year=2016, tm_mon=8, tm_mday=21, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=234, tm_isdst=-1)
3.1.5 strftime()
將元組形式的字符串按照指定格式轉換成字符串形式
>>> import time
>>> time.strftime('%Y%m%d',(2016,8,21,0,0,0,6,234,0))
'20160821'
3.1.6 mktime()
講元組形式的時間轉換成從19700101累計的秒數
>>> import time
>>> time.mktime((2016,8,21,0,0,0,6,234,0))
1471708800.0
3.2 Eirc與Qt Designer的使用
本部分結合項目編寫一起講解。
3.3Qt中添加matplotlib組件窗口
在Qt中添加matplotlib組件窗口需要創建一個新的類mplwidget,在這個類中創建matplotlib的畫布,然后在Qt designer中添加一個普通的Widget,然后將這個widget提升為我們所建的類mplwidget。
4.項目編寫
4.1 創建項目
- 打開Eric,單擊菜單欄【項目】-【新建】
- 輸入“項目名稱”,選擇“項目文件夾”,點擊【OK】
4.2創建窗體
- 在Eric“項目瀏覽器”的“窗體”中,單擊右鍵,選擇【新建窗體】
- 選擇窗體類型“主窗口”,點擊【OK】
- 輸入窗體文件名,點擊【Save】
- 在項目瀏覽器中,右鍵點擊新建的.ui窗體文件,選擇【在Qt設計師中打開】
- 打開Qt Designer后,會有幾個基本的窗口,你自己的窗口“MainWindow”、“窗口部件盒”、“對象查看器”、“屬性編輯器”,其他的窗口可從菜單欄“視圖”窗口選擇。
拖拽“MainWindows”設置窗口的初始大小
從“窗口部件盒”拖4個Widget到“MainWindow”
- 在“MainWindow”4個Widget以外的地方單擊右鍵,選擇【布局】-【水平布局】
- 在一個Widget上單擊右鍵,選擇【提升為】
- 在“提升的類名稱”中輸入要創建的自定義的widget類名稱,點擊【添加】
- 選中“提升的類”中新建的那個類,點擊【提升】
- 選中Widget組件,在右側的“屬性編輯器”中將objectName改為mpl···Widget
- 保存文件,退出Qt Designer。
- 右擊Eric“項目瀏覽器”中的.ui窗體文件,選擇【編譯窗體】,生成文件Ui_countdownmainwindow.py
- 打開生成的文件,將
from mplpiewidget import MplPieWidget
剪切至class Ui_MainWindow(object):
上面,保存文件。
4.4 自定義Widget類的編寫
- 單擊Eric工具欄新建按鈕,創建一個空白文檔,保存為名為‘mplpiewidget.py’的文件。
- 偽代碼
# 導入PyQt5的圖形界面組件模塊QtGui,非圖形類模塊QtCore,基礎界面控件模塊QtWidgets,
# 導入matplotlib庫中qt5后端,用於實現在qt5的組件里繪制matplotlib圖像。
# 導入matplotlib的figure模塊,figure模塊包含所有畫圖的元素。
# 創建matplotlib的畫布類MplCanvas,繼承於qt5agg的figurecanvas
#初始化
#創建figure,Axis
#超類初始化
#將widget設置成expandable,隨窗口變化
#系統更新widget設置
#創建自定義widget類MplPieWidget,繼承於QtWidget.QWidget
#初始化
#超類初始化
#創建MplCanvas實例畫布
#創建垂直布局的容器
#在容器中添加畫布
#設置垂直布局生效
- 編寫代碼
# 導入PyQt5的圖形界面組件模塊QtGui,非圖形類模塊QtCore,基礎界面控件模塊QtWidgets,
from PyQt5 import QtGui, QtCore, QtWidgets
# 導入matplotlib庫中qt5后端,用於實現在qt5的組件里繪制matplotlib圖像。
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
# 導入matplotlib的figure模塊,figure模塊包含所有畫圖的元素。
from matplotlib.figure import Figure
# 創建matplotlib的畫布類MplCanvas,繼承於qt5agg的figurecanvas
class MplCanvas(FigureCanvas):
#初始化
def __init__(self):
#創建figure,Axis
self.fig= Figure()
self.ax= self.fig.add_subplot(111)
#超類初始化
FigureCanvas.__init__(self,self.fig)
#將widget設置成expandable,隨窗口變化
FigureCanvas.setSizePolicy(self,\
QtWidgets.QSizePolicy.Expanding,\
QtWidgets.QSizePolicy.Expanding)
#系統更新widget設置
FigureCanvas.updateGeometry(self)
#創建自定義widget類MplPieWidget,繼承於QtWidget.QWidget
class MplPieWidget(QtWidgets.QWidget):
#初始化
def __init__(self, parent= None):
#超類初始化
QtWidgets.QWidget.__init__(self,parent)
#創建MplCanvas實例畫布
self.canvas= MplCanvas()
#創建垂直布局的容器
self.vbl= QtWidgets.QVBoxLayout()
#在容器中添加畫布
self.vbl.addWidget(self.canvas)
#設置垂直布局生效
self.setLayout(self.vbl)
4.4 Time類編寫
- 單擊Eric工具欄新建按鈕,創建一個空白文檔,保存為名為‘mytime.py’的文件。
- 偽代碼
#導入time模塊
#創建Time類
#獲取現在的年、月、日、時、分、秒、星期以及今天是今年的第幾天
#將值賦給year,month,day,hour,minute,second,weekday,yearday
#創建一個方法,根據是不是閏年返回今年的總天數
#if year能夠被400整除:
#天數為366
#elif year能被100整除:
#天數為365
#elif year能被4整除:
#天數為366
#else:
#天數為365
#返回天數
#創建本年天數變量daysOfYear
#創建一個方法,返回本月天數
#if month是1,3,5,7,8,10,12月:
#天數為31
#elif month是4,6,9,11月:
#天數是30
#elif 今年是閏年:
#天數為29
#else:
#天數為28
#返回天數
#創建本月天數變量daysOfMonth
#創建一個方法,將字符串形式時間轉換成時間戳
#將year,month,day轉換成字符串連在一起
#將時間戳形式時間返回
#將今天的時間(時分秒)換算成秒數
- 編寫代碼
#導入time模塊
import time
#創建Time類
class Time(object):
#獲取現在的年、月、日、時、分、秒、星期以及今天是今年的第幾天
#將值賦給year,month,day,hour,minute,second,weekday,yearday
localTime= time.localtime()
year,month,day,hour,minute,second,weekday,yearday= localTime[0:-1]
#創建一個方法,根據是不是閏年返回今年的總天數
def totalDaysOfYear(year):
#if year能夠被400整除:
if year% 400== 0:
#天數為366
totalDays= 366
#elif year能被100整除:
elif year% 100== 0:
#天數為365
totalDays= 365
#elif year能被4整除:
elif year% 4== 0:
#天數為366
totalDays= 366
#else:
else:
#天數為365
totalDays= 365
#返回天數
return totalDays
#創建本年天數變量daysOfYear
daysOfYear= totalDaysOfYear(year)
#創建一個方法,返回本月天數
def totalDaysOfMonth(month):
#if month是1,3,5,7,8,10,12月:
if month in [1,3,5,7,8,10,12]:
#天數為31
totalDays= 31
#elif month是4,6,9,11月:
elif month in [4,6,9,11]:
#天數是30
totalDays= 30
#elif 今年是閏年:
elif self.daysOfYear== 366:
#天數為29
totalDays= 29
#else:
else:
#天數為28
totalDays= 28
#返回天數
return totalDays
#創建本月天數變量daysOfMonth
daysOfMonth= totalDaysOfMonth(month)
#創建一個方法,將字符串形式時間轉換成時間戳
def transformTime(year,month,day):
#將year,month,day轉換成字符串連在一起
nowtime= str(year)+ '-'+ str(month)+ '-'+ str(day)
#將時間戳形式時間返回
return time.mktime(time.strptime(nowtime,'%Y-%m-%d'))
#將今天的時間(時分秒)換算成秒數
secondsOfTheDay= time.time()- transformTime(year,month,day)
4.5 主程序編寫
1.Eric“項目瀏覽器”右擊.ui文件選擇【生成對話框代碼】
2.選擇【新建】類名
3.單擊【OK】,項目中生成名為countdownmainwindow.py的文件
4.編輯countdownmainwindow.py
- 將
from .Ui_countdownmainwindow import Ui_MainWindow
改為from Ui_countdownmainwindow import Ui_MainWindow
- 導入我們寫的Time類
from mytime import Time
- 創建一個繪制餅圖的方法
def plotPie(self,widget,list,colors):
widget.canvas.ax.clear()
widget.canvas.ax.pie(list,explode= None, labels= None, colors= colors, \
labeldistance= 1.1, autopct= None,shadow= False, \
startangle= 90, pctdistance= 0.6)
widget.canvas.draw()
- 創建列表,用於繪制餅圖及設置餅圖顏色
#創建年列表=[今年剩余天數,已過天數]
yearList= [Time.daysOfYear- Time.yearday, Time.yearday]
yearColorsList= ['blue','gray']
#創建月列表=[本月剩余天數,已過天數]
monthList= [Time.daysOfMonth- Time.day, Time.day]
monthColorsList= ['blue','gray']
#創建周列表=[本周剩余天數,已過天數]
weekList= [6-Time.weekday, Time.weekday+1]
weekColorsList= ['blue','gray']
#創建日列表-[本天剩余秒數,已過秒數]
dayList= [24*60*60- Time.secondsOfTheDay, Time.secondsOfTheDay]
dayColorsList= ['blue','gray']
- 在__init__方法中添加繪制餅圖的方法
def __init__(self, parent=None):
"""
Constructor
@param parent reference to the parent widget
@type QWidget
"""
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.plotPie(self.mplYearWidget,ListOfPie.yearList,['blue','gray'])
self.plotPie(self.mplMonthWidget,ListOfPie.monthList,['blue','gray'])
self.plotPie(self.mplWeekWidget,ListOfPie.weekList,['blue','gray'])
self.plotPie(self.mplDayWidget,ListOfPie.dayList,['blue','gray'])
- 在最后添加如下代碼,將主窗口顯示出來。
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
- 完整代碼為:
# -*- coding: utf-8 -*-
"""
Module implementing MainWindow.
"""
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QMainWindow
from countdown import ListOfPie
from Ui_CountdownMainWindow import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
"""
Class documentation goes here.
"""
def __init__(self, parent=None):
"""
Constructor
@param parent reference to the parent widget
@type QWidget
"""
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.plotPie(self.mplYearWidget,ListOfPie.yearList,['blue','gray'])
self.plotPie(self.mplMonthWidget,ListOfPie.monthList,['blue','gray'])
self.plotPie(self.mplWeekWidget,ListOfPie.weekList,['blue','gray'])
self.plotPie(self.mplDayWidget,ListOfPie.dayList,['blue','gray'])
def plotPie(self,widget,list,colors):
widget.canvas.ax.clear()
widget.canvas.ax.pie(list,explode= None, labels= None, colors= colors, \
labeldistance= 1.1, autopct= None,shadow= False, \
startangle= 90, pctdistance= 0.6)
widget.canvas.draw()
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
4.6 程序的調試與運行
- F5鍵為調試程序
選中主程序調試,調試整個項目,如果沒有錯誤直接運行
- F2鍵為直接運行程序
5 程序演示
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
想觀看Matplotlib教學視頻,了解更多Matplotlib實用技巧可關注
微信公眾賬號: MatplotlibClass
今日頭條號:Matplotlib小講堂