一、说明:
在 Tkinter 中使用 Matplotlib 的 NavigationToolbar2Tk 时,你可能会注意到它并不直接提供一个名为 editor_options 或 qt4_editor_options 的属性或方法。这是因为 NavigationToolbar2Tk 是为 Tkinter 设计的,而 editor_options 和 qt4_editor_options 通常与基于 Qt 的后端(如 PyQt 或 PySide)相关。所以在Tkinter中以嵌入式Matplotlib图表时,虽然可以用NavigationToolbar2Tk增加它的工具条,但其中会少一个按钮。如下图所示:
原本应有工具条:
在TK中的工具条:
缺少了这个功能:
如果你正在寻找一个类似于在 Qt 界面中编辑图像或图表属性的功能,但在 Tkinter 中实现,你可能需要采取一些不同的方法,因为 Tkinter 本身并不直接支持这些高级功能。
二、可以替代的方法:
不过,这里有几个可能的解决方案或替代方法:
自定义工具栏:
你可以通过继承 NavigationToolbar2Tk 并添加自定义的按钮或方法来扩展工具栏。这些自定义的按钮可以触发函数,这些函数可以修改图表的属性或调用其他编辑功能。
使用其他 GUI 框架:
如果你需要更复杂的图形界面和编辑功能,考虑使用 PyQt 或 PySide 等基于 Qt 的框架。这些框架提供了更丰富的控件和更强大的自定义能力。
弹出对话框:
你可以通过 Tkinter 的 Toplevel 或 simpledialog 模块来创建弹出对话框,让用户可以在对话框中输入或选择图表的编辑选项。然后,你可以根据这些输入来更新图表。
外部工具:
考虑使用外部工具(如 Photoshop、GIMP 或其他图像编辑软件)来编辑图表生成的图像文件。虽然这不是一个自动化的解决方案,但它允许用户利用现有工具的强大功能。
查看 Matplotlib 的源代码:
如果你对 Matplotlib 的 Qt 后端感兴趣,并想了解它是如何实现编辑功能的,你可以查看相关的源代码。这可能会给你一些灵感,以便在 Tkinter 中实现类似的功能。
使用 Web 技术:
另一个现代且灵活的选择是使用基于 Web 的解决方案,如 Plotly、Bokeh 或 Matplotlib 的 WebAgg 后端。这些工具允许你创建交互式图表,并通过 Web 浏览器进行编辑和交互。虽然这涉及到一些额外的设置,但它可以提供更丰富的用户体验。
总之,由于 NavigationToolbar2Tk 是为 Tkinter 设计的,并且 Tkinter 本身并不支持像 Qt 那样的高级编辑功能,因此你可能需要采用上述方法之一来实现所需的编辑功能。
三、自定义汉化工具栏图标并实现它的功能:
我通过自定义工具栏实现其功能,通过修改NavigationToolbar2Tk 中的变量toolitems,可以实现工具条的汉化并将在tk中不能使用的按钮启用。
程序执行结果如下:
点击后出现:
程序中有三个例子,其中例一按以上选择后运行结果为:
例二的运行情况:
完整代码如下:
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from tkinter import colorchooser,BooleanVar,StringVar
import numpy as np
import os
from sys import argv
# 获取当前执行脚本的目录
current_directory = os.path.dirname(argv[0])
# # 改变当前工作目录到脚本所在的目录
os.chdir(current_directory)
plt.rcParams["font.sans-serif"] = ["SimHei"] # 设置字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时负号'-'显示为方块的问题
class MyScale(ttk.Frame):
def __init__(self, master=None, from_=0, to=100, orient='horizontal', 保留小数=0,调整透明度窗口=None,外部类=None,**kwargs):
super().__init__(master, **kwargs)
self.保留小数 = 保留小数
self.调整透明度窗口 =调整透明度窗口
self.外部类 = 外部类
self.位数 = max(len(str(from_)),len(str(to)))+(0 if 保留小数==0 else 保留小数+1)
# 创建 Scale 控件
self.scale = ttk.Scale(self, from_=from_, to=to, orient=orient, command=self.update_label)
self.scale.pack(side=tk.LEFT, fill=tk.X, expand=True) # 使用 pack 布局
# 创建 Label 控件用于显示当前值
self.label = ttk.Label(self, text=" "*self.位数, font=('Consolas', 11)) # Consolas 等宽字体,防止窗口大小自动变化
self.label.pack(side=tk.RIGHT, padx=(0, 5)) # 在 Scale 控件右侧放置 Label,并添加一些内边距
def format_num(self,num=None): # 按等长度输出数据
if num is None:
num = self.scale.get()
if self.保留小数 == 0:
ret = int(round(num,self.保留小数))
else:
ret = round(self.scale.get(),self.保留小数)
ret = ' '*(self.位数-len(str(ret)))+str(ret)
return ret
def update_label(self, *args):
# 当 Scale 的值改变时调用此函数来更新 Label 的文本
self.label.config(text=self.format_num())
if self.外部类 is not None:
self.外部类.窗口透明度 = self.get()
if self.调整透明度窗口 is not None and self.get()>=128:
self.调整透明度窗口.attributes('-alpha',self.get()/255) # 设置窗口的透明度
def set(self,num):
self.scale.set(num)
self.label.config(text=self.format_num(num))
def get(self):
if self.保留小数 == 0:
return int(round(self.scale.get(),self.保留小数))
else:
return round(self.scale.get(),self.保留小数)
class MyToolbar(NavigationToolbar2Tk):
def __init__(self, canvas, parent,fig):
'''参数说明:
canvas:matplotlib在Tk中创建的画板
parent:Tk创建的主窗口,一般由 tk.Tk() 命令创建
fig:matplotlib创建的图形窗口,创建时请赋值给相应变量,然后把其传递到本类中
'''
self.fig = fig
# self.fig = plt.gcf()
self.root = parent
self.当前选择 = 0
self.窗口透明度 = 235
self.初始图表()
self.toolitems = (
('主页', '重置原始视图', 'home', 'home'),
('后退', '返回上一个视图', 'back', 'back'),
('前进', '前进到下一个视图', 'forward', 'forward'),
(None, None, None, None),
('平移', '左键平移,右键缩放\nx/y固定轴,CTRL固定比例', 'move', 'pan'),
('缩放', '缩放到矩形\nx/y固定轴', 'zoom_to_rect', 'zoom'),
('边距', '边距和间隔大小', 'subplots', 'configure_subplots'),
(None, None, None, None),
# 增加在TK中缺少的工具
("参数", "编辑轴、曲线和图像参数", "qt4_editor_options", "open_settings"),
(None, None, None, None),
('保存', '保存图形', 'filesave', 'save_figure'))
# 添加设置控件 : 每个图形的相关参数
self.markers = [
['' , '无标记'],
['.' , '小圆点'],
['o' , '圆形'],
[',' , '像素点'],
['s' , '正方形'],
['p' , '五边形'],
['*' , '五角星'],
['+' , '加号'],
['P' , '粗加号'],
['x' , '叉号'],
['X' , '粗叉号'],
['D' , '菱形'],
['d' , '窄菱形'],
['^' , '三角形(向上)'],
['v' , '三角形(向下)'],
['<' , '三角形(向左)'],
['>' , '三角形(向右)'],
['1' , 'Y形'],
['2' , '反Y形'],
['3' , '左斜Y形'],
['4' , '右斜Y形'],
['_' , '水平线'],
['|' , '竖线'],
['h' , '六边形1'],
['H' , '六边形2'],
['8' , '八边形'],
[0, '左侧刻度'],
[1, '右侧刻度'],
[2, '上侧刻度'],
[3, '下侧刻度'],
[4, '右侧三角形'],
[5, '左侧三角形'],
[6, '下侧三角形'],
[7, '上侧三角形'],
[8, '偏左三角形'],
[9, '偏右三角形'],
[10, '偏上三角形'],
[11, '偏下三角形'] ]
self.marker_descriptions = [f'{desc[0]} {desc[1]}' for desc in self.markers] # 提取描述性文本
self.line_styles = ['-', '--', '-.', ':', 'None']
self.drawstyles=['default', 'steps-pre', 'steps-mid', 'steps-post']
super().__init__(canvas, parent)
def 初始图表(self):
if len(self.fig.axes) > 1:
self.ax=self.fig.axes[self.当前选择]
else:
self.ax = self.fig.gca()
self.objs= self.ax.get_lines()
self.objs2= self.ax.get_children()
# self.坐标轴样式()
print(self.objs2)
self.legend = self.a