python - 动态更新类属性并将其从一个类传递到另一个类
问题描述
我有一个A
包含 matplotlib 画布的类。这个画布是可点击的,即我点击绘图,这会调用一个函数来保存event.x = self.x
. 我有另一个类,只要它们发生变化B
,就应该从类接收属性。我在这篇文章How to trigger function on value change中看到了观察者模式?,我认为这可能是我需要的,但我无法让它运行(见下面的代码)。A
两个类都位于两个 tkk 框架中,但我想这与问题无关。
明确地说,在这个最小的例子中,我想将 , 传递plotFrame.x
给plotFrame.y
类WorkFrame()
。每次我点击绘图时,我都希望在右侧的小标签中看到新的值!
import Tkinter as tk
import ttk
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2TkAgg)
import matplotlib.pyplot as plt
import numpy as np
class Frame_examples_program():
def __init__(self):
self.window = tk.Tk()
self.window.title("Amazing GUI 5000")
self.create_widgets()
def create_widgets(self):
self.window['padx'] = 10
self.window['pady'] = 10
# - - - - - - - - - - - - - - - - - - - - -
# Frame
frame1 = ttk.Frame(self.window, relief=tk.RIDGE)
frame1.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0)
frame2 = ttk.Frame(self.window, relief=tk.RIDGE)
frame2.grid(row=1, column=0, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0)
self.plotFrame = self.PlotFrame(frame1, frame2)
frame3 = ttk.Frame(self.window, relief=tk.RIDGE)
frame3.grid(row=2, column=2, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0)
self.workFrame = self.WorkFrame(frame3, self.plotFrame)
class PlotFrame():
# The plot
def __init__(self, parent1, parent2):
self.parent1 = parent1
self.parent2 = parent2
self.observers = []
self.x = 0
self.y = 0
canvas = self.plot()
self.plot_toolbar(canvas)
def plot(self):
# the actual plot
fig, ax = plt.subplots()
plt.imshow(np.ones((100,100)),picker=True)
canvas = FigureCanvasTkAgg(fig, self.parent1)
canvas.mpl_connect('button_press_event', self.onclick)
return(canvas)
def plot_toolbar(self, canvas):
# the tool bar to the plot
toolbar = NavigationToolbar2TkAgg(canvas, self.parent2)
toolbar.update()
canvas.get_tk_widget().grid(row=1, column=1)
canvas.draw()
def onclick(self, event):
# the devilish thing that does nothing!
self.x = event.x
self.y = event.y
self.position()
@property
def position(self):
return(self.x,self.y)
@position.setter
def position(self, x, y):
self.x = x
self.y = y
for callback in self.observers:
self.observers.append(callback)
def bind_to(self, callback):
self.observers.append(callback)
class WorkFrame():
def __init__(self, parent, plot_frame):
self.parent = parent
self.x = 0
self.y = 0
self.plot_frame = plot_frame
self.plot_frame.bind_to(self.update_position)
self.display()
def update_position(self, x, y):
self.x = x
self.y = y
def display(self):
l_x = tk.Label(self.parent, text ='Xposition: ' + str(self.x))
l_y = tk.Label(self.parent, text ='Yposition: ' + str(self.y))
l_x.grid(row = 0, column=0)
l_y.grid(row = 0, column=1)
# Create the entire GUI program
program = Frame_examples_program()
# Start the GUI event loop
program.window.mainloop()
这引发了异常:
File "test_xy_positions.py", line 65, in onclick
self.position()
TypeError: 'tuple' object is not callable
这指的是我返回元组的事实(self.x,self.y)
, position(self)
。
解决方案
我正在使用 python3 并已更改导入以使用您的原始示例,但这对我来说效果很好,让我知道它对您的工作方式。我试图评论我改变的所有地方,但可能错过了一个:
import Tkinter as tk
import ttk
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2TkAgg)
import matplotlib.pyplot as plt
import numpy as np
class Frame_examples_program(object):
def __init__(self):
self.window = tk.Tk()
self.window.title("Amazing GUI 5000")
self.create_widgets()
def create_widgets(self):
self.window['padx'] = 10
self.window['pady'] = 10
# - - - - - - - - - - - - - - - - - - - - -
# Frame
frame1 = ttk.Frame(self.window, relief=tk.RIDGE)
frame1.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0)
frame2 = ttk.Frame(self.window, relief=tk.RIDGE)
frame2.grid(row=1, column=0, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0)
self.plotFrame = self.PlotFrame(frame1, frame2)
frame3 = ttk.Frame(self.window, relief=tk.RIDGE)
frame3.grid(row=2, column=2, sticky=tk.E + tk.W + tk.N + tk.S, padx=0, pady=0)
self.workFrame = self.WorkFrame(frame3, self.plotFrame)
class PlotFrame(object):
# The plot
def __init__(self, parent1, parent2):
self.parent1 = parent1
self.parent2 = parent2
self.observers = []
self.x = 0
self.y = 0
canvas = self.plot()
self.plot_toolbar(canvas)
def plot(self):
# the actual plot
fig, ax = plt.subplots()
plt.imshow(np.ones((100, 100)), picker=True)
canvas = FigureCanvasTkAgg(fig, self.parent1)
canvas.mpl_connect('button_press_event', self.onclick)
return canvas
def plot_toolbar(self, canvas):
# the tool bar to the plot
toolbar = NavigationToolbar2TkAgg(canvas, self.parent2)
toolbar.update()
canvas.get_tk_widget().grid(row=1, column=1)
canvas.draw()
def onclick(self, event):
# Here I am now setting the position
self.set_new_position(event.x, event.y)
def set_new_position(self, x, y):
self.x = x
self.y = y
for callback in self.observers:
# Here I am now calling the methods that have been captured so far
# and passing them the arguments of x, y to do with as they please
callback(self.x, self.y)
def bind_to(self, callback):
self.observers.append(callback)
class WorkFrame():
def __init__(self, parent, plot_frame):
self.parent = parent
self.x = 0
self.y = 0
self.plot_frame = plot_frame
self.plot_frame.bind_to(self.update_position)
self.display()
def update_position(self, x, y):
self.x = x
self.y = y
# Here I have added the requirement to run the display code again
# after an update
self.display()
def display(self):
l_x = tk.Label(self.parent, text ='Xposition: ' + str(self.x))
l_y = tk.Label(self.parent, text ='Yposition: ' + str(self.y))
l_x.grid(row = 0, column=0)
l_y.grid(row = 0, column=1)
# Create the entire GUI program
program = Frame_examples_program()
# Start the GUI event loop
program.window.mainloop()
推荐阅读
- c++ - 将我的全局变量放在 Microsoft Visual Studio Form 中的什么位置?
- c - ollydbg 中有许多“printf”,但 a.exe 中只有一个“printf”
- protocol-buffers - 从 C++ 服务器反序列化 protobuf 数据时,Java 客户端出现 InvalidProtocolBufferException
- php - Laravel 身份验证:默认 Web Guard 的 'guest' 方法重定向其他登录的守卫
- python - 尝试在 seaborn 中显示交叉表时收到 TypeError
- asp.net-mvc - 将身份框架数据库适配到另一个自定义数据库中。数据库优先(哈希问题)
- asp.net-core - ASP.NET Core Razor 页面中的 Page() 和 Rediirect() to self 有什么区别?
- git - 无法从 mac 笔记本电脑、终端(Git)推送到我的 GITHUB
- javascript - 如何从 firefox 开发者工具发起 Ajax 请求?
- c - 使用 fscanf 从文件读取无法按预期工作