Skip to main content

Interactive canvas widget for CustomTkinter with draggable, resizable rectangles

Project description

CTk Interactive Canvas

CodeFactor Python version PyPi version PyPi status PyPi downloads Star this repo

Interactive canvas widget for CustomTkinter with draggable, resizable rectangles featuring multi-selection, alignment, distribution, and professional-grade interaction controls.

Table of Contents

Features

Core Capabilities

  • Draggable Rectangles: Click and drag to move objects
  • Resizable Objects: Bottom-right handle for intuitive resizing
  • Multi-Selection: Shift-click or drag-select multiple objects
  • Alignment Tools: Align multiple rectangles (top, middle, bottom, start, center, end)
  • Distribution Tools: Evenly distribute rectangles horizontally or vertically
  • Panning: Middle-mouse or Space+drag to pan the canvas

Professional Controls

  • Editor-style Constraints:
    • Shift during move: Lock to 45-degree angles (0°, 45°, 90°, 135°, etc.)
    • Shift during resize: Maintain aspect ratio
    • Ctrl during resize: Resize from center
    • Alt during resize: Constrain to one dimension
    • Shift+Ctrl during resize: Aspect ratio + center resize

Advanced Features

  • 26 Magic Methods: NumPy-like interface for geometric operations
  • Unit Conversion: Built-in mm ↔ px conversion with DPI support
  • Intersection & Union: Geometric operations via & and | operators
  • Point Containment: Test if coordinates are inside rectangles
  • Sorting & Comparison: Area-based ordering and equality testing
  • Coordinate Access: Index-based access and iteration

Installation

pip install ctk-interactive-canvas

Quick Start

import customtkinter as ctk
from ctk_interactive_canvas import InteractiveCanvas

root = ctk.CTk()
root.title("Interactive Canvas Demo")

canvas = InteractiveCanvas(root, width=800, height=600, bg='white')
canvas.pack()

rect1 = canvas.create_draggable_rectangle(50, 50, 150, 150, outline='blue', width=5)
rect2 = canvas.create_draggable_rectangle(200, 200, 300, 300, outline='red', width=5)

root.mainloop()

Usage Examples

Basic Rectangle Creation

canvas = InteractiveCanvas(root, width=800, height=600, bg='white')
canvas.pack()

rect = canvas.create_draggable_rectangle(
    x1=100, y1=100,
    x2=200, y2=200,
    outline='blue',
    width=5,
    fill=''
)

Selection Callbacks

def on_select():
    selected = canvas.get_selected()
    print(f"Selected: {len(selected)} objects")

def on_deselect():
    print("Selection cleared")

canvas = InteractiveCanvas(
    root,
    width=800,
    height=600,
    select_callback=on_select,
    deselect_callback=on_deselect
)

Alignment and Distribution

from ctk_interactive_canvas import DraggableRectangle

rectangles = [rect1, rect2, rect3]

DraggableRectangle.align(rectangles, mode='center')
DraggableRectangle.distribute(rectangles, mode='horizontal')

Mathematical Operations

translated = rect + [50, 30]

doubled = rect * 2

halved = rect / 2

rect += [10, 10]

intersection = rect1 & rect2
bounding = rect1 | rect2

if [x, y] in rect:
    print("Point inside rectangle!")

sorted_rects = sorted([rect1, rect2, rect3])

Unit Conversion

rect = canvas.create_draggable_rectangle(0, 0, 100, 100)

pos_mm = rect.get_topleft_pos(in_mm=True, dpi=300)
print(f"Position in mm: {pos_mm}")

rect.set_size([50, 50], in_mm=True, dpi=300)

Coordinate Access

x0, y0, x1, y1 = rect

rect[2] = 300

coords = rect[:]

for coord in rect:
    print(coord)

Keyboard Modifiers

Action Modifier Behavior
Move Shift Lock to 45° angles
Resize Shift Maintain aspect ratio
Resize Ctrl Resize from center
Resize Alt Constrain to one axis
Resize Shift+Ctrl Aspect ratio + center
Pan Space Enable pan mode
Select Shift+Click Add to selection
Delete Delete Remove selected

API Reference

InteractiveCanvas

InteractiveCanvas(
    master=None,
    select_callback=None,
    deselect_callback=None,
    delete_callback=None,
    select_outline_color='#16fff6',
    dpi=300,
    create_bindings=True,
    **kwargs
)

Methods:

  • create_draggable_rectangle(x1, y1, x2, y2, **kwargs) → DraggableRectangle
  • copy_draggable_rectangle(rect, offset=[21, 21], **kwargs) → DraggableRectangle
  • delete_draggable_rectangle(item_id) → None
  • get_selected() → List[DraggableRectangle]
  • get_draggable_rectangle(item_id) → DraggableRectangle
  • select_all() → None
  • deselect_all() → None

DraggableRectangle

Position & Size:

  • get_topleft_pos(relative_pos=None, in_mm=False, dpi=None) → [x, y]
  • set_topleft_pos(new_pos, relative_pos=None, in_mm=False, dpi=None)
  • get_size(in_mm=False, dpi=None) → [width, height]
  • set_size(new_size, in_mm=False, dpi=None)

Transformations:

  • safe_rotate(angle, anchor='topleft') - Rotate 90°/180°/-90°/-180°
  • copy_(offset=[50, 50], **kwargs) → DraggableRectangle

Class Methods:

  • align(rectangles, mode, relative_pos=None) - Align multiple rectangles
  • distribute(rectangles, mode, relative_pos=None) - Distribute evenly
  • compare(rect1, rect2) → (bool, dict) - Compare two rectangles
  • get_instances() → List[DraggableRectangle] - Get all alive instances

Magic Methods:

  • Arithmetic: +, -, *, /, +=, -=, *=, /=
  • Comparison: ==, !=, <, <=, >, >=
  • Bitwise: & (intersection), | (union)
  • Unary: -, +, abs()
  • Container: len(), [], in, iter()
  • Representation: str(), repr(), format(), bool(), hash()

Requirements

  • Python ≥ 3.9
  • CustomTkinter ≥ 5.1.0

Development

Install Development Dependencies

pip install -e ".[dev]"

Run Tests

pytest

Code Quality

black .
ruff check .
mypy src/ctk_interactive_canvas

License

See LICENSE file for details.

Contributing

See CONTRIBUTING.md for guidelines.

Changelog

See CHANGELOG.md for version history.

Credits

Author

T. K. Joram Smith (DeltaGa)

Acknowledgments


Note: This package is in active development. APIs may change between minor versions until 1.0.0 release.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ctk_interactive_canvas-0.6.0.tar.gz (42.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ctk_interactive_canvas-0.6.0-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

Details for the file ctk_interactive_canvas-0.6.0.tar.gz.

File metadata

  • Download URL: ctk_interactive_canvas-0.6.0.tar.gz
  • Upload date:
  • Size: 42.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ctk_interactive_canvas-0.6.0.tar.gz
Algorithm Hash digest
SHA256 d5f2230bc66e64320b963fb3c080087cc29768f9add937173b1f673b23ec30f7
MD5 e7f39a373b9addf50c0bff46789bb8ff
BLAKE2b-256 eba785f921f169e40dfc13f76fa1403303612659b48c240b901f7684a3ec6f50

See more details on using hashes here.

File details

Details for the file ctk_interactive_canvas-0.6.0-py3-none-any.whl.

File metadata

File hashes

Hashes for ctk_interactive_canvas-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 700618532222d2bd050dcf36cb6029e417dcebb3be9b404e5fd106b864dc64b2
MD5 e111e2eab534f3bb8a4179ff74da24a1
BLAKE2b-256 4f197fe8631c2bc30a1277a00db9a1d059d1cf35a7e1f2189cd332d326215a4b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page