Python 在tkinter UI中绘制两个对象之间的线

Python 在tkinter UI中绘制两个对象之间的线,python,tkinter,Python,Tkinter,多亏了很多人的帮助,我能画出三个可以拖动的正方形 现在我试图在每个方块之间画3条线,但我找不到方法来启用它。我尝试的是: from tkinter import * window = Tk() window.state('zoomed') window.configure(bg = 'white') def drag(event): new_x = event.x_root - window.winfo_rootx() new_y = event.y_root - window

多亏了很多人的帮助,我能画出三个可以拖动的正方形

现在我试图在每个方块之间画3条线,但我找不到方法来启用它。我尝试的是:

from tkinter import *
window = Tk()
window.state('zoomed')
window.configure(bg = 'white')

def drag(event):
    new_x = event.x_root - window.winfo_rootx()
    new_y = event.y_root - window.winfo_rooty()
    event.widget.place(x=new_x, y=new_y,anchor=CENTER)

card = Canvas(window, width=10, height=10, bg='red1')
card.place(x=300, y=600,anchor=CENTER)
card.bind("<B1-Motion>", drag)

another_card = Canvas(window, width=10, height=10, bg='red2')
another_card.place(x=600, y=600,anchor=CENTER)
another_card.bind("<B1-Motion>", drag)

third_card = Canvas(window, width=10, height=10, bg='red3')
third_card.place(x=600, y=600,anchor=CENTER)
third_card.bind("<B1-Motion>", drag)

def line(x1, y1, x2, y2):
    print(x1, y1, x2, y2)
    Canvas.create_line(x1, y1, x2, y2, fill="green")

coor_1 = canvas.coords(card)
coor_2 = canvas.coords(another_card)
line(coor_1[0],coor_1[1],coor_1[0],coor_2[1])
window.mainloop()
从tkinter导入*
window=Tk()
window.state('缩放')
window.configure(bg='white')
def拖动(事件):
new_x=event.x_root-window.winfo_rootx()
new_y=event.y_root-window.winfo_rooty()
event.widget.place(x=new\ux,y=new\uy,anchor=CENTER)
卡片=画布(窗口,宽度=10,高度=10,bg='red1')
卡片位置(x=300,y=600,锚定=中心)
卡片绑定(“,拖动)
另一张卡片=画布(窗口,宽度=10,高度=10,背景=red2')
另一个位置(x=600,y=600,锚定=中心)
另一张卡。绑定(“,拖动)
第三张卡片=画布(窗口,宽度=10,高度=10,背景=red3')
第三个位置(x=600,y=600,锚定=中心)
第三张卡。绑定(“,拖动)
def管路(x1、y1、x2、y2):
打印(x1、y1、x2、y2)
画布。创建线(x1,y1,x2,y2,fill=“绿色”)
coor_1=canvas.coords(卡片)
coor_2=canvas.coords(另一张卡片)
行(coor_1[0],coor_1[1],coor_1[0],coor_2[1])
window.mainloop()

它不起作用,我也不认为它会起作用,因为这段代码没有捕获通过拖动对象发生的更改,但我无法猜测如何编码,因为我不完全理解事件函数是如何工作的。我应该如何为它编写代码?

为了自学:

import tkinter as tk

window = tk.Tk()
window.state('zoomed')

class DragAndDropArea(tk.Canvas):
    def __init__(self,master, **kwargs):
        tk.Canvas.__init__(self,master, **kwargs)
        self.active = None

        card_I = self.draw_card(300,600, 100,100, 'red1')
        card_II = self.draw_card(600,600, 100,100, 'red2')
        card_III = self.draw_card(400,400, 100,100, 'red3')

        self.bind_tention(card_I,card_III)
        self.bind_tention(card_I,card_II)
        self.bind_tention(card_III,card_II)

        self.bind('<ButtonPress-1>', self.get_item)
        self.bind('<B1-Motion>',self.move_active)
        self.bind('<ButtonRelease-1>', self.set_none)
    def set_none(self,event):
        self.active = None
    def get_item(self,event):
        try:
            item =  self.find_withtag('current')
            self.active = item[0]
        except IndexError:
            print('no item was clicked')
    def move_active(self,event):
        if self.active != None:
            coords = self.coords(self.active)
            width = coords[2] - coords[0] #x2-x1
            height= coords[1] - coords[3] #y1-y2
            position = coords[0],coords[1]#x1,y1

            x1 = event.x - width/2
            y1 = event.y - height/2
            x2 = event.x + width/2
            y2 = event.y + height/2
            
            self.coords(self.active, x1,y1, x2,y2)
            try:
                self.update_tention(self.active)
            except IndexError:
                print('no tentions found')

    def update_tention(self, tag):
        tentions = self.find_withtag(f'card {tag}')
        for tention in tentions:
            bounded_cards = self.gettags(tention)
            card = bounded_cards[0].split()[-1]
            card2= bounded_cards[1].split()[-1]
            x1,y1 = self.get_mid_point(card)
            x2,y2 = self.get_mid_point(card2)
            self.coords(tention, x1,y1, x2,y2)
            self.lower(tention)

    def draw_card(self, x,y, width,height, color):
        x1,y1 = x,y
        x2,y2 = x+width,y+height
        reference = self.create_rectangle(x1,y1,x2,y2,
                                          fill = color)
        return reference
    def bind_tention(self, card, another_card):
        x1,y1 = self.get_mid_point(card)
        x2,y2 = self.get_mid_point(another_card)
        tag_I = f'card {card}'
        tag_II= f'card {another_card}'
        
        reference = self.create_line(x1,y1,x2,y2, fill='green',
                                     tags=(tag_I,tag_II))
        self.lower(reference)

    def get_mid_point(self, card):
        coords = self.coords(card)
        width = coords[2] - coords[0] #x2-x1
        height= coords[1] - coords[3] #y1-y2
        position = coords[0],coords[1]#x1,y1

        mid_x = position[0] + width/2
        mid_y = position[1] - height/2

        return mid_x,mid_y
        
area = DragAndDropArea(window, bg='white')
area.pack(fill='both',expand=1)
window.mainloop()
将tkinter作为tk导入
window=tk.tk()
window.state('缩放')
类DragAndDropArea(tk.Canvas):
定义初始(自我、主控、**kwargs):
tk.Canvas.\uuuuu init\uuuuuuuu(self,master,**kwargs)
self.active=无
卡片=自抽式卡片(300600100100,“红色1”)
card_II=自动提款卡(600600100100,“红色2”)
card_III=自抽卡(400400100100,“红色3”)
自我约束(卡I、卡III)
自我约束(卡I、卡II)
自我约束(卡III、卡II)
self.bind(“”,self.get_项)
self.bind(“”,self.move\u活动)
self.bind(“”,self.set\u none)
def set_none(自身、事件):
self.active=无
def get_项目(自身、事件):
尝试:
item=self.find_with tag('current'))
self.active=项目[0]
除索引器外:
打印('未单击任何项目')
def move_激活(自身、事件):
如果自我激活!=无:
coords=self.coords(self.active)
宽度=坐标[2]-坐标[0]#x2-x1
高度=坐标[1]-坐标[3]#y1-y2
位置=坐标[0],坐标[1]#x1,y1
x1=事件x-宽度/2
y1=事件y-高度/2
x2=事件x+宽度/2
y2=事件y+高度/2
自协调(自激活,x1,y1,x2,y2)
尝试:
自我更新提示(自我激活)
除索引器外:
打印('未找到帐篷')
def更新提示(自我、标签):
tentions=self.find_with tag(f'card{tag})
对于帐篷中的帐篷:
有界卡片=自我获取(帐篷)
卡片=有界的卡片[0]。拆分()[-1]
card2=有界_卡[1]。拆分()[-1]
x1,y1=自取中点(卡)
x2,y2=自取中点(卡片2)
自身坐标(帐篷,x1,y1,x2,y2)
自我降低(张力)
def绘图卡(自身、x、y、宽度、高度、颜色):
x1,y1=x,y
x2,y2=x+宽度,y+高度
参考=自身。创建矩形(x1,y1,x2,y2,
填充=颜色)
返回引用
def绑定(自身、卡、另一张卡):
x1,y1=自取中点(卡)
x2,y2=自身。获取中间点(另一张卡)
tag_I=f'card{card}'
tag_II=f'card{另一张}
reference=self.create_线(x1,y1,x2,y2,fill='green',
标签=(标签I,标签II))
自下(参考)
def get_中点(自身、卡):
coords=self.coords(卡片)
宽度=坐标[2]-坐标[0]#x2-x1
高度=坐标[1]-坐标[3]#y1-y2
位置=坐标[0],坐标[1]#x1,y1
中间x=位置[0]+宽度/2
中间y=位置[1]-高度/2
返回mid_x,mid_y
面积=DragAndDropArea(窗口,背景为白色)
area.pack(fill='both',expand=1)
window.mainloop()

每次移动对象时,使用
画布移除线条。删除(线条id)
然后重新创建线条,以便引用
画布
,而不在此处定义:
画布。坐标(卡片)
。同样,这也不是正确的使用方法:
Canvas.create_line(x1,y1,x2,y2,fill=“green”)
假设我定义了“Canvas=Canvas(window,width=img.width(),height=img.height(),bg='white'),我如何正确调用每个对象的坐标?我定义了画布,但它仍然不起作用。我可以得到一些文档来获得任何提示吗?当您创建对象时,您会得到它的ID-
line\u ID=my\u canvas.create\u line(…)
,以后您应该使用此ID来移动/更新/删除此对象。但要创建线,您必须首先创建画布,在画布上绘制这条线。您应该创建主画布,并将所有卡片和线条放在此画布上。你们不能直接把线放在窗户里。这很有效。现在我正在研究这个代码,我只有一个问题。如果我想保存每张卡的中心点位置,是否可以使用self.get_mid_point(卡)生成函数?是的,这可以。你只需要想一想,如果移动卡来更新值。我在考虑为卡片而不是函数制作类。但我不知道你是否能遵循这个过程。我不知道函数和类之间的函数区别,但是现在我发现当我想画超过8条线时,在卡片之间画线会显示一些错误。所以现在我正在研究你的代码并尝试t