简体   繁体   English

用对象Tkinter移动线

[英]Moving line with Object Tkinter

I am currently working on a netwoking project and I want to make it so I can create multiple nodes and add connections between them. 我目前正在从事一个netwoking项目,我想使其成为一个项目,以便我可以创建多个节点并在它们之间添加连接。 I have got this all completed but now I am stuck on trying to make the lines move with the objects when I move the object. 我已经完成了所有这些工作,但是现在我不得不尝试在移动对象时使线条随对象一起移动。 I have created dictionaries for each object that I create and these are all stored within a list. 我为创建的每个对象创建了词典,这些词典都存储在列表中。 The dicitonary stores the item, the amount of connectors the item has, and then the connectors that it has linked to it. 字典存储该项目,该项目具有的连接器的数量,然后存储与其链接的连接器。

How can I make it so the lines move with the objects when I move them? 当移动对象时,如何使其与对象一起移动?

Here is my library code: 这是我的图书馆代码:

#-------------------------------------------------------------------------------
# Name:        module1
# Purpose:
#
# Author:      ahilton
#
# Created:     18/12/2014
# Copyright:   (c) ahilton 2014
# Licence:     <your licence>
#-------------------------------------------------------------------------------

#used for validation
#will make sure that the program will run on different versions of python
try:
    # Python2
    from Tkinter import *
except ImportError:
    # Python3
    from tkinter import *

#imports pre-defined libraries that are installed in tkinter
import random
#______________________________________________________________________________________________________________________________________________________________________

#creates a variable used for a count
count = 1
IPvar = 256
f = 0
ConnectCount = 1
a = 0
temp = 0
temp2 = 0

itemsconnectors = []
itemlist = []
LinkedItems = []
#______________________________________________________________________________________________________________________________________________________________________

class Window:

    #______________________________________________________________________________________________________________________________________________________________________

    def __init__(self, window, colour = 'White', width = 1440, height = 720):
        #window variables
        self.colour = colour
        self.screenwidth = width
        self.screenheight = height
        #create the panes
        self.MainCanvas = Canvas(window, background = self.colour, width = self.screenwidth, height = self.screenheight)
        self.MainCanvas.pack()

        #This dictionary is used to keep track of an item being dragged
        self._drag_data = {"x": 0, "y": 0, "item": None}

        #This dictionary is used to keep track of an item having it's state changed
        self._state_change = {"item": None, "tag": "PCchange1", "colour": "Black"}

        #This dictionary is used to keep track of the items being connected
        self._connector = {"connector": None, "item": None, "item2": None, "x": 0, "y": 0, "x2": 0, "y2": 0, "tag": "False"}

        self._object_data = []

        #Add bindings for clicking, dragging and releasing over any object with the "PCdrag" tag
        self.MainCanvas.tag_bind("PCdrag", "<ButtonPress-1>", self.OnButtonPress)
        self.MainCanvas.tag_bind("PCdrag", "<ButtonRelease-1>", self.OnButtonRelease)
        self.MainCanvas.tag_bind("PCdrag", "<B1-Motion>", self.OnMotion)

        self.MainCanvas.tag_bind("ColourSwitch", "<ButtonPress-3>", self.ColourChange)
        #self.MainCanvas.tag_bind("ColourSwitch", "<ButtonRelease-3>", self.ColourChangeRelease)
        #self.MainCanvas.tag_bind("PCchange", "<B3-Motion>", self.ColourChange)

        self.MainCanvas.tag_bind("text", "<Return>", self.OnEnter)

    #______________________________________________________________________________________________________________________________________________________________________

    def OnEnter(self, event):
        print 'hi'

    #______________________________________________________________________________________________________________________________________________________________________

    def ChangeClick(self):
        #This will change the binding of the mouse while the connector process is active
        self.MainCanvas.tag_bind("PCdrag", "<ButtonPress-1>", self.LocateObject)
        self.MainCanvas.tag_bind("PCdrag", "<ButtonRelease-1>", self.LocateObject2)
        self.MainCanvas.tag_bind("PCdrag", "<B1-Motion>", self.Ignore)

    #this is a temporary function to get rid of the OnMotion function which is usually called when the item is dragged
    def Ignore(self, event):
        a = 1
        #print "Ignore"
    #______________________________________________________________________________________________________________________________________________________________________

    #This is used to draw the computer on the canvas, notice the tag that has been added as an attribute
    def CreateComputer(self, x_start, y_start, color, tag):

        #count = count + 1
        #self._state_change["count"] = self._state_change["count"] + 1
        #Creates a list of tags that are going to be added on to each computer object
        #The second tag is defined elsewhere in the program as it changes depending on the state of the computer
        #tag = ["PCdrag", self._state_change["count"], self._state_change["tag"], "ColourSwitch", self._connector["tag"]]
        if temp <= temp2:
            self._object_data.append(dict(item=count, CoCount=0))

            #creates the object and takes properties from the DragItem class
            self.MainCanvas.create_rectangle(x_start-40, y_start-25, x_start+40, y_start+25, outline=color, fill=color, tags = ("PCdrag", self._state_change["tag"], "ColourSwitch", self._connector["tag"], tag))

            itemlist.append(self._state_change)
            #print itemlist
    #______________________________________________________________________________________________________________________________________________________________________

    #This is used to draw text on top of the object on the canvas
    def CreateText(self, x_start, y_start, Node, tag):
        global count
        global f
        global IPvar
        global temp
        global temp2

        IP = "192.168.0."

        if f == 0:
            temp2 = Node - 1
            #IPvar = (IPvar - Node) + 1
            #temp = IPvar
            temp = 1
            f = 1
        else:
            f = 1

        if temp <= temp2:
            self.MainCanvas.create_text(x_start, y_start, text = (IP, temp), fill = 'white', tag = ('PCdrag','text', tag))
            count = count + 1
            temp = temp + 1
        else:
            print 'fail'
    #______________________________________________________________________________________________________________________________________________________________________

    #this function will be called before the line is created. it sets all the variables for the line
    def CreateLine(self):
        global ConnectCount
        #sets the four variables that will determine the coords of the line
        xstart = self._connector["x"]
        ystart = self._connector["y"]
        xend = self._connector["x2"]
        yend = self._connector["y2"]

        #this will reset the _connector dictionary
        self._connector["x"] = 0
        self._connector["y"] = 0
        self._connector["x2"] = 0
        self._connector["y2"] = 0

        #this will set the tag bindings back to their original ones to allow you to drag the item again
        self.MainCanvas.tag_bind("PCdrag", "<ButtonPress-1>", self.OnButtonPress)
        self.MainCanvas.tag_bind("PCdrag", "<ButtonRelease-1>", self.OnButtonRelease)
        self.MainCanvas.tag_bind("PCdrag", "<B1-Motion>", self.OnMotion)

        #print self._object_data
        #tag = ["Linedrag", self._connector("item"), self._connector("item2")]

        #this will create the line and put it on the main canvas
        self.MainCanvas.create_line(xstart, ystart, xend , yend, tags = ("Linedrag", ConnectCount), width = 5, smooth = 1)
        self.MainCanvas.tag_raise("PCdrag")
        ConnectCount = ConnectCount + 1

    #______________________________________________________________________________________________________________________________________________________________________

    def LocateObject(self, event):
        global ConnectCount
        #sets the key "item" in the _connector dictionary to be equal to the object closest to the mouse
        #sets the key "x" and the key "y" to be equal to the x and y coords of the object
        self._connector["item"] = self.MainCanvas.find_closest(event.x, event.y)[0]

        if self._connector["item"] % 2 == 0:
            temp = self._connector["item"] / 2

            for d in range(len(self._object_data)):

                if self._object_data[d]["item"] == temp:

                    self._object_data[d]["CoCount"] = self._object_data[d]["CoCount"] + 1
                    self._object_data[d]["Connect" + str(self._object_data[d]["CoCount"])] = ConnectCount
            self._connector["item"] = self._connector["item"] - 1

        else:
            self._connector["item"] = self._connector["item"] + 1
            temp = self._connector["item"] / 2
            for d in range(len(self._object_data)):

                if self._object_data[d]["item"] == temp:

                    self._object_data[d]["CoCount"] = self._object_data[d]["CoCount"] + 1
                    self._object_data[d]["Connect" + str(self._object_data[d]["CoCount"])] = ConnectCount

            self._connector["item"] = self._connector["item"] - 1

        #print self._object_data, 'test1'

        self._connector["x"] = self.MainCanvas.coords(self._connector["item"])[0] + 40
        self._connector["y"] = self.MainCanvas.coords(self._connector["item"])[1] + 25
    #______________________________________________________________________________________________________________________________________________________________________

    def LocateObject2(self, event):
        global ConnectCount
        #sets the key "item" in the _connector dictionary to be equal to the object closest to the mouse
        #sets the key "x2" and the key "y2" to be equal to the x and y coords of the object
        #self._connector["connector"] = self.MainCanvas.find_closest(event.x, event.y)
        self._connector["item2"] = self.MainCanvas.find_closest(event.x, event.y)[0]

        if self._connector["item2"] % 2 == 0:
            temp = self._connector["item2"] / 2

            for d in range(len(self._object_data)):

                if self._object_data[d]["item"] == temp:

                    self._object_data[d]["CoCount"] = self._object_data[d]["CoCount"] + 1
                    self._object_data[d]["Connect" + str(self._object_data[d]["CoCount"])] = ConnectCount
            self._connector["item2"] = self._connector["item2"] - 1

        else:
            self._connector["item2"] = self._connector["item2"] + 1
            temp = self._connector["item2"] / 2
            for d in range(len(self._object_data)):

                if self._object_data[d]["item"] == temp:

                    self._object_data[d]["CoCount"] = self._object_data[d]["CoCount"] + 1
                    self._object_data[d]["Connect" + str(self._object_data[d]["CoCount"])] = ConnectCount

            self._connector["item2"] = self._connector["item2"] - 1

        #print self._object_data, 'test2'

        self._connector["x2"] = self.MainCanvas.coords(self._connector["item2"])[2] - 40
        self._connector["y2"] = self.MainCanvas.coords(self._connector["item2"])[3] - 25

        #an if statement to check whether the items are the same or if there is no item selected
        if self._connector["item"] != self._connector["item2"]:

            self._connector["tag"] = "True"

            #sets the tags of the objects again to compensate for the tag change in the if statements previously
            #tag = ["PCdrag", self._state_change["count"], self._state_change["tag"], "ColourSwitch", self._connector["tag"]]
            #tag = ["PCdrag", self._state_change["tag"], "ColourSwitch", self._connector["tag"]]

            #configures the items to change the tags of the items accordingly
            #self.MainCanvas.itemconfig(self._connector["item"], tags = tag)
            #self.MainCanvas.itemconfig(self._connector["item2"], tags = tag)
            self.CreateLine()

            self._connector["item"] = None
            self._connector["connector"] = None
            self._connector["item2"] = None
            self._connector["x"] = 0
            self._connector["y"] = 0
            self._connector["x2"] = 0
            self._connector["y2"] = 0


        elif self._connector["item"] and self._connector["item2"] == 0:
            self.Fail()
        else:
            self.Fail()
    #______________________________________________________________________________________________________________________________________________________________________
    #function that is called if the connector cannot be made
    def Fail(self):

        print 'Fail'

        self._connector = {"connector": None, "item": None, "item2": None, "x": 0, "y": 0, "x2": 0, "y2": 0, "tag": "False"}
        #this will set the tag bindings back to their original ones to allow you to drag the item again
        self.MainCanvas.tag_bind("PCdrag", "<ButtonPress-1>", self.OnButtonPress)
        self.MainCanvas.tag_bind("PCdrag", "<ButtonRelease-1>", self.OnButtonRelease)
        self.MainCanvas.tag_bind("PCdrag", "<B1-Motion>", self.OnMotion)

    #______________________________________________________________________________________________________________________________________________________________________

    #This uses the find_closest method to get store the x and y positions of the nearest item into the dictionary
    def OnButtonPress(self, event):
        global itemsconnectors
        global a

        def Search(a):
            for d in range(len(self._object_data)):
                print 'hi1'
                print self._object_data
                if a in self._object_data[d]:
                    print 'hi'

##        def Search():
##            for d in range(len(a)):
##                if 15 in a[d]["CoCount"]:
##                    print 'hi'
##                else:
##                    print 'fail'

        p = 0
        item = self.MainCanvas.find_closest(event.x, event.y)[0]
        tags = self.MainCanvas.gettags(item)
        for tag in tags:
            if tag.startswith("circle-"):
                break
        self._drag_data["item"] = tag
        '''Begin drag of an object'''
        # record the item and its location
        #self._drag_data["item"] = self.MainCanvas.find_closest(event.x, event.y)[0]
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

        if item % 2 == 0:
            item = item / 2

        #runs for loop for the amount of nodes on screen
        for d in range(len(self._object_data)):
                #checks to find the current items dictionary
                if self._object_data[d]["item"] == item:
                    #checks if the item has a connector
                    if self._object_data[d]["CoCount"] > 0:
                        #sets the amount of connectors the object has
                        connectors = len(self._object_data[d]) - 2
                        #runs a loop for the amount of connectors it has
                        for i in range(connectors):
                            #sets a to be equal to the current connector in the loop
                            a = self._object_data[d]["Connect" + str(i + 1)]
                            #prints the coords of the current connector
                            print self.MainCanvas.coords(len(itemlist) + a)
                            #appends that connector to a list
                            itemsconnectors.append(a)
                            print itemsconnectors
                            #runs loop for the amount of nodes on screen
                            for o in range(len(self._object_data)):
                                #LinkedItems.append(Search(self._object_data[d], a))
                                #checks if each node is connected to current connector
                                LinkedItems.append(Search(a))

                    else:
                        print 'No Connectors'

        #print LinkedItems

        #print itemlist
        #print list(self.MainCanvas.gettags(self.MainCanvas.find_closest(event.x, event.y)))


    #______________________________________________________________________________________________________________________________________________________________________

    #This clears the dictionary once the mouse button has been released
    def OnButtonRelease(self, event):
        '''End drag of an object'''
        # reset the drag information
        self._drag_data["item"] = None
        self._drag_data["x"] = 0
        self._drag_data["y"] = 0

    #______________________________________________________________________________________________________________________________________________________________________

    def OnMotion(self, event):

        b = len(self._object_data) + a

        '''Handle dragging of an object'''
        # compute how much this object has moved
        delta_x = event.x - self._drag_data["x"]
        delta_y = event.y - self._drag_data["y"]
        # move the object the appropriate amount
        self.MainCanvas.move(self._drag_data["item"], delta_x, delta_y)
        #self.MainCanvas.coords(b, 10, 10 ,100 ,100)
        # record the new position
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

    #______________________________________________________________________________________________________________________________________________________________________

    def Delete_Object(self):
        global IPvar
        temp = IPvar

        #deletes all the objects on the canvas
        self.MainCanvas.delete('all')

        #This dictionary is used to keep track of an item being dragged
        self._drag_data = {"x": 0, "y": 0, "item": None}

        #This dictionary is used to keep track of an item having it's state changed
        self._state_change = {"item": None, "tag": "PCchange1", "colour": "Black"}

        #This dictionary is used to keep track of the items being connected
        self._connector = {"connector": None, "item": None, "item2": None, "x": 0, "y": 0, "x2": 0, "y2": 0, "tag": "False"}

        self._data_store = {"item": None, "tag": self._state_change["tag"]}
    #______________________________________________________________________________________________________________________________________________________________________

    def ColourChange(self, event):

        #sets the key "item" in the _state_change dictionaryto be equal to the object closest to the mouse
        self._state_change["item"] = self.MainCanvas.find_closest(event.x, event.y)[0]

        #a set of if statements to check what the current object colour is and change it depending on its colour
        if self._state_change["colour"] == "Black":
            self._state_change["colour"] = "Red"
            #changes the tag of the object to reflect what colour it is
            #this will then be used to set the PC to be either a sender, receiver or a router
            self._state_change["tag"] = "PCchange2"

        elif self._state_change["colour"] == "Red":
            self._state_change["colour"] = "Blue"
            self._state_change["tag"] = "PCchange3"

        elif self._state_change["colour"] == "Blue":
            self._state_change["colour"] = "Black"
            self._state_change["tag"] = "PCchange1"
        #an else for error checking. incase none of the if statements work
        else:
            print "Error"

        #sets the tags of the objects again to compensate for the tag change in the if statements previously
        #tag = ["PCdrag", self._state_change["count"], self._state_change["tag"], "ColourSwitch", self._connector["tag"]]
        #tag = ["PCdrag", self._state_change["tag"], "ColourSwitch", self._connector["tag"]]
        #configures the items to change the colour and the tags of the items accordingly
        self.MainCanvas.itemconfig(self._state_change["item"], fill = self._state_change["colour"])
        #print self.MainCanvas.gettags(self.MainCanvas.find_closest(event.x, event.y))
#______________________________________________________________________________________________________________________________________________________________________

class DragItem:
    #Constructor
    #Initiates when the class is called
    #all the arguements are passed through
    #the aruements have pre-set values that can be over written incase the program doesnt get passed anything
    def __init__(self, window, width=100, height=100, colour="black", x_start=0, y_start=0, node = 5):
        #window variables
        self.window = window
        tag = "circle-%d" % id(self)
        #calls a method to create the computer object
        self.circle = self.window.CreateComputer(x_start, y_start, colour, tag)
        self.circle_text = self.window.CreateText(x_start, y_start, node, tag)

class Connector:
    #Constructor
    #Initiates when the class is called
    #all the arguements are passed through
    #the aruements have pre-set values that can be over written incase the program doesnt get passed anything
    def __init__(self, window):
        #window variables
        self.window = window
        self.window.ChangeClick()

You can use the canvas.coords() method to redefine the points of the line ( http://effbot.org/tkinterbook/canvas.htm ). 您可以使用canvas.coords()方法重新定义线的点( http://effbot.org/tkinterbook/canvas.htm )。

Assuming that line is the id or the tag of the line that you want to move, canvas.coords(line) will return the coordinates of the line. 假设该line是您要移动的行的idtagcanvas.coords(line)将返回该行的坐标。 If it is a straight line, this will give you two points pt1 and pt2 representing the origin and the end of the line. 如果它是一条直线,这将为您提供两个点pt1pt2代表该线的起点和终点。 One of these two points will be the start of your new line after you move the object. 这两个点之一将是您移动对象后新行的开始。

Then, you move the object. 然后,您移动对象。 When releasing the mouse button, a function will be called. 释放鼠标按钮时,将调用一个功能。 The first argument of that function is event and contains the coordinates of the mouse, when you released the mouse button. 该函数的第一个参数是event ,包含释放鼠标按钮时鼠标的坐标。 These coordinates ( event.x and event.y ) will be the end of your new line. 这些坐标( event.xevent.y )将在新行的结尾。

With this, you should have all the coordinates (the origin and end) of your new line and all you need to do is call canvas.coords(line, new_coords) to move the line to its new position. 这样,您应该拥有新行的所有坐标(原点和终点),而您需要做的就是调用canvas.coords(line, new_coords)将线移动到新位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM