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.

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

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.2.tar.gz (26.7 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.2-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ctk_interactive_canvas-0.3.2.tar.gz
  • Upload date:
  • Size: 26.7 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.3.2.tar.gz
Algorithm Hash digest
SHA256 c4fec708eeaa87773938ab4b35330a1dd77baeed5d326f0ef50df4197377ae57
MD5 aa27239a0b586d564dd570271ecc202d
BLAKE2b-256 4ef30e862a7c5678b44717bd40a2c93bb4137e722e809c6f90dc8df1ded5a6af

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ctk_interactive_canvas-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6c1de561b67def175ee6cd460f92896dea75863cc24daf7678bac312ef837530
MD5 96f843353e68edd69f90362c588a905e
BLAKE2b-256 305b3ffcae729d7282aca5339bb8a3d42a57f2b760c0304b194625812b8f050c

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