如何在tkinter中用箭头连接两个状态圈?

3 投票
2 回答
2821 浏览
提问于 2025-04-15 17:35

我现在正在用tkinter写一个有限状态机(fsm)编辑器。但是,我在连接两个状态时遇到了困难。我有两个问题:

1) 我该怎么让过渡箭头根据鼠标移动而变长呢?

2) 我该怎么把箭头的起点固定在一个状态上,而箭头的终点固定在另一个状态上呢?

附注:你觉得tkinter的文档够好吗?

2 个回答

3

Tkinter非常适合这种类型的应用程序。过去我曾经做过一些工具,它们是用箭头连接的框,这些框在你移动的时候箭头也会保持连接(我想这就是你想问的)。不要被那些对Tkinter了解不多的人影响——它是一个非常不错的工具包,画布功能也很灵活。

解决你问题的方法其实很简单,就是一些数学计算。你只需要计算出框的边缘或角落的坐标,这样就能知道箭头该怎么固定。你说的“让它增长”,其实就是在鼠标移动的时候绑定一个事件,然后相应地更新坐标。

要让线条可以增长,你只需要在每次鼠标移动时调整线条的坐标。最简单的方法就是多用画布标签。通过标签,你可以知道哪些箭头连接到哪些框,这样当你移动框的时候,就可以调整指向或来自这个框的箭头的坐标。

5

这里有一个例子来说明这个概念。简单来说,就是用标签把线和框关联起来,当用户移动鼠标时,只需适当地调整坐标。

运行这个例子,然后在米色框内点击并拖动。

当然,如果是要用在实际项目中,你需要做一个更通用的解决方案,但希望这个例子能让你明白,创建一个可以随着框移动而调整的箭头是多么简单。

from Tkinter import *

class CanvasDemo(Frame):
    def __init__(self, width=200, height=200):
        Frame.__init__(self, root)
        self.canvas = Canvas(self)
        self.canvas.pack(fill="both", expand="1")
        self.canvas.create_rectangle(50, 25, 150, 75, fill="bisque", tags="r1")
        self.canvas.create_line(0,0, 50, 25, arrow="last", tags="to_r1")
        self.canvas.bind("<B1-Motion>", self.move_box)
        self.canvas.bind("<ButtonPress-1>", self.start_move)

    def move_box(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        self.canvas.move("r1", deltax, deltay)
        coords = self.canvas.coords("to_r1")
        coords[2] += deltax
        coords[3] += deltay
        self.canvas.coords("to_r1", *coords)
        self.x = event.x
        self.y = event.y

    def start_move(self, event):
        self.x = event.x
        self.y = event.y

root = Tk()
canvas = CanvasDemo(root)
canvas.pack()
mainloop()

撰写回答