Interactive canvas widget for CustomTkinter with draggable, resizable rectangles
Project description
CTk Interactive Canvas
Interactive canvas widget for CustomTkinter with draggable, resizable rectangles featuring multi-selection, alignment, distribution, and professional-grade interaction controls.
Table of Contents
- Features
- Installation
- Quick Start
- Usage Examples
- Keyboard Modifiers
- API Reference
- Requirements
- Development
- License
- Contributing
- Changelog
- Credits
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)→ DraggableRectanglecopy_draggable_rectangle(rect, offset=[21, 21], **kwargs)→ DraggableRectangledelete_draggable_rectangle(item_id)→ Noneget_selected()→ List[DraggableRectangle]get_draggable_rectangle(item_id)→ DraggableRectangleselect_all()→ Nonedeselect_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 rectanglesdistribute(rectangles, mode, relative_pos=None)- Distribute evenlycompare(rect1, rect2)→ (bool, dict) - Compare two rectanglesget_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)
- Email: dev.github.tkjoramsmith@outlook.com
- GitHub: @DeltaGa
Acknowledgments
- CustomTkinter - Modern UI framework
Note: This package is in active development. APIs may change between minor versions until 1.0.0 release.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ctk_interactive_canvas-0.4.3.tar.gz.
File metadata
- Download URL: ctk_interactive_canvas-0.4.3.tar.gz
- Upload date:
- Size: 37.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4131f132902774d4bd94b46057e3adae1c5d12a093a8465f09cda606f81a1964
|
|
| MD5 |
7569b0be84d842ace28e31f11107ec3f
|
|
| BLAKE2b-256 |
144fbef9447f2679ed4a1d3b9437c5d22d2b4a60a20d96a1e4e540b1742b939f
|
File details
Details for the file ctk_interactive_canvas-0.4.3-py3-none-any.whl.
File metadata
- Download URL: ctk_interactive_canvas-0.4.3-py3-none-any.whl
- Upload date:
- Size: 25.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcde7071e126b947349e1906a4f2bfd9d5caeae40bb5fc0515245db7729e5a26
|
|
| MD5 |
0d799970c722537bf47e89ce8bd03787
|
|
| BLAKE2b-256 |
cae8bc056432d6ef0bd52aeb5d6e757e7097b099bac5ba99ee829279020a8f41
|