Created
April 27, 2017 12:30
-
-
Save KevinTyrrell/68d3e5b55c1fd5fc367b079662f34fc2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Analysis: I had a lot of fun re-designing assignment 7 in this assignment. I created a Rectangle2D class and made it so that the back-end communicated with the front end. When the back-end was updated, so was the front-end. The only problem at that point was making sure I only used the back-end variables are didn't touch the front end. | |
# Design: Made a Rectangle2D class. Allowed the front end variables to be setup inside that class. Finally, added the ability for the text input fields to directly have access to the last clicked rectangle. | |
# Coding: Please indent and format your code properly | |
from tkinter import * | |
class Rectangle2D: | |
""" | |
Constructor function. | |
""" | |
def __init__(self, centerX, centerY, width, height): | |
self.__centerX = centerX | |
self.__centerY = centerY | |
self.__width = width | |
self.__height = height | |
# GUI variables. | |
self.__canvas = None | |
self.__rectptr = None | |
""" | |
Setter functions. | |
""" | |
def setCenter(self, x, y): | |
self.__centerX = x | |
self.__centerY = y | |
if (self.__synced()): | |
self.__update() | |
def setWidth(self, newVal): | |
self.__width = newVal | |
if (self.__synced()): | |
self.__update() | |
def setHeight(self, newVal): | |
self.__height = newVal | |
if (self.__synced()): | |
self.__update() | |
""" | |
Getter functions. | |
""" | |
def getCenterX(self): | |
return self.__centerX | |
def getCenterY(self): | |
return self.__centerY | |
def getWidth(self): | |
return self.__width | |
def getHeight(self): | |
return self.__height | |
""" | |
Translates the rectangle by dx, dy. | |
Updates the rectangle if synced. | |
Return - No value. | |
""" | |
def move(self, dx, dy): | |
self.__centerX += dx | |
self.__centerY += dy | |
if (self.__synced()): | |
self.__update() | |
""" | |
Returns true if two given rectangles are overlapping. | |
Two rectangles overlap if the assumption is false that one rectangle | |
is above, below, or on one of the sides of the other rectangle. | |
""" | |
def intersects(self, other_rect): | |
return (self.__centerY + self.__height / 2 > other_rect.__centerY - other_rect.__height / 2 | |
and self.__centerY - self.__height / 2 < other_rect.__centerY + other_rect.__height / 2 | |
and self.__centerX + self.__width / 2 > other_rect.__centerX - other_rect.__width / 2 | |
and self.__centerX - self.__width / 2 < other_rect.__centerX + other_rect.__width / 2) | |
""" | |
Syncs this Rectangle2D with a tkinter rectangle. | |
The sync is only one way: Rectangle2D ---> tkinter Rectangle. | |
Changes to the tkinter rectangle will not update this Rectangle2D. | |
If this Rectangle2D changes, the tkinter Rectangle will be updated. | |
canvas - Canvas in which the `rect` exists on. | |
rect - Rectangle which this syncs to. | |
Return - No value. | |
""" | |
def sync(self, canvas, rect): | |
self.__canvas = canvas | |
self.__rectptr = rect | |
self.__update() | |
""" | |
Returns true if the Rectangle2D is synced with the tkinter rectangle. | |
""" | |
def __synced(self): | |
return self.__canvas != None and self.__rectptr != None | |
""" | |
Updates the front-end tkinter rectangle according to the Rectangle2D's properties. | |
Raises an exception if the Rectangle2D was never synced with tkinter's canvas. | |
Return - No value. | |
""" | |
def __update(self): | |
if (not self.__synced()): | |
raise Exception() | |
left_x = self.__centerX - self.__width / 2 | |
left_y = self.__centerY - self.__height / 2 | |
right_x = self.__centerX + self.__width / 2 | |
right_y = self.__centerY + self.__height / 2 | |
# Move the rectangle. | |
self.__canvas.coords( | |
self.__rectptr, (left_x, left_y, right_x, right_y)) | |
class Application: | |
RECT_THICKNESS = 3 | |
INTERSECT = "Rectangles are intersecting" | |
NOT_INTERSECT = "Rectangles are not intersecting" | |
def __init__(self, master, width, height): | |
# Frame that contains all other frames. | |
root = Frame(master) | |
input_frame = Frame(root) | |
# Properties | |
self.__label = Label(root, font = "Calibri 20 bold") | |
self.__canvas = Canvas(root) | |
self.__moving = None | |
self.__current_rect = None | |
self.__rectangles = {} | |
self.__inputs = [] | |
# Window Specifications | |
master.resizable(False, False) | |
master.minsize(width, height) | |
master.maxsize(width, height) | |
# Packing. | |
root.pack() | |
self.__label.pack() | |
self.__canvas.pack(fill = BOTH, expand = YES) | |
input_frame.pack() | |
# Canvas settings | |
self.__canvas.config(height = height * 0.75, width = width * 0.75, highlightbackground = "RED") | |
# Function which initializes movement of rectangles via the mouse. | |
def callback_move_start(event): | |
""" | |
Determine the back-end rectangle that corresponds to the | |
front-end rectangle that lies underneath the mouse cursor. | |
""" | |
selected = self.__canvas.find_withtag(CURRENT) | |
# User did not select anything. | |
if (len(selected) == 0): | |
self.__current_rect = None | |
return | |
self.__current_rect = self.__rectangles[selected[0]] | |
self.__current_rect.setCenter(event.x, event.y) | |
# Function which moves rectangles via the mouse during drag events. | |
def callback_move_drag(event): | |
rect = self.__current_rect | |
if (rect == None): | |
return | |
rect.setCenter(event.x, event.y) | |
self.__check_collision() | |
self.__canvas.bind("<Button-1>", lambda event: callback_move_start(event)) | |
self.__canvas.bind("<B1-Motion>", lambda event: callback_move_drag(event)) | |
# Input fields. | |
LABELS_TEXT = ("Center x", "Center y", "Width", "Height") | |
for i in range(len(LABELS_TEXT)): | |
def callback(sv, field): | |
rect = self.__current_rect | |
# If no rectangle is clicked, disregard this. | |
if (rect == None): | |
return | |
# Make sure the input is valid. | |
newValue = None | |
try: | |
newValue = int(sv.get()) | |
except ValueError: | |
return | |
if (field == 0): | |
rect.setCenter(newValue, rect.getCenterY()) | |
elif (field == 1): | |
rect.setCenter(rect.getCenterX(), newValue) | |
elif (field == 2): | |
rect.setWidth(newValue) | |
else: | |
rect.setHeight(newValue) | |
# Variable which controls the text of the entry. | |
sv = StringVar() | |
# Whenever the text changes, notify the callback function. | |
sv.trace("w", lambda name, index, mode, sv = sv, field = i: callback(sv, field)) | |
lbl = Label(input_frame, font = "Calibri 15", text = LABELS_TEXT[i]) | |
input = Entry(input_frame, textvariable = sv) | |
lbl.grid(row = i) | |
input.grid(column = 1, row = i) | |
""" | |
Adds the provided rectangle to the graphical interface. | |
rect - Rectangle2D object. | |
color - Color of the rectangle. | |
Return - No value. | |
""" | |
def addRectangle(self, rect, color): | |
# Create an empty front-end rectangle. | |
tk_rect = self.__canvas.create_rectangle(0, 0, 0, 0, | |
width = self.RECT_THICKNESS, outline = "black", | |
fill = color, tags = ('rect')) | |
rect.sync(self.__canvas, tk_rect) | |
self.__rectangles[tk_rect] = rect | |
self.__check_collision() | |
""" | |
Changes the label of the GUI according to if rectangles | |
are currently intersecting or not. Checks each rectangle | |
with all other rectangles to determine collision. | |
Return - No value. | |
""" | |
def __check_collision(self): | |
for k1, v1 in self.__rectangles.items(): | |
for k2, v2 in self.__rectangles.items(): | |
if (v1 == v2): | |
continue | |
if (v1.intersects(v2)): | |
self.__label.config(text = self.INTERSECT) | |
return | |
self.__label.config(text = self.NOT_INTERSECT) | |
def main(): | |
WIN_WIDTH = 600 | |
WIN_HEIGHT = 700 | |
root = Tk() | |
a = Application(root, WIN_WIDTH, WIN_HEIGHT) | |
a.addRectangle(Rectangle2D(50, 50, 30, 40), "green") | |
a.addRectangle(Rectangle2D(150, 150, 90, 90), "pink") | |
root.mainloop() | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment