Skip to main content

Interactive canvas widget for CustomTkinter with draggable, resizable rectangles

Project description

CTk Interactive Canvas

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.

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

  • Adobe Illustrator-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=2)
rect2 = canvas.create_draggable_rectangle(200, 200, 300, 300, outline='red', width=2)

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=2,
    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

MIT License - see LICENSE file for details.

Credits

Author

T. K. Joram Smith (DeltaGa)

Acknowledgments

  • CustomTkinter - Modern UI framework
  • Python Community - Continuous ecosystem evolution

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Changelog

See CHANGELOG.md for version history.

Support


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.3.0.dev1.tar.gz (25.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.3.0.dev1-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file ctk_interactive_canvas-0.3.0.dev1.tar.gz.

File metadata

File hashes

Hashes for ctk_interactive_canvas-0.3.0.dev1.tar.gz
Algorithm Hash digest
SHA256 84b90a3b073398e67cf3695d23f08adc472ca98446a8ea2328d4a7db46714e96
MD5 137560cf21efa3ab39a99c845886facc
BLAKE2b-256 100b7d1b45af1ee3ee7728d740897a4111ed0e79b986b18d80b23c32a715878f

See more details on using hashes here.

File details

Details for the file ctk_interactive_canvas-0.3.0.dev1-py3-none-any.whl.

File metadata

File hashes

Hashes for ctk_interactive_canvas-0.3.0.dev1-py3-none-any.whl
Algorithm Hash digest
SHA256 cc4171dc1b22ed79158ea460238fc67e0e1f155fbe702cee4c3af95308676cd0
MD5 195e555a777005d19113485eefc6fa15
BLAKE2b-256 6165d49a6d7f011893e1477be245d61d04c3c14a4ef6c8e06bb29841300eb6fa

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