目錄
[TOC]
前言
前一章節(jié),我們解讀了tkinter內(nèi)嵌Matplotlib的教程,了解其內(nèi)嵌的原理,就是在tkinter創(chuàng)建matplotlib的畫布控件,再利用其返回的畫布對象進(jìn)行繪圖,其他附加功能,使用tkinter控件實現(xiàn)。
(一)對matplotlib畫布的封裝:
(1)說明:
我們希望對官方的實例代碼進(jìn)行封裝成一個函數(shù),并返回一個畫布對象,外部再調(diào)用該函數(shù),并獲取畫布對象,進(jìn)行繪制操作。
(2)封裝后的代碼:
"""
畫布文件,實現(xiàn)繪圖區(qū)域的顯示,并返回畫布的對象。
"""
import tkinter as tk
# 創(chuàng)建畫布需要的庫
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# 創(chuàng)建工具欄需要的庫
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
# 快捷鍵需要的庫
from matplotlib.backend_bases import key_press_handler
# 導(dǎo)入畫圖常用的庫
from matplotlib.figure import Figure
def plot_fun(root):
"""
該函數(shù)實現(xiàn)的是內(nèi)嵌畫布,不負(fù)責(zé)畫圖,返回畫布對象。
:param root:父親控件對象, 一般是容器控件或者窗體
:return: 畫布對象
"""
# 畫布的大小和分別率
fig = Figure(dpi=100)
axs = fig.add_subplot(111)
# 創(chuàng)建畫布
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
# 顯示畫布
canvas.get_tk_widget().pack()
# 創(chuàng)建工具條
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
# 顯示工具條
canvas.get_tk_widget().pack()
# 調(diào)用快捷鍵
def on_key_press(event):
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect("key_press_event", on_key_press)
# 返回畫布的對象
return axs
(二)思路分析:
1.需求說明:
(1)背景:
作為學(xué)生的我們,你是否有那么一個場景,唉……,這個數(shù)學(xué)函數(shù)好難求哦,要是知道它的圖像這么畫就好了。
(2)需求:
給出數(shù)學(xué)表達(dá)式,繪制出該數(shù)學(xué)表達(dá)式的函數(shù)曲線,一來可以觀察函數(shù)的變化趨勢,二來可以根據(jù)兩條曲線的交點(diǎn),來求解出方程的大致結(jié)果。
2.框架的設(shè)置:
(1)說明:
分模塊編程,向來是眾人所提倡的,再python里更是很好的實現(xiàn)。
再動手敲代碼之前,我們先來大致的設(shè)置一下,小項目的框架。
(2)框架圖解:
01.png
3.文件說明:
(1)main.py
主程序文件,負(fù)責(zé)程序的啟動與結(jié)束和窗體的大致設(shè)置。
(2)widget.py
控件文件,負(fù)責(zé)程序控件的創(chuàng)建與布局
(3)figure.py
畫布文件,實現(xiàn)繪圖區(qū)域的顯示,并返回畫布的對象。
(4)plot.py
繪圖文件,負(fù)責(zé)函數(shù)曲線的繪制
(三)各文件的源代碼
1.main.py
"""
主程序文件,負(fù)責(zé)程序的啟動與結(jié)束和窗體的大致設(shè)置。
"""
import tkinter as tk
import widget
def win_w_h(root):
"""
控制窗口的大小和出現(xiàn)的位置
:param root:
:return: 窗口的大小和出現(xiàn)的位置
"""
# 設(shè)置標(biāo)題:
win.title("數(shù)學(xué)函數(shù)繪圖")
# 繪圖區(qū)標(biāo)簽
label_plot = tk.Label(root, text="繪 圖 區(qū)",
font=("微軟雅黑", 10), fg="blue")
label_plot.place(relx=0.26, rely=0)
label_func = tk.Label(root, text="功 能 區(qū)",
font=("微軟雅黑", 10), fg="blue")
label_func.place(relx=0.75, rely=0)
# 獲取屏幕的大小;
screen_height = root.winfo_screenheight()
screen_width = root.winfo_screenwidth()
# 窗體的大小
win_width = 0.8 * screen_width
win_height = 0.8 * screen_height
# 窗體出現(xiàn)的位置:控制的是左上角的坐標(biāo)
show_width = (screen_width - win_width) / 2
show_height = (screen_height - win_height) / 2
# 返回窗體 坐標(biāo)
return win_width, win_height, show_width, show_height
win = tk.Tk()
# 大小 位置
win.geometry("%dx%d+%d+%d" % (win_w_h(win)))
# 創(chuàng)建一個容器, 沒有畫布時的背景
frame1 = tk.Frame(win, bg="#c0c0c0")
frame1.place(relx=0.00, rely=0.05, relwidth=0.62, relheight=0.89)
# 控件區(qū)
frame2 = tk.Frame(win, bg="#808080")
frame2.place(relx=0.62, rely=0.05, relwidth=0.38, relheight=0.89)
# 調(diào)用控件模塊
widget.widget_main(win, frame2)
win.mainloop()
2.widget.py
"""
控件文件,負(fù)責(zé)程序控件的創(chuàng)建與布局
"""
import tkinter as tk
# 對話框所需的庫
import tkinter.messagebox as mb
# 畫布文件
import figure
# 繪圖文件
import plot
def widget_main(win, root):
"""
負(fù)責(zé)程序控件的創(chuàng)建與布局
:param win: 主窗體的對象。
:param root: 繪圖區(qū)的容器對象。
:return: 無
"""
# 控件區(qū)的容器對象
frame1 = None
# ===========功能區(qū)============================
# 繪圖的功能函數(shù)
def plot_f():
string = entry.get()
# 判斷輸入框是否為空
if string == "":
mb.showerror("提示", "沒有輸入值,請重新輸入:")
else:
# 判斷是否已經(jīng)創(chuàng)建畫布
if frame1==None:
mb.showerror("提示", "沒有創(chuàng)建畫布,不能畫圖,請先創(chuàng)建畫布")
else:
axs = figure.plot_fun(frame1)
plot.plot_main(string, axs)
# 清除的功能函數(shù)
def clear():
nonlocal frame1
entry.delete(0, "end")
if frame1==None:
mb.showerror("提示", "已經(jīng)沒有畫布,無法清除畫布")
else:
frame1.destroy()
frame1 = None
# 創(chuàng)建畫布的功能函數(shù)
def create():
nonlocal frame1
if frame1 != None:
mb.showerror("提示", "畫布已經(jīng)存在,請不要重復(fù)創(chuàng)建畫布")
else:
frame1 = tk.LabelFrame(win, bg="#80ff80", text="畫-----布", labelanchor="n", fg="green")
frame1.place(relx=0.00, rely=0.05, relwidth=0.62, relheight=0.95)
# =============控件區(qū)======================
# 標(biāo)簽控件
label = tk.Label(root,
text="請輸入含x的數(shù)學(xué)公式:",
font=("微軟雅黑", 18),
fg="blue")
label.place(relx=0.2, rely=0.1)
# 輸入框
entry = tk.Entry(root, font=("華文楷體", 15))
entry.place(relx=0.1, rely=0.2, relwidth=0.8)
# 創(chuàng)建畫布區(qū)
btn_draw = tk.Button(root,
text="創(chuàng)建",
cursor="hand2",
width=10,
bg="orange",
relief="raised",
command=create
)
btn_draw.place(relx=0.1, rely=0.3)
# 繪圖按鈕
btn_draw = tk.Button(root,
text="繪圖",
cursor="hand2",
width=10,
bg="green",
relief="raised",
command=plot_f
)
btn_draw.place(relx=0.4, rely=0.3)
# 清除按鈕
btn_clear = tk.Button(root,
text="清除",
cursor="hand2",
width=10,
bg="yellow",
relief="raised",
command=clear
)
btn_clear.place(relx=0.7, rely=0.3)
3.figure.py
"""
畫布文件,實現(xiàn)繪圖區(qū)域的顯示,并返回畫布的對象。
"""
import tkinter as tk
# 創(chuàng)建畫布需要的庫
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# 創(chuàng)建工具欄需要的庫
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
# 快捷鍵需要的庫
from matplotlib.backend_bases import key_press_handler
# 導(dǎo)入畫圖常用的庫
from matplotlib.figure import Figure
def plot_fun(root):
"""
該函數(shù)實現(xiàn)的是內(nèi)嵌畫布,不負(fù)責(zé)畫圖,返回畫布對象。
:param root:父親控件對象, 一般是容器控件或者窗體
:return: 畫布對象
"""
# 畫布的大小和分別率
fig = Figure(dpi=100)
axs = fig.add_subplot(111)
# 創(chuàng)建畫布
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
# 顯示畫布
canvas.get_tk_widget().pack()
# 創(chuàng)建工具條
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
# 顯示工具條
canvas.get_tk_widget().pack()
# 調(diào)用快捷鍵
def on_key_press(event):
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect("key_press_event", on_key_press)
# 返回畫布的對象
return axs
4.plot.py
"""
繪圖文件,負(fù)責(zé)函數(shù)曲線的繪制
"""
import numpy as np
def plot_main(string, plt):
"""
負(fù)責(zé)函數(shù)曲線的繪制
:param string: 數(shù)學(xué)表達(dá)式
:param plt: 畫布的對象
:return: 無
"""
list_expr = []
list_expr = string.split(",")
string1 = []
for sub_expr in list_expr:
string1.append(sub_expr)
x = np.linspace(-10, 10, 100)
y = []
num = string.count('x')
for i in x:
t = (i, ) * num
string = string.replace("x", "(%f)")
i = eval(string % t)
y.append(i)
plt.plot(x, y)
plt.grid(True)
plt.legend(labels=string1)
(四)文件結(jié)構(gòu)
四個文件均處于同一個文件夾下,用main.py來運(yùn)行。
02.png
(五)項目下載:
百度網(wǎng)盤下載
鏈接:https://pan.baidu.com/s/13G_hWqagxqHRkdHaYcxiQQ
提取碼:codq