目录
目录
前言
前一章节,我们解读了tkinter内嵌Matplotlib的教程,了解其内嵌的原理,就是在tkinter创建matplotlib的画布控件,再利用其返回的画布对象进行绘图,其他附加功能,使用tkinter控件实现。
(一)对matplotlib画布的封装:
(1)说明:
我们希望对官方的实例代码进行封装成一个函数,并返回一个画布对象,外部再调用该函数,并获取画布对象,进行绘制操作。
(2)封装后的代码:
""" 画布文件,实现绘图区域的显示,并返回画布的对象。"""import tkinter as tk# 创建画布需要的库from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg# 创建工具栏需要的库from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk# 快捷键需要的库from matplotlib.backend_bases import key_press_handler# 导入画图常用的库from matplotlib.figure import Figuredef plot_fun(root): """ 该函数实现的是内嵌画布,不负责画图,返回画布对象。 :param root:父亲控件对象, 一般是容器控件或者窗体 :return: 画布对象 """ # 画布的大小和分别率 fig = Figure(dpi=100) axs = fig.add_subplot(111) # 创建画布 canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea. canvas.draw() # 显示画布 canvas.get_tk_widget().pack() # 创建工具条 toolbar = NavigationToolbar2Tk(canvas, root) toolbar.update() # 显示工具条 canvas.get_tk_widget().pack() # 调用快捷键 def on_key_press(event): key_press_handler(event, canvas, toolbar) canvas.mpl_connect("key_press_event", on_key_press) # 返回画布的对象 return axs
(二)思路分析:
1.需求说明:
(1)背景:
作为学生的我们,你是否有那么一个场景,唉……,这个数学函数好难求哦,要是知道它的图像这么画就好了。
(2)需求:
给出数学表达式,绘制出该数学表达式的函数曲线,一来可以观察函数的变化趋势,二来可以根据两条曲线的交点,来求解出方程的大致结果。
2.框架的设置:
(1)说明:
分模块编程,向来是众人所提倡的,再python里更是很好的实现。
再动手敲代码之前,我们先来大致的设置一下,小项目的框架。
(2)框架图解:
3.文件说明:
(1)main.py
主程序文件,负责程序的启动与结束和窗体的大致设置。
(2)widget.py
控件文件,负责程序控件的创建与布局
(3)figure.py
画布文件,实现绘图区域的显示,并返回画布的对象。
(4)plot.py
绘图文件,负责函数曲线的绘制
(三)各文件的源代码
1.main.py
""" 主程序文件,负责程序的启动与结束和窗体的大致设置。"""import tkinter as tkimport widgetdef win_w_h(root): """ 控制窗口的大小和出现的位置 :param root: :return: 窗口的大小和出现的位置 """ # 设置标题: win.title("数学函数绘图") # 绘图区标签 label_plot = tk.Label(root, text="绘 图 区", font=("微软雅黑", 10), fg="blue") label_plot.place(relx=0.26, rely=0) label_func = tk.Label(root, text="功 能 区", 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 # 窗体出现的位置:控制的是左上角的坐标 show_width = (screen_width - win_width) / 2 show_height = (screen_height - win_height) / 2 # 返回窗体 坐标 return win_width, win_height, show_width, show_heightwin = tk.Tk()# 大小 位置win.geometry("%dx%d+%d+%d" % (win_w_h(win)))# 创建一个容器, 没有画布时的背景frame1 = tk.Frame(win, bg="#c0c0c0")frame1.place(relx=0.00, rely=0.05, relwidth=0.62, relheight=0.89)# 控件区frame2 = tk.Frame(win, bg="#808080")frame2.place(relx=0.62, rely=0.05, relwidth=0.38, relheight=0.89)# 调用控件模块widget.widget_main(win, frame2)win.mainloop()
2.widget.py
""" 控件文件,负责程序控件的创建与布局"""import tkinter as tk# 对话框所需的库import tkinter.messagebox as mb# 画布文件import figure# 绘图文件import plotdef widget_main(win, root): """ 负责程序控件的创建与布局 :param win: 主窗体的对象。 :param root: 绘图区的容器对象。 :return: 无 """ # 控件区的容器对象 frame1 = None# ===========功能区============================ # 绘图的功能函数 def plot_f(): string = entry.get() # 判断输入框是否为空 if string == "": mb.showerror("提示", "没有输入值,请重新输入:") else: # 判断是否已经创建画布 if frame1==None: mb.showerror("提示", "没有创建画布,不能画图,请先创建画布") else: axs = figure.plot_fun(frame1) plot.plot_main(string, axs) # 清除的功能函数 def clear(): nonlocal frame1 entry.delete(0, "end") if frame1==None: mb.showerror("提示", "已经没有画布,无法清除画布") else: frame1.destroy() frame1 = None # 创建画布的功能函数 def create(): nonlocal frame1 if frame1 != None: mb.showerror("提示", "画布已经存在,请不要重复创建画布") 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)# =============控件区====================== # 标签控件 label = tk.Label(root, text="请输入含x的数学公式:", 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) # 创建画布区 btn_draw = tk.Button(root, text="创建", 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
""" 画布文件,实现绘图区域的显示,并返回画布的对象。"""import tkinter as tk# 创建画布需要的库from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg# 创建工具栏需要的库from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk# 快捷键需要的库from matplotlib.backend_bases import key_press_handler# 导入画图常用的库from matplotlib.figure import Figuredef plot_fun(root): """ 该函数实现的是内嵌画布,不负责画图,返回画布对象。 :param root:父亲控件对象, 一般是容器控件或者窗体 :return: 画布对象 """ # 画布的大小和分别率 fig = Figure(dpi=100) axs = fig.add_subplot(111) # 创建画布 canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea. canvas.draw() # 显示画布 canvas.get_tk_widget().pack() # 创建工具条 toolbar = NavigationToolbar2Tk(canvas, root) toolbar.update() # 显示工具条 canvas.get_tk_widget().pack() # 调用快捷键 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
""" 绘图文件,负责函数曲线的绘制"""import numpy as npdef plot_main(string, plt): """ 负责函数曲线的绘制 :param string: 数学表达式 :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)
(四)文件结构
四个文件均处于同一个文件夹下,用main.py来运行。
(五)项目下载:
链接:
提取码:codq