You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:10:31