Jan-09-2025, 05:33 PM
(This post was last modified: Jan-09-2025, 08:50 PM by deanhystad.)
Here is my code, and I want when I scale my grid, it will scale where the cursor is and smoothly move to the middle of the screen. Similar to how AutoCAD does it. Basically I want the cursor to be my zoom focus. For now it scales by making the center of the canvas the zoom focus.
import tkinter as tk
import json
def create_grid(canvas, grid_size, color="black"):
"""Draws a grid on the canvas."""
canvas.delete("grid")
max_width = max_columns * grid_size
max_height = max_rows * grid_size
for x in range(0, max_width + 1, grid_size):
canvas.create_line(x, 0, x, max_height, fill=color, dash=(1, 3), tags="grid")
for y in range(0, max_height + 1, grid_size):
canvas.create_line(0, y, max_width, y, fill=color, dash=(1, 3), tags="grid")
canvas.config(scrollregion=(0, 0, max_width, max_height)) # Limit scrolling
def add_text_to_grid(canvas, row, col, text, font=("Arial", 12)):
"""Adds a text element aligned to the grid, within limits."""
if 0 <= row < max_rows and 0 <= col < max_columns:
x = col * grid_size
y = row * grid_size
item = canvas.create_text(x, y, text=text, font=font, tags="grid_text", anchor="center")
text_items.append({"item": item, "row": row, "col": col})
else:
print("Cannot place text outside the grid limits.")
def update_text_positions():
"""Updates text positions when the grid size changes."""
for text in text_items:
row, col = text["row"], text["col"]
if 0 <= row < max_rows and 0 <= col < max_columns:
x = col * grid_size
y = row * grid_size
canvas.coords(text["item"], x, y)
def on_mouse_wheel(event):
"""Zooms in or out with the mouse wheel, centered at the cursor."""
global grid_size, offset_x, offset_y
# Get cursor position relative to canvas
cursor_x = canvas.canvasx(event.x)
cursor_y = canvas.canvasy(event.y)
# Calculate zoom factor
if event.delta > 0: # Scroll up
new_grid_size = max(grid_size - 5, 10) # Minimum grid size is 10
else: # Scroll down
new_grid_size = min(grid_size + 5, 191) # Maximum grid size is 191
# Zoom adjustment ratio
if new_grid_size != grid_size:
zoom_ratio = new_grid_size / grid_size
# Adjust offsets to keep the cursor centered
offset_x = cursor_x - (cursor_x - offset_x) * zoom_ratio
offset_y = cursor_y - (cursor_y - offset_y) * zoom_ratio
grid_size = new_grid_size
create_grid(canvas, grid_size)
update_text_positions()
# Update canvas view
canvas.xview_moveto(offset_x / (max_columns * grid_size))
canvas.yview_moveto(offset_y / (max_rows * grid_size))
def on_mouse_drag_start(event):
"""Start dragging the canvas."""
global start_x, start_y
start_x = event.x
start_y = event.y
def on_mouse_drag(event):
"""Handle dragging the canvas."""
global start_x, start_y, offset_x, offset_y
dx = start_x - event.x
dy = start_y - event.y
# Update offsets with boundaries
max_width = max_columns * grid_size - canvas.winfo_width()
max_height = max_rows * grid_size - canvas.winfo_height()
offset_x = max(0, min(offset_x + dx, max_width))
offset_y = max(0, min(offset_y + dy, max_height))
canvas.xview_moveto(offset_x / (max_columns * grid_size))
canvas.yview_moveto(offset_y / (max_rows * grid_size))
# Update starting position for smooth dragging
start_x = event.x
start_y = event.y
def save_settings():
"""Saves the grid size to a settings file."""
data = {"grid_size": grid_size}
with open("settings.json", "w") as f:
json.dump(data, f)
def load_settings():
"""Loads the grid size from a settings file."""
try:
with open("settings.json", "r") as f:
data = json.load(f)
return data.get("grid_size", 100) # Default grid size is 100
except FileNotFoundError:
return 100
# Initialize variables
grid_size = load_settings()
text_items = []
start_x = start_y = 0
offset_x = offset_y = 0
# Define maximum rows and columns for the grid
max_rows = 101 # Maximum number of rows
max_columns = 192 # Maximum number of columns
# Create the main window and canvas
window = tk.Tk()
window.title("Zoomable Grid with Cursor-Centered Zoom")
# Set the window to start maximized
window.state("zoomed")
canvas = tk.Canvas(window, bg="white")
canvas.pack(fill="both", expand=True)
# Create grid and add elements
create_grid(canvas, grid_size)
add_text_to_grid(canvas, 4, 5, "Center") # Aligned to row 4, column 5
add_text_to_grid(canvas, 2, 1, "Random") # Aligned to row 2, column 1
# Bind events
window.protocol("WM_DELETE_WINDOW", lambda: (save_settings(), window.destroy()))
canvas.bind("<Control-MouseWheel>", on_mouse_wheel)
canvas.bind("<ButtonPress-1>", on_mouse_drag_start)
canvas.bind("<B1-Motion>", on_mouse_drag)
window.mainloop()
deanhystad write Jan-09-2025, 08:50 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
