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.