2015-03-31 218 views
0

我目前正在開發一個網絡項目,並且我想讓它可以創建多個節點並在它們之間添加連接。我已經完成了這一切,但現在我被困在嘗試使對象在移動對象時與對象一起移動。我爲每個創建的對象創建了字典,這些字典都存儲在列表中。 dicitonary存儲項目,項目所具有的連接器的數量,然後存儲與之關聯的連接器。使用對象Tkinter移動行

我該如何做到這一點,當我移動它們時,線條隨着物體一起移動?

這裏是我的庫代碼:

#------------------------------------------------------------------------------- 
# 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() 
+1

你可以使用canvas.coords()方法重新定義行的點(http://effbot.org/tkinterbook/canvas.htm) – 2015-03-31 18:41:45

+0

是的,我用過。對不起,我不夠清楚。我遇到的問題是我無法獲取連線的物體的座標。所以當我移動一個物體並連接一條線時,我需要它能夠找到第二個物體的座標以便移動這條線。 – AaronH 2015-04-03 00:39:28

+0

我認爲釋放按鈕時調用的函數中的'event'應該包含您拖動的對象的新座標。 – 2015-04-03 00:52:58

回答

1

可以使用canvas.coords()方法來重新定義線(http://effbot.org/tkinterbook/canvas.htm)的點。

假設lineidtag您要移動的行,canvas.coords(line)將返回行的座標。如果是直線,則會給出兩個點pt1pt2,分別代表線的起點和終點。移動對象後,這兩點之一將成爲新行的開始。

然後,您移動該對象。釋放鼠標按鈕時,將調用一個函數。該函數的第一個參數是event並且包含鼠標的座標,當您釋放鼠標按鈕時。這些座標(event.xevent.y)將作爲新行的結尾。

這樣,您應該擁有新線的所有座標(起點和終點),並且您只需撥打canvas.coords(line, new_coords)即可將線移動到新的位置。