1 '''
2 使用matplotlib創建圖表,並顯示在tk窗口
3 '''
4 import matplotlib.pyplot as plt
5 from matplotlib.pylab import mpl
6 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
7 import tkinter as tk
8 import numpy as np
9 import time,sys
10 import threading
11
12 mpl.rcParams['font.sans-serif'] = ['SimHei'] # 中文顯示
13 mpl.rcParams['axes.unicode_minus'] = False # 負號顯示
14
15 global win
16 global tempGraphLabel, tempData, runFlag
17 runFlag = True
18 tempData = []
19
20 '''
21 圖表類,定義時參數root為父控件
22 '''
23 class tempGraph():
24 def __init__(self, root):
25 self.root = root # 主窗體
26 self.canvas = tk.Canvas() # 創建一塊顯示圖形的畫布
27 self.figure = self.create_matplotlib() # 返回matplotlib所畫圖形的figure對象
28 self.showGraphIn(self.figure) # 將figure顯示在tkinter窗體上面
29
30 '''生成fig'''
31 def create_matplotlib(self):
32 # 創建繪圖對象f
33 f = plt.figure(num=2, figsize=(16, 8), dpi=100, edgecolor='green', frameon=True)
34 # 創建一副子圖
35 self.fig11 = plt.subplot(1, 1, 1)
36 self.line11, = self.fig11.plot([], [])
37
38 def setLabel(fig, title, titleColor="red"):
39 fig.set_title(title+"溫度曲線", color=titleColor) # 設置標題
40 fig.set_xlabel('時間[s]') # 設置x軸標簽
41 fig.set_ylabel("溫度[℃]") # 設置y軸標簽
42 setLabel(self.fig11, "設備1")
43 # fig1.set_yticks([-1, -1 / 2, 0, 1 / 2, 1]) # 設置坐標軸刻度
44 f.tight_layout() # 自動緊湊布局
45 return f
46
47 '''把fig顯示到tkinter'''
48 def showGraphIn(self, figure):
49 # 把繪制的圖形顯示到tkinter窗口上
50 self.canvas = FigureCanvasTkAgg(figure, self.root)
51 self.canvas.draw() # 以前的版本使用show()方法,matplotlib 2.2之后不再推薦show()用draw代替,但是用show不會報錯,會顯示警告
52 self.canvas.get_tk_widget().pack(side=tk.TOP) #, fill=tk.BOTH, expand=1
53
54 # 把matplotlib繪制圖形的導航工具欄顯示到tkinter窗口上
55 toolbar = NavigationToolbar2Tk(self.canvas,
56 self.root) # matplotlib 2.2版本之后推薦使用NavigationToolbar2Tk,若使用NavigationToolbar2TkAgg會警告
57 toolbar.update()
58 self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
59
60 '''更新fig'''
61 def updateMeltGraph(self, meltData):
62 x = [i for i in range(len(meltData))]
63 self.line11.set_xdata(x) # x軸也必須更新
64 self.line11.set_ydata(meltData) # 更新y軸數據
65 # 更新x數據,但未更新繪圖范圍。當我把新數據放在繪圖上時,它完全超出了范圍。解決辦法是增加:
66 self.fig11.relim()
67 self.fig11.autoscale_view()
68 plt.draw()
69 # self.canvas.draw_idle()
70 '''
71 更新數據,在次線程中運行
72 '''
73 def updataData():
74 global tempData,runFlag
75 while runFlag:
76 tempData.append(5)
77 time.sleep(1)
78 '''
79 更新窗口
80 '''
81 def updateWindow():
82 global win
83 global tempGraphLabel, tempData, runFlag
84 if runFlag:
85 tempGraphLabel.updateMeltGraph(tempData)
86 win.after(1000, updateWindow) # 1000ms更新畫布
87 '''
88 關閉窗口觸發函數,關閉S7連接,置位flag
89 '''
90 def closeWindow():
91 global runFlag
92 runFlag = False
93 sys.exit()
94 '''
95 創建控件
96 '''
97 def createGUI():
98 global win
99 win = tk.Tk()
100 displayWidth = win.winfo_screenwidth() # 獲取屏幕寬度
101 displayHeight = win.winfo_screenheight()
102 winWidth, winHeight = displayWidth, displayHeight - 70
103 winX, winY = -8, 0
104 # winX, winY = int((displayWidth - winWidth) /
105 # 2), int((displayHeight - winHeight - 70) / 2)
106 win.title("窗口標題")
107 win.geometry(
108 '%dx%d-%d+%d' %
109 (winWidth,
110 winHeight,
111 winX, winY)) # %dx%d寬度x 高度+橫向偏移量(距左邊)+縱向偏移量(距上邊)
112 # win.resizable(0, 0) # 不使能最大化
113 win.protocol("WM_DELETE_WINDOW", closeWindow)
114 # win.iconbitmap(r'resource/images/motor.ico') # 窗口圖標
115
116 graphFrame = tk.Frame(win) # 創建圖表控件
117 graphFrame.place(x=0, y=0)
118 global tempGraphLabel
119 tempGraphLabel = tempGraph(graphFrame)
120
121 recv_data = threading.Thread(target=updataData) # 開啟線程
122 recv_data.start()
123
124 updateWindow() # 更新畫布
125 win.mainloop()
126
127 if __name__ == '__main__':
128 createGUI()