Aug-06-2023, 06:45 PM
Hello! I am currently a pretty fresh coder in Python and general programming and have been trying to create a Flowchart Maker. The only import I have needed to use is Tkinter for its GUI. Everything is running smoothly, but I am having troubles figuring out a way to make the arrows. I do not really know how to make an efficient version of lines that are able to bend and do not collide with the objects, since my only idea is making a spaghetti of 40 different if statements and such. The code that I need help making is at line 300. Once again, I have only had around 2 months of experience, so I apologize for the likely not refined code and would love to help explain any questions or concerns. As an added bonus, if anyone has any better ideas on how to refine the code or make data storage better, I would love to hear it! For general information for replication I am running Python through Visual Code Studio with Homebrew's 3.11.4 version. I should probably put this through Github too, but I really do not have any clue as to how to work Github, where I would put it, etc. Anyway, thank you guys for any help, and I'll try to check in and make sure I can answer any questions!
from tkinter import * #info variable setup: # index 0 - object # index 1-4: scaling dots # index 5-8: Anchor dots # index 9-end: arrow connections #width x height of all objects DIAMOND_SIZE = [300,200] CIRCLE_SIZE = [300,200] RECTANGLE_SIZE = [300,200] PARALLELOGRAM_SIZE = [300,200] PARALLELOGRAM_ANGLE = 45 ARROW_SIZE = 300 ARROW_WIDTH = 30 DOT_SIZE = 10 COLOR = "#666666" BASE_COLOR = "#663300" last_clicked = None show_anchors = False first_anchor = None first_coords = None first_anchor_coords = None first_anchor_orient = None first_object_hitbox = None first_object_info = None second_anchor = None second_coords = None second_anchor_coords = None second_anchor_orient = None second_object_hitbox = None second_object_info = None #instating the window window = Tk() window.title("Flowchart Maker") #window.attributes("-fullscreen",True) #instating the canvas that fills the whole window even when expanded canvas = Canvas(window,bg="#000000") canvas.pack(fill="both", expand=True) def anchor_mode(): global show_anchors if show_anchors: show_anchors = False canvas.itemconfig("anchor",state="hidden") anchor_button.config(text="Arrow Mode: OFF") else: show_anchors = True canvas.itemconfig("anchor",state="normal") anchor_button.config(text="Arrow Mode: ON") anchor_button = Button(canvas,highlightbackground="#CCCCAA",text="Arrow Mode: OFF",font=("Noteworthy",25),command=anchor_mode,fg=BASE_COLOR,padx=5,pady=5,relief=GROOVE,bd=4) anchor_button.pack(side=BOTTOM) #CREATION OF CLASSES #click function: this basically just finds the place that the user clicked inside the object #without this the program wouldn't be able to find the distance between point A and B #drag function: this finds where the cursor is now and subtracts the distance between where the cursor is to where it was #Then the program uses canvas.move() to move the object however many units and then sets the last click position to where the cursor is now for future calls #__init__ function: each time an object is created, it gets the width x height constants and is created at a specific location #it looks like a lot of math, but in reality it is the size of every object above itself + 20 for spacing between each object class Icon: def click(self, event): #coordinates of the place we click the label at (Point A) self.click_x = event.x self.click_y = event.y print("Click:",self.click_x,self.click_y) global last_clicked try: canvas.itemconfig(self.info[4], state="normal") canvas.itemconfig(last_clicked.info[1], state="hidden") canvas.itemconfig(last_clicked.info[2], state="hidden") canvas.itemconfig(last_clicked.info[3], state="hidden") canvas.itemconfig(last_clicked.info[4], state="hidden") except AttributeError: pass finally: last_clicked = self canvas.itemconfig(self.info[1], state="normal") canvas.itemconfig(self.info[2], state="normal") canvas.itemconfig(self.info[3], state="normal") def drag(self, event, obj_type): #coordinates of the place we are dragging the widget to (Point B) pointer_x=event.x pointer_y=event.y print("Pointer:",pointer_x,pointer_y) #distance between Point A and Point B for x and y x = pointer_x - self.click_x y = pointer_y - self.click_y canvas.move(self.info[0], x, y) canvas.move(self.info[1], x, y) canvas.move(self.info[2], x, y) canvas.move(self.info[3], x, y) canvas.move(self.info[4], x, y) canvas.move(self.info[5], x, y) canvas.move(self.info[6], x, y) canvas.move(self.info[7], x, y) canvas.move(self.info[8], x, y) self.click_x = pointer_x self.click_y = pointer_y self.coords = canvas.coords(self.info[0]) if obj_type == "circle": self.hitbox = [self.coords[0],self.coords[1], self.coords[2],self.coords[3]] elif obj_type == "rectangle": self.hitbox = [self.coords[0], self.coords[1], self.coords[4], self.coords[5]] elif obj_type == "diamond": self.hitbox = [self.coords[2], self.coords[1], self.coords[6], self.coords[5]] elif obj_type == "parallelogram": self.hitbox = [self.coords[2], self.coords[1], self.coords[6], self.coords[5]] print("Hitbox:",self.hitbox) def scale(self, event, obj_type, dot): coords = canvas.coords(self.info[0]) if obj_type == "circle": if dot == 1: canvas.coords(self.info[0], [event.x,event.y,coords[2],coords[3]]) elif dot == 2: canvas.coords(self.info[0], [event.x,coords[1],coords[2],event.y]) elif dot == 3: canvas.coords(self.info[0], [coords[0],coords[1],event.x,event.y]) elif dot == 4: canvas.coords(self.info[0], [coords[0],event.y,event.x,coords[3]]) coords = canvas.coords(self.info[0]) canvas.coords(self.info[1], [coords[0]-DOT_SIZE, coords[1]-DOT_SIZE, coords[0]+DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[2], [coords[0]-DOT_SIZE, coords[3]-DOT_SIZE, coords[0]+DOT_SIZE, coords[3]+DOT_SIZE]) canvas.coords(self.info[3], [coords[2]-DOT_SIZE, coords[3]-DOT_SIZE, coords[2]+DOT_SIZE, coords[3]+DOT_SIZE]) canvas.coords(self.info[4], [coords[2]-DOT_SIZE, coords[1]-DOT_SIZE, coords[2]+DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[5], [coords[0] + ((coords[2]-coords[0])/2) -DOT_SIZE, coords[1]-DOT_SIZE, coords[0] + ((coords[2]-coords[0])/2) +DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[6], [coords[0] -DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) -DOT_SIZE, coords[0] +DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) + DOT_SIZE]) canvas.coords(self.info[7], [coords[0] + ((coords[2]-coords[0])/2) -DOT_SIZE, coords[3] -DOT_SIZE, coords[0] + ((coords[2]-coords[0])/2) +DOT_SIZE, coords[3] + DOT_SIZE]) canvas.coords(self.info[8], [coords[2] -DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) -DOT_SIZE, coords[2] +DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) + DOT_SIZE]) elif obj_type == "rectangle": if dot == 1: canvas.coords(self.info[0], [event.x, event.y, event.x, coords[3], coords[4], coords[5], coords[6], event.y]) elif dot == 2: canvas.coords(self.info[0], [event.x, coords[1], event.x, event.y, coords[4], event.y, coords[6], coords[7]]) elif dot == 3: canvas.coords(self.info[0], [coords[0], coords[1], coords[2], event.y, event.x, event.y, event.x, coords[7]]) elif dot == 4: canvas.coords(self.info[0], [coords[0], event.y, coords[2], coords[3], event.x, coords[5], event.x, event.y]) coords = canvas.coords(self.info[0]) canvas.coords(self.info[1], [coords[0]-DOT_SIZE, coords[1]-DOT_SIZE, coords[0]+DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[2], [coords[2]-DOT_SIZE, coords[3]-DOT_SIZE, coords[2]+DOT_SIZE, coords[3]+DOT_SIZE]) canvas.coords(self.info[3], [coords[4]-DOT_SIZE, coords[5]-DOT_SIZE, coords[4]+DOT_SIZE, coords[5]+DOT_SIZE]) canvas.coords(self.info[4], [coords[6]-DOT_SIZE, coords[7]-DOT_SIZE, coords[6]+DOT_SIZE, coords[7]+DOT_SIZE]) canvas.coords(self.info[5], [coords[0] + ((coords[6]-coords[0])/2) -DOT_SIZE, coords[1]-DOT_SIZE, coords[0] + ((coords[6]-coords[0])/2) +DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[6], [coords[2] + ((coords[0]-coords[2])/2) -DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) -DOT_SIZE, coords[2] + ((coords[0]-coords[2])/2) +DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) + DOT_SIZE]) canvas.coords(self.info[7], [coords[2] + ((coords[4]-coords[2])/2) -DOT_SIZE, coords[3] -DOT_SIZE, coords[2] + ((coords[4]-coords[2])/2) +DOT_SIZE, coords[3] + DOT_SIZE]) canvas.coords(self.info[8], [coords[4] + ((coords[6]-coords[4])/2) -DOT_SIZE, coords[7] + ((coords[5]-coords[7])/2) -DOT_SIZE, coords[4] + ((coords[6]-coords[4])/2) +DOT_SIZE, coords[7] + ((coords[5]-coords[7])/2) + DOT_SIZE]) elif obj_type == "diamond": if dot == 1: canvas.coords(self.info[0], [event.x + ((coords[6]-coords[2])/2), event.y, event.x, event.y + ((coords[5]-coords[1])/2), event.x + ((coords[6]-coords[2])/2), coords[5], coords[6], event.y + ((coords[5]-coords[1])/2)]) elif dot == 2: canvas.coords(self.info[0], [event.x + ((coords[6]-coords[2])/2), coords[1], event.x, event.y - ((coords[5]-coords[1])/2), event.x + ((coords[6]-coords[2])/2), event.y, coords[6], event.y - ((coords[5]-coords[1])/2)]) elif dot == 3: canvas.coords(self.info[0], [event.x - ((coords[6]-coords[2])/2), coords[1], coords[2], event.y - ((coords[5]-coords[1])/2), event.x - ((coords[6]-coords[2])/2), event.y, event.x, event.y - ((coords[5]-coords[1])/2)]) elif dot == 4: canvas.coords(self.info[0], [event.x - ((coords[6]-coords[2])/2), event.y, coords[2], event.y + ((coords[5] - coords[1])/2), event.x - ((coords[6]-coords[2])/2), coords[5], event.x, event.y + ((coords[5] - coords[1])/2)]) coords = canvas.coords(self.info[0]) canvas.coords(self.info[1], [coords[2]-DOT_SIZE, coords[1]-DOT_SIZE, coords[2]+DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[2], [coords[2]-DOT_SIZE, coords[5]-DOT_SIZE, coords[2]+DOT_SIZE, coords[5]+DOT_SIZE]) canvas.coords(self.info[3], [coords[6]-DOT_SIZE, coords[5]-DOT_SIZE, coords[6]+DOT_SIZE, coords[5]+DOT_SIZE]) canvas.coords(self.info[4], [coords[6]-DOT_SIZE, coords[1]-DOT_SIZE, coords[6]+DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[5], [coords[0]-DOT_SIZE, coords[1]-DOT_SIZE, coords[0]+DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[6], [coords[2]-DOT_SIZE, coords[3]-DOT_SIZE, coords[2]+DOT_SIZE, coords[3]+DOT_SIZE]) canvas.coords(self.info[7], [coords[4]-DOT_SIZE, coords[5]-DOT_SIZE, coords[4]+DOT_SIZE, coords[5]+DOT_SIZE]) canvas.coords(self.info[8], [coords[6]-DOT_SIZE, coords[7]-DOT_SIZE, coords[6]+DOT_SIZE, coords[7]+DOT_SIZE]) elif obj_type == "parallelogram": if dot == 1: canvas.coords(self.info[0], [event.x + PARALLELOGRAM_ANGLE, event.y, event.x, coords[3], coords[4], coords[5], coords[6], event.y]) elif dot == 2: canvas.coords(self.info[0], [event.x + 45, coords[1], event.x, event.y, coords[4], event.y, coords[6], coords[7]]) elif dot == 3: canvas.coords(self.info[0], [coords[0], coords[1], coords[2], event.y, event.x - PARALLELOGRAM_ANGLE, event.y, event.x, coords[7]]) elif dot == 4: canvas.coords(self.info[0], [coords[0], event.y, coords[2], coords[3], event.x - PARALLELOGRAM_ANGLE, coords[5], event.x, event.y]) coords = canvas.coords(self.info[0]) canvas.coords(self.info[1], [coords[2]-DOT_SIZE, coords[1]-DOT_SIZE, coords[2]+DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[2], [coords[2]-DOT_SIZE, coords[3]-DOT_SIZE, coords[2]+DOT_SIZE, coords[3]+DOT_SIZE]) canvas.coords(self.info[3], [coords[6]-DOT_SIZE, coords[5]-DOT_SIZE, coords[6]+DOT_SIZE, coords[5]+DOT_SIZE]) canvas.coords(self.info[4], [coords[6]-DOT_SIZE, coords[7]-DOT_SIZE, coords[6]+DOT_SIZE, coords[7]+DOT_SIZE]) canvas.coords(self.info[5], [coords[0] + ((coords[6]-coords[0])/2) -DOT_SIZE, coords[1]-DOT_SIZE, coords[0] + ((coords[6]-coords[0])/2) +DOT_SIZE, coords[1]+DOT_SIZE]) canvas.coords(self.info[6], [coords[2] + ((coords[0]-coords[2])/2) -DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) -DOT_SIZE, coords[2] + ((coords[0]-coords[2])/2) +DOT_SIZE, coords[1] + ((coords[3]-coords[1])/2) + DOT_SIZE]) canvas.coords(self.info[7], [coords[2] + ((coords[4]-coords[2])/2) -DOT_SIZE, coords[3] -DOT_SIZE, coords[2] + ((coords[4]-coords[2])/2) +DOT_SIZE, coords[3] + DOT_SIZE]) canvas.coords(self.info[8], [coords[4] + ((coords[6]-coords[4])/2) -DOT_SIZE, coords[7] + ((coords[5]-coords[7])/2) -DOT_SIZE, coords[4] + ((coords[6]-coords[4])/2) +DOT_SIZE, coords[7] + ((coords[5]-coords[7])/2) + DOT_SIZE]) def connect(self, event, anchor): def check_for_orient(info, anchor): if info[5] == anchor: return "top" elif info[6] == anchor: return "left" elif info[7] == anchor: return "bottom" elif info[8] == anchor: return "right" else: return None global first_anchor, second_anchor, first_coords, second_coords, first_anchor_coords, second_anchor_coords, first_anchor_orient, second_anchor_orient, first_object_hitbox, second_object_hitbox, first_object_info, second_object_info if first_anchor == None: first_anchor = anchor first_object_info = self.info first_anchor_orient = check_for_orient(first_object_info, anchor) first_anchor_coords = canvas.coords(first_anchor) first_anchor_coords = [first_anchor_coords[0]+DOT_SIZE, first_anchor_coords[1]+DOT_SIZE] print("first anchor clicked: ",first_anchor_coords) first_object_hitbox = self.hitbox elif second_anchor != first_anchor: second_anchor = anchor second_object_info = self.info second_anchor_orient = check_for_orient(self.info, anchor) second_anchor_coords = canvas.coords(second_anchor) second_anchor_coords = [second_anchor_coords[0]+DOT_SIZE, second_anchor_coords[1]+DOT_SIZE] print("second anchor clicked: ",second_anchor_coords) second_object_hitbox = self.hitbox line_coords = [] line_coords.append(first_anchor_coords) #Code goes here! Thank you for any help! line_coords.append(second_anchor_coords) first_anchor = None second_anchor = None line = Arrow("#AA66AA", line_coords) line.info.append(first_object_info[0]) line.info.append(second_object_info[0]) first_object_info.append(line) second_object_info.append(line) class Circle(Icon): def __init__(self, color): self.info =[] self.info.append(canvas.create_oval(10,10,10+CIRCLE_SIZE[0],10+CIRCLE_SIZE[1], fill=color,width=4,outline="black")) self.coords = canvas.coords(self.info[0]) print(self.coords) self.info.append(canvas.create_oval(((self.coords[0])-DOT_SIZE,self.coords[1]-DOT_SIZE), ((self.coords[0])+DOT_SIZE,self.coords[1]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden", tag="dot")) self.info.append(canvas.create_oval((self.coords[0]-DOT_SIZE,(self.coords[3])-DOT_SIZE), (self.coords[0]+DOT_SIZE,(self.coords[3])+DOT_SIZE), fill="white", outline="black", width=3, state="hidden", tag="dot")) self.info.append(canvas.create_oval((self.coords[2]-DOT_SIZE,(self.coords[3])-DOT_SIZE), (self.coords[2]+DOT_SIZE,(self.coords[3])+DOT_SIZE), fill="white", outline="black", width=3, state="hidden", tag="dot")) self.info.append(canvas.create_oval(((self.coords[2])-DOT_SIZE,self.coords[1]-DOT_SIZE), ((self.coords[2])+DOT_SIZE,self.coords[1]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden", tag="dot")) self.info.append(canvas.create_oval((self.coords[0] + ((self.coords[2]-self.coords[0])/2) -DOT_SIZE, self.coords[1]-DOT_SIZE), (self.coords[0] + ((self.coords[2]-self.coords[0])/2) +DOT_SIZE, self.coords[1]+DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[0] -DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) -DOT_SIZE), (self.coords[0] +DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[0] + ((self.coords[2]-self.coords[0])/2) -DOT_SIZE, self.coords[3] -DOT_SIZE), (self.coords[0] + ((self.coords[2]-self.coords[0])/2) +DOT_SIZE, self.coords[3] +DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[2] -DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) -DOT_SIZE), (self.coords[2] +DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.hitbox = [self.coords[0],self.coords[1], self.coords[2],self.coords[3]] canvas.tag_bind(self.info[0],"<Button-1>",self.click) canvas.tag_bind(self.info[0],"<B1-Motion>",lambda event: self.drag(event, "circle")) canvas.tag_bind(self.info[1], "<B1-Motion>", lambda event: self.scale(event, "circle", 1)) canvas.tag_bind(self.info[2], "<B1-Motion>", lambda event: self.scale(event, "circle", 2)) canvas.tag_bind(self.info[3], "<B1-Motion>", lambda event: self.scale(event, "circle", 3)) canvas.tag_bind(self.info[4], "<B1-Motion>", lambda event: self.scale(event, "circle", 4)) canvas.tag_bind(self.info[5], "<Button-1>", lambda event: self.connect(event, self.info[5])) canvas.tag_bind(self.info[6], "<Button-1>", lambda event: self.connect(event, self.info[6])) canvas.tag_bind(self.info[7], "<Button-1>", lambda event: self.connect(event, self.info[7])) canvas.tag_bind(self.info[8], "<Button-1>", lambda event: self.connect(event, self.info[8])) class Rectangle(Icon): def __init__(self, color): self.info =[] self.info.append(canvas.create_polygon(10, CIRCLE_SIZE[1]+20, 10, CIRCLE_SIZE[1]+20+RECTANGLE_SIZE[1], 10+RECTANGLE_SIZE[0], CIRCLE_SIZE[1]+20+RECTANGLE_SIZE[1], 10+RECTANGLE_SIZE[0], CIRCLE_SIZE[1]+20, fill=color,width=4,outline="black")) self.coords = canvas.coords(self.info[0]) self.info.append(canvas.create_oval((self.coords[0]-DOT_SIZE,self.coords[1]-DOT_SIZE), (self.coords[0]+DOT_SIZE,self.coords[1]+DOT_SIZE), fill="white",outline="black",width=3,state="hidden")) self.info.append(canvas.create_oval((self.coords[2]-DOT_SIZE,self.coords[3]-DOT_SIZE), (self.coords[2]+DOT_SIZE,self.coords[3]+DOT_SIZE), fill="white",outline="black",width=3,state="hidden")) self.info.append(canvas.create_oval((self.coords[4]-DOT_SIZE,self.coords[5]-DOT_SIZE), (self.coords[4]+DOT_SIZE,self.coords[5]+DOT_SIZE), fill="white",outline="black",width=3,state="hidden")) self.info.append(canvas.create_oval((self.coords[6]-DOT_SIZE,self.coords[7]-DOT_SIZE), (self.coords[6]+DOT_SIZE,self.coords[7]+DOT_SIZE), fill="white",outline="black",width=3,state="hidden")) self.info.append(canvas.create_oval((self.coords[0] + ((self.coords[6]-self.coords[0])/2) -DOT_SIZE, self.coords[1]-DOT_SIZE), (self.coords[0] + ((self.coords[6]-self.coords[0])/2) +DOT_SIZE, self.coords[1]+DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[2] + ((self.coords[0]-self.coords[2])/2) -DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) -DOT_SIZE), (self.coords[2] + ((self.coords[0]-self.coords[2])/2) +DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[2] + ((self.coords[4]-self.coords[2])/2) -DOT_SIZE, self.coords[3] -DOT_SIZE), (self.coords[2] + ((self.coords[4]-self.coords[2])/2) +DOT_SIZE, self.coords[3] + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[4] + ((self.coords[6]-self.coords[4])/2) -DOT_SIZE, self.coords[7] + ((self.coords[5]-self.coords[7])/2) -DOT_SIZE), (self.coords[4] + ((self.coords[6]-self.coords[4])/2) +DOT_SIZE, self.coords[7] + ((self.coords[5]-self.coords[7])/2) + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.hitbox = [self.coords[0], self.coords[1], self.coords[4], self.coords[5]] canvas.tag_bind(self.info[0],"<Button-1>",self.click) canvas.tag_bind(self.info[0],"<B1-Motion>",lambda event: self.drag(event, "rectangle")) canvas.tag_bind(self.info[1], "<B1-Motion>", lambda event: self.scale(event, "rectangle", 1)) canvas.tag_bind(self.info[2], "<B1-Motion>", lambda event: self.scale(event, "rectangle", 2)) canvas.tag_bind(self.info[3], "<B1-Motion>", lambda event: self.scale(event, "rectangle", 3)) canvas.tag_bind(self.info[4], "<B1-Motion>", lambda event: self.scale(event, "rectangle", 4)) canvas.tag_bind(self.info[5], "<Button-1>", lambda event: self.connect(event, self.info[5])) canvas.tag_bind(self.info[6], "<Button-1>", lambda event: self.connect(event, self.info[6])) canvas.tag_bind(self.info[7], "<Button-1>", lambda event: self.connect(event, self.info[7])) canvas.tag_bind(self.info[8], "<Button-1>", lambda event: self.connect(event, self.info[8])) class Diamond(Icon): def __init__(self, color): self.info =[] self.info.append(canvas.create_polygon((10+ (DIAMOND_SIZE[0] / 2), (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20)), (10, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20) + (DIAMOND_SIZE[1] / 2)), (10+ (DIAMOND_SIZE[0] / 2), (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20) + DIAMOND_SIZE[1]), (10+ DIAMOND_SIZE[0], (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20) + (DIAMOND_SIZE[1] / 2)), fill=color,width=4,outline="black")) self.coords = canvas.coords(self.info[0]) self.info.append(canvas.create_oval((self.coords[2]-DOT_SIZE,self.coords[1]-DOT_SIZE), (self.coords[2]+DOT_SIZE,self.coords[1]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[2]-DOT_SIZE,self.coords[5]-DOT_SIZE), (self.coords[2]+DOT_SIZE,self.coords[5]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[6]-DOT_SIZE,self.coords[5]-DOT_SIZE), (self.coords[6]+DOT_SIZE,self.coords[5]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[6]-DOT_SIZE,self.coords[1]-DOT_SIZE), (self.coords[6]+DOT_SIZE,self.coords[1]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[0] -DOT_SIZE, self.coords[1]-DOT_SIZE), (self.coords[0] +DOT_SIZE, self.coords[1]+DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[2] -DOT_SIZE, self.coords[3] -DOT_SIZE), (self.coords[2] +DOT_SIZE, self.coords[3] +DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[4] -DOT_SIZE, self.coords[5] -DOT_SIZE), (self.coords[4] +DOT_SIZE, self.coords[5] +DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[6] -DOT_SIZE, self.coords[7] -DOT_SIZE), (self.coords[6] +DOT_SIZE, self.coords[7] +DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.hitbox = [self.coords[2], self.coords[1], self.coords[6], self.coords[5]] canvas.tag_bind(self.info[0],"<Button-1>",self.click) canvas.tag_bind(self.info[0],"<B1-Motion>",lambda event: self.drag(event, "diamond")) canvas.tag_bind(self.info[1], "<B1-Motion>", lambda event: self.scale(event, "diamond", 1)) canvas.tag_bind(self.info[2], "<B1-Motion>", lambda event: self.scale(event, "diamond", 2)) canvas.tag_bind(self.info[3], "<B1-Motion>", lambda event: self.scale(event, "diamond", 3)) canvas.tag_bind(self.info[4], "<B1-Motion>", lambda event: self.scale(event, "diamond", 4)) canvas.tag_bind(self.info[5], "<Button-1>", lambda event: self.connect(event, self.info[5])) canvas.tag_bind(self.info[6], "<Button-1>", lambda event: self.connect(event, self.info[6])) canvas.tag_bind(self.info[7], "<Button-1>", lambda event: self.connect(event, self.info[7])) canvas.tag_bind(self.info[8], "<Button-1>", lambda event: self.connect(event, self.info[8])) class Parallelogram(Icon): def __init__(self, color): self.info =[] self.info.append(canvas.create_polygon((10+PARALLELOGRAM_ANGLE, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)), (10, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)+PARALLELOGRAM_SIZE[1]), (10+PARALLELOGRAM_SIZE[0]-PARALLELOGRAM_ANGLE, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)+PARALLELOGRAM_SIZE[1]), (10+PARALLELOGRAM_SIZE[0], (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)), fill=color,width=4,outline="black")) self.coords = canvas.coords(self.info[0]) self.info.append(canvas.create_oval((self.coords[2]-DOT_SIZE,self.coords[1]-DOT_SIZE), (self.coords[2]+DOT_SIZE,self.coords[1]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[2]-DOT_SIZE,self.coords[3]-DOT_SIZE), (self.coords[2]+DOT_SIZE,self.coords[3]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[6]-DOT_SIZE,self.coords[5]-DOT_SIZE), (self.coords[6]+DOT_SIZE,self.coords[5]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[6]-DOT_SIZE,self.coords[7]-DOT_SIZE), (self.coords[6]+DOT_SIZE,self.coords[7]+DOT_SIZE), fill="white", outline="black", width=3, state="hidden")) self.info.append(canvas.create_oval((self.coords[0] + ((self.coords[6]-self.coords[0])/2) -DOT_SIZE, self.coords[1]-DOT_SIZE), (self.coords[0] + ((self.coords[6]-self.coords[0])/2) +DOT_SIZE, self.coords[1]+DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[2] + ((self.coords[0]-self.coords[2])/2) -DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) -DOT_SIZE), (self.coords[2] + ((self.coords[0]-self.coords[2])/2) +DOT_SIZE, self.coords[1] + ((self.coords[3]-self.coords[1])/2) + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[2] + ((self.coords[4]-self.coords[2])/2) -DOT_SIZE, self.coords[3] -DOT_SIZE), (self.coords[2] + ((self.coords[4]-self.coords[2])/2) +DOT_SIZE, self.coords[3] + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.info.append(canvas.create_oval((self.coords[4] + ((self.coords[6]-self.coords[4])/2) -DOT_SIZE, self.coords[7] + ((self.coords[5]-self.coords[7])/2) -DOT_SIZE), (self.coords[4] + ((self.coords[6]-self.coords[4])/2) +DOT_SIZE, self.coords[7] + ((self.coords[5]-self.coords[7])/2) + DOT_SIZE), fill="#999900", outline="black", width=3, state="hidden", tag="anchor")) self.hitbox = [self.coords[2], self.coords[1], self.coords[6], self.coords[5]] canvas.tag_bind(self.info[0],"<Button-1>",self.click) canvas.tag_bind(self.info[0],"<B1-Motion>",lambda event: self.drag(event, "parallelogram")) canvas.tag_bind(self.info[1], "<B1-Motion>", lambda event: self.scale(event, "parallelogram", 1)) canvas.tag_bind(self.info[2], "<B1-Motion>", lambda event: self.scale(event, "parallelogram", 2)) canvas.tag_bind(self.info[3], "<B1-Motion>", lambda event: self.scale(event, "parallelogram", 3)) canvas.tag_bind(self.info[4], "<B1-Motion>", lambda event: self.scale(event, "parallelogram", 4)) canvas.tag_bind(self.info[5], "<Button-1>", lambda event: self.connect(event, self.info[5])) canvas.tag_bind(self.info[6], "<Button-1>", lambda event: self.connect(event, self.info[6])) canvas.tag_bind(self.info[7], "<Button-1>", lambda event: self.connect(event, self.info[7])) canvas.tag_bind(self.info[8], "<Button-1>", lambda event: self.connect(event, self.info[8])) class Arrow(Icon): def __init__(self, color, coordinates): self.info =[] self.info.append(canvas.create_line((coordinates), fill=color, width=2, arrow="last", arrowshape=(30,30,9))) self.coords = canvas.coords(self.info[0]) print(self.coords) #For each object, there is a base object that creates a new canvas item when it is clicked #The math for where it is placed is the same as the __init__ variables above #when it is clicked, is creates another circle with the color from the constant at the top base_oval = canvas.create_oval(10,10,10+CIRCLE_SIZE[0], 10+CIRCLE_SIZE[1], fill=BASE_COLOR, width=4, outline="black") canvas.tag_bind(base_oval,"<Button-1>",lambda self: Circle(COLOR)) base_rectangle = canvas.create_rectangle(10,(CIRCLE_SIZE[1]+20), 10+RECTANGLE_SIZE[0],(CIRCLE_SIZE[1]+20)+RECTANGLE_SIZE[1], fill=BASE_COLOR, width=4, outline="black") canvas.tag_bind(base_rectangle,"<Button-1>",lambda self: Rectangle(COLOR)) base_diamond = canvas.create_polygon((10+ (DIAMOND_SIZE[0] / 2), (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20)), (10, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20) + (DIAMOND_SIZE[1] / 2)), (10+ (DIAMOND_SIZE[0] / 2), (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20) + DIAMOND_SIZE[1]), (10+ DIAMOND_SIZE[0], (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20) + (DIAMOND_SIZE[1] / 2)), fill=BASE_COLOR, width=4, outline="black") canvas.tag_bind(base_diamond,"<Button-1>",lambda self: Diamond(COLOR)) base_parallelogram = canvas.create_polygon((10+PARALLELOGRAM_ANGLE, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)), (10, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)+PARALLELOGRAM_SIZE[1]), (10+PARALLELOGRAM_SIZE[0]-PARALLELOGRAM_ANGLE, (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)+PARALLELOGRAM_SIZE[1]), (10+PARALLELOGRAM_SIZE[0], (RECTANGLE_SIZE[1]+20+CIRCLE_SIZE[1]+20+DIAMOND_SIZE[1]+20)), fill=BASE_COLOR, width=4, outline="black") canvas.tag_bind(base_parallelogram,"<Button-1>",lambda self: Parallelogram(COLOR)) window.mainloop()