Tkinter类开发:如何点击画布自定义实例绘制连接线?
问题分析
你的代码核心问题是每个features_object实例都维护着独立的click状态和起始坐标变量。当右键点击第一个实例时,它的click变为1,但右键点击第二个实例时,第二个实例的click还是0,只会设置它自己的起始点,永远不会触发画线逻辑。而过程式编程用全局变量时,所有操作共享同一个状态,所以能正常工作。
解决方案
把共享的状态(点击次数、起始坐标)放到所有实例共同依赖的Canvas对象中,让所有features_object实例读写同一个状态。
修正后的代码
from tkinter import Tk, Frame, Canvas, Text, END, TRUE, BOTH class features_object(): def __init__(self, master, feature_text, feature_xpos, feature_ypos, feature_color): self.master = master self.feature_text = feature_text self.feature_xpos = feature_xpos self.feature_ypos = feature_ypos self.feature_color = feature_color # 初始化Canvas的共享状态(仅第一次创建实例时初始化) if not hasattr(self.master, 'line_click'): self.master.line_click = 0 self.master.start_x = 0 self.master.start_y = 0 self.feature_frame = Frame(self.master, bg=self.feature_color, border=40) self.feature_text = Text(self.feature_frame, font=("Helvetica", 12), relief='flat', width=20, height=3, selectbackground=self.feature_color, selectforeground="black", exportselection=TRUE) self.feature_text.grid(row=0, column=0, padx=5, pady=5, sticky='w') self.feature_text.config(wrap='word') self.feature_text.insert(END, feature_text) self.feature_tags = 'feature' self.feature_id = self.master.create_window(self.feature_xpos, self.feature_ypos, window=self.feature_frame, tags=self.feature_tags) self.bind_events() def bind_events(self): self.feature_frame.bind('<Button-1>', self.clicked) self.feature_frame.bind('<Button-3>', self.draw_line_with_bind) def clicked(self, event=None): print(f'You clicked {self.feature_id} with the cords {self.master.coords(self.feature_id)}') def draw_line_with_bind(self, event): activ_elem = self.master.coords(self.feature_id) if self.master.line_click == 0: # 记录起始点到Canvas的共享属性 self.master.start_x = activ_elem[0] self.master.start_y = activ_elem[1] self.master.line_click = 1 elif self.master.line_click == 1: # 从Canvas获取起始点,绘制连线 end_x = activ_elem[0] end_y = activ_elem[1] self.master.create_line(self.master.start_x, self.master.start_y, end_x, end_y, fill="red", width=5) self.master.line_click = 0 window = Tk() window.geometry("1000x800") frame_start = Frame(window) frame_start.pack(expand=TRUE, fill=BOTH) draw_canvas = Canvas(frame_start) draw_canvas.pack(expand=TRUE, fill=BOTH) created_feature_1 = features_object(draw_canvas, 'feature A', 100, 100, 'red') created_feature_2 = features_object(draw_canvas, 'feature B', 300, 300, 'green') created_feature_3 = features_object(draw_canvas, 'feature C', 500, 500, 'magenta') if __name__ == '__main__': window.mainloop()
关键修改点
- 移除每个实例自己的
click、start_x、start_y变量,改用Canvas对象的属性存储共享状态 - 在
__init__中判断Canvas是否已有共享属性,避免重复初始化 draw_line_with_bind方法中读写Canvas的共享属性,确保所有实例操作同一个状态
内容的提问来源于stack exchange,提问作者Stefanos Stavroulis
相关产品推荐
相关产品推荐

