0% found this document useful (0 votes)
7 views4 pages

Tkinter Drawing Application Code

Uploaded by

ahmadsalih889
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views4 pages

Tkinter Drawing Application Code

Uploaded by

ahmadsalih889
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

from tkinter import *

from [Link] import askcolor

class DrawingApp:
def __init__(self, root):
[Link] = root
[Link] = Canvas([Link], width=800, height=600, bg="white")
[Link](side=BOTTOM, padx=10, pady=10)

# Create buttons frame


button_frame = Frame([Link])
button_frame.pack(side=TOP)

# Create buttons for shape selection


self.create_shape_button("Line", "line", button_frame)
self.create_shape_button("Rectangle", "rectangle", button_frame)
self.create_shape_button("Circle", "circle", button_frame)
# Create button for tool selection
self.create_tool_button("Select", button_frame)

# Create button frame for color selection, fill, and thickness buttons
button_frame2 = Frame([Link])
button_frame2.pack(side=TOP)

# Create button for color selection


self.color_button = Button(button_frame2, text="Select Color",
command=self.select_color)
self.color_button.pack(side=LEFT, pady=5)

# Create button for color filling


self.fill_button = Button(button_frame2, text="Fill",
command=self.set_fill_mode)
self.fill_button.pack(side=LEFT, pady=5, padx=5)

# Create button and slider for thickness selection


self.thickness_button = Button(button_frame2, text="Thickness",
command=self.create_thickness_slider)
self.thickness_button.pack(side=LEFT, pady=5)

[Link] = "Draw" # Current tool (Draw or Select)


self.selected_shape = None
self.selected_color = "black" # Default color
[Link] = []
[Link] = 1 # Default thickness

# Binding mouse events


[Link]("<Button-1>", self.handle_mouse_click)
[Link]("<B1-Motion>", self.handle_mouse_motion)
[Link]("<ButtonRelease-1>", self.handle_mouse_release)
[Link]("<Button-3>", self.select_shape)
[Link]("<B3-Motion>", self.move_shape)
[Link]("<Delete>", self.delete_shape)
[Link]("<BackSpace>", self.delete_shape)

def create_shape_button(self, text, shape_type, parent_frame):


button = Button(parent_frame, text=text, command=lambda:
self.set_selected_shape(shape_type))
[Link](side=LEFT, padx=5)
def create_tool_button(self, tool_type, parent_frame):
button = Button(parent_frame, text=tool_type, command=lambda:
self.set_tool(tool_type))
[Link](side=LEFT, padx=5)

def create_thickness_slider(self):
self.thickness_slider = Scale([Link], from_=1, to=10, orient=HORIZONTAL,
command=self.update_thickness)
self.thickness_slider.pack(pady=5)

def update_thickness(self, value):


[Link] = int(value)

def set_selected_shape(self, shape_type):


self.selected_shape = shape_type
self.set_tool("Draw") # Switch to Draw mode when a shape is selected

def set_tool(self, tool_type):


[Link] = tool_type

def set_fill_mode(self):
[Link] = "Fill"

def select_color(self):
color = askcolor(color=self.selected_color)[1]
if color:
self.selected_color = color

def handle_mouse_click(self, event):


if [Link] == "Draw":
self.start_drawing(event)
elif [Link] == "Select":
self.select_shape(event)
elif [Link] == "Fill":
self.fill_shape(event)

def handle_mouse_motion(self, event):


if [Link] == "Draw":
self.draw_shape(event)
elif [Link] == "Select":
self.move_shape(event)

def handle_mouse_release(self, event):


if [Link] == "Draw":
self.end_drawing(event)
elif [Link] == "Select":
pass

def start_drawing(self, event):


self.start_x = event.x
self.start_y = event.y

def draw_shape(self, event):


if self.selected_shape == "line":
[Link]("temp_shape")
[Link].create_line(self.start_x, self.start_y, event.x, event.y,
tags="temp_shape",
fill=self.selected_color, width=[Link])
elif self.selected_shape == "rectangle":
[Link]("temp_shape")
[Link].create_rectangle(self.start_x, self.start_y, event.x,
event.y, tags="temp_shape",
fill=self.selected_color,
outline=self.selected_color, width=[Link])
elif self.selected_shape == "circle":
[Link]("temp_shape")
[Link].create_oval(self.start_x, self.start_y, event.x, event.y,
tags="temp_shape",
fill=self.selected_color,
outline=self.selected_color, width=[Link])

def end_drawing(self, event):


[Link]("temp_shape")
if self.selected_shape == "line":
shape = [Link].create_line(self.start_x, self.start_y, event.x,
event.y, fill=self.selected_color,
width=[Link])
elif self.selected_shape == "rectangle":
shape = [Link].create_rectangle(self.start_x, self.start_y,
event.x, event.y, fill=self.selected_color,
outline=self.selected_color,
width=[Link])
elif self.selected_shape == "circle":
shape = [Link].create_oval(self.start_x, self.start_y, event.x,
event.y, fill=self.selected_color,
outline=self.selected_color,
width=[Link])
[Link](shape)

def fill_shape(self, event):


# Get the shape that is under the cursor
selected_shape = [Link].find_withtag(CURRENT)
if selected_shape:
if [Link](selected_shape) == "line":
# Change the color of the line
[Link](selected_shape, fill=self.selected_color)
else:
# Change the color of the shape
[Link](selected_shape, fill=self.selected_color,
outline=self.selected_color)

def select_shape(self, event):


# Get the shape that is under the cursor
selected_shape = [Link].find_withtag(CURRENT)
if selected_shape:
self.selected_shape = selected_shape[0]
self.set_tool("Select") # Switch to Select mode when a shape is
selected

# Save the coordinates of the cursor at the moment of selection


self.selection_point_x = event.x
self.selection_point_y = event.y
else:
self.selected_shape = None

def move_shape(self, event):


if self.selected_shape:
# Calculate the distance the cursor has moved from the point of
selection
delta_x = event.x - self.selection_point_x
delta_y = event.y - self.selection_point_y

# Move the shape by this distance


[Link](self.selected_shape, delta_x, delta_y)

# Update the selection point to the new cursor position


self.selection_point_x = event.x
self.selection_point_y = event.y

def delete_shape(self, event):


if self.selected_shape:
[Link](self.selected_shape)
[Link](self.selected_shape)
self.selected_shape = None

if __name__ == "__main__":
root = Tk()
[Link]("Drawing App")
app = DrawingApp(root)
[Link]()

Common questions

Powered by AI

The DrawingApp orchestrates interaction between shape drawing and other functionalities through tightly bound event handlers and state management. The initial selection of a shape or tool inherently shifts the app's state, controlled by set_tool and set_selected_shape methods. This transition updates the relevant tool states (like 'Draw' or 'Select'), affecting how mouse events are processed, thus limiting user operations to task-specific commands. For example, selecting the 'Fill' tool allows users to change colors on existing shapes while selecting ‘Draw’ lets them create new shapes. Furthermore, functions like select_color directly update selected attributes without disrupting the ongoing process, providing seamless switching due to consistent method invocations that reflect tool and shape updates across all components. This cohesive interplay orchestrated by event-driven logic supports a polished user experience without inadvertent cross-functional interference .

The current implementation, which computes shape movement based on real-time cursor changes using relative deltas captured from initial selection points, is efficient for single-user interaction but poses challenges for collaborative use or advanced enhancement. For collaboration, synchronization of cursor data between users could result in complex conflict resolutions due to simultaneous modifications on the same shape. Additionally, for feature enhancement, managing precision alignment or grouping shapes may require a more sophisticated movement protocol incorporating snapping, guidelines, or layers. Such extensions demand robust event handling modifications, locking mechanisms for concurrency, and potentially a more structured model-view-controller architecture to manage interactions better and support future scalability in multi-user or complex functionality setups .

In fill mode, the DrawingApp changes the color of a selected shape through the fill_shape method. When a user clicks on a shape in fill mode, the shape under the cursor is identified using canvas.find_withtag(CURRENT). If the shape is a line, its color is changed using the canvas.itemconfig method with the fill keyword, while for other shapes, both fill and outline colors are set to the selected color using the same method. This ensures that the shape is visually updated according to the current color selection .

The askcolor method plays a crucial role in enabling color selection in the DrawingApp. It is used to open a color dialog window that prompts users to select a color. This method is integrated into the user interface via the 'Select Color' button, configured with a command attribute set to call the select_color method. Within select_color, upon user's color selection, askcolor returns a tuple, where the second element is the hexadecimal representation of the selected color. If a valid color is chosen, it updates self.selected_color, effectively changing the color option for shapes to be drawn or filled, thereby integrating an interactive element for enhanced user engagement with color customization options .

The sequence begins when a user clicks a shape tool button (such as 'Line', 'Rectangle', or 'Circle'), triggering a command set by create_shape_button to call set_selected_shape with the shape_type parameter. set_selected_shape assigns the shape type to self.selected_shape and switches the application to 'Draw' mode using set_tool('Draw'). When the user clicks on the canvas, it calls handle_mouse_click, recognized by <Button-1> binding, which invokes start_drawing, storing initial coordinates (start_x, start_y). As the mouse moves with <B1-Motion>, handle_mouse_motion executes draw_shape, continuously removing ('temp_shape') and redrawing the selected shape with current mouse coordinates. Upon release of the mouse button, handle_mouse_release calls end_drawing, permanently adding the final shape to the canvas and self.shapes list .

The delete functionality in the DrawingApp is implemented using the delete_shape method, which is triggered by pressing the Delete or BackSpace keys. When this method is invoked, it first checks if there's any shape currently selected (indicated by self.selected_shape). If a shape is selected, it's removed from the canvas with the canvas.delete(self.selected_shape) function call. Additionally, this shape is removed from the internal list self.shapes that tracks all drawn shapes. Lastly, the self.selected_shape is set to None, representing the updated application state that no shape is currently selected for further actions. This maintains the integrity by updating both the UI and internal state consistently .

The DrawingApp allows users to dynamically set the thickness of shapes through a thickness slider. When the 'Thickness' button is pressed, the create_thickness_slider method is called, which creates a Scale widget ranging from 1 to 10, orientated horizontally. This slider is displayed in the interface, allowing users to adjust it as needed. The thickness value is updated in real-time through the command callback set in the Scale widget, which calls the update_thickness method with the new value. This value is then converted to an integer and stored in self.thickness, influencing the width of lines and borders of shapes drawn henceforth .

The DrawingApp implements shape selection and movement through mouse events. When the user clicks on a shape, the event <Button-3> triggers the select_shape method, which sets the clicked shape as selected by finding the shape under the current mouse position with the canvas.find_withtag(CURRENT) call, and then switches to 'Select' mode. The coordinates of the cursor at selection time are stored in selection_point_x and selection_point_y. For movement, the event <B3-Motion> calls the move_shape method, which calculates the displacement delta_x and delta_y from the initial selection point by subtracting selection_point_x and selection_point_y from the current mouse coordinates. The method then moves the shape using canvas.move(self.selected_shape, delta_x, delta_y) and updates the selection point to the new cursor position .

The DrawingApp differentiates between various tools by setting the tool state with the set_tool method. Initially, the default tool is set to 'Draw'. Users can switch tools by pressing corresponding buttons created through create_tool_button, such as 'Select'. Each tool modifies how mouse events are handled. For instance, in 'Draw' mode, mouse actions initiate shape creation with start_drawing, draw_shape, and end_drawing methods. In 'Select' mode, the tools function to select, move, or delete an object. This method-based tool assignment creates distinct interactive layers, enabling smooth transitions and differentiated functionality between drawing, selecting, and editing modes, thereby shaping user control workflow in the application .

During the drawing process, the DrawingApp ensures that temporary shapes are not persistently drawn by using a tag-based identification mechanism. The draw_shape method utilizes a unique tag 'temp_shape' to label graphical elements immediately when they are drawn by functions like canvas.create_line, canvas.create_rectangle, and canvas.create_oval. By applying canvas.delete('temp_shape') before redrawing the shape at any new mouse position, it removes previously drawn temporary representations, which helps in dynamically updating only the current canvas visualization instead of permanently rendering incomplete shapes .

You might also like