Skip to main content

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.

Metadata

Release files for ctk-interactive-canvas 0.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ctk-interactive-canvas 0.9.0
File Size Uploaded
ctk_interactive_canvas-0.9.0.tar.gz 52.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ctk-interactive-canvas 0.9.0
File Interpreter ABI Platform
ctk_interactive_canvas-0.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 89.7 kB

Release files / ctk_interactive_canvas-0.9.0.tar.gz

Download URL ctk_interactive_canvas-0.9.0.tar.gz
Size 52.7 kB
Tags Source
SHA-256 checksum
How to use checksums
90b0e4c3a4549e2f2d9f82f6a34436aed7ec351222be1c5dae3fdd30d6349720
BLAKE2b-256 checksum
How to use checksums
d9cb4e153fbd8ab48882e9b6e75541e48e74c892d7c63766b9a65b847e1c523a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / ctk_interactive_canvas-0.9.0-py3-none-any.whl

Download URL ctk_interactive_canvas-0.9.0-py3-none-any.whl
Size 37.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b0870dd5cc40c020e41b6767ba281e04a4555773eb827b5fc8cc9845be852867
BLAKE2b-256 checksum
How to use checksums
2c3f8a4de85ed988527096335a01ffc0fdab5abb01894917feb303012ebb4426
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

0.9.0 This release

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page