CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pytermtk

Python Terminal Toolkit for creating sophisticated text-based user interfaces with Qt-like API and full widget support

Pending
Overview
Eval results
Files

event-system.mddocs/

Event System

Signal-slot communication system for event handling and inter-widget communication patterns.

Capabilities

Signal Class

pyTTkSignal provides the signal mechanism for event communication between objects.

class pyTTkSignal:
    def __init__(self, *types):
        """
        Initialize a signal.
        
        Parameters:
        - types: Type hints for signal parameters (optional)
        """
    
    def connect(self, slot):
        """
        Connect a slot function to this signal.
        
        Parameters:
        - slot: Function or method to call when signal is emitted
        """
    
    def disconnect(self, slot=None):
        """
        Disconnect a slot from this signal.
        
        Parameters:
        - slot: Specific slot to disconnect, or None to disconnect all
        """
    
    def emit(self, *args):
        """
        Emit the signal with optional arguments.
        
        Parameters:
        - args: Arguments to pass to connected slots
        """
    
    def isConnected(self):
        """Check if any slots are connected to this signal."""
    
    def connectionCount(self):
        """Get the number of connected slots."""
    
    def blockSignals(self, blocked):
        """Block or unblock signal emission."""
    
    def signalsBlocked(self):
        """Check if signals are blocked."""

Slot Decorator

pyTTkSlot decorator marks functions as slots for signal connection.

def pyTTkSlot(*types):
    """
    Decorator to mark a function as a slot.
    
    Parameters:
    - types: Expected parameter types (optional, for type checking)
    
    Returns:
    Decorated function that can be connected to signals
    
    Usage:
    @pyTTkSlot()
    def my_slot():
        pass
    
    @pyTTkSlot(int, str)
    def typed_slot(number, text):
        pass
    """

Event Classes

Event objects that carry information about user interactions and system events.

class TTkKeyEvent:
    def __init__(self, type, key, text="", modifiers=0):
        """
        Initialize a keyboard event.
        
        Parameters:
        - type (int): Event type (KeyPress, KeyRelease)
        - key (int): Key code constant
        - text (str): Text representation of key
        - modifiers (int): Modifier keys (Ctrl, Alt, Shift)
        """
    
    def type(self):
        """Get the event type."""
    
    def key(self):
        """Get the key code."""
    
    def text(self):
        """Get the text representation."""
    
    def modifiers(self):
        """Get the modifier keys."""
    
    def matches(self, key_sequence):
        """Check if event matches a key sequence."""
    
    def accept(self):
        """Accept the event (stops propagation)."""
    
    def ignore(self):
        """Ignore the event (allows propagation)."""
    
    def isAccepted(self):
        """Check if event is accepted."""

class TTkMouseEvent:
    def __init__(self, type, pos, button, buttons, modifiers):
        """
        Initialize a mouse event.
        
        Parameters:
        - type (int): Event type (MousePress, MouseRelease, MouseMove)
        - pos (TTkPoint): Mouse position
        - button (int): Button that caused the event
        - buttons (int): All pressed buttons
        - modifiers (int): Modifier keys
        """
    
    def type(self):
        """Get the event type."""
    
    def pos(self):
        """Get the mouse position."""
    
    def x(self):
        """Get the x coordinate."""
    
    def y(self):
        """Get the y coordinate."""
    
    def button(self):
        """Get the button that caused the event."""
    
    def buttons(self):
        """Get all pressed buttons."""
    
    def modifiers(self):
        """Get the modifier keys."""
    
    def accept(self):
        """Accept the event."""
    
    def ignore(self):
        """Ignore the event."""
    
    def isAccepted(self):
        """Check if event is accepted."""

Timer Class

TTkTimer provides timing functionality for periodic events and delayed actions.

class TTkTimer:
    def __init__(self, parent=None):
        """Initialize a timer."""
    
    def start(self, msec=None):
        """
        Start the timer.
        
        Parameters:
        - msec (int): Interval in milliseconds (optional if set before)
        """
    
    def stop(self):
        """Stop the timer."""
    
    def setInterval(self, msec):
        """Set the timer interval in milliseconds."""
    
    def interval(self):
        """Get the timer interval."""
    
    def setSingleShot(self, singleShot):
        """Set whether timer fires only once."""
    
    def isSingleShot(self):
        """Check if timer is single-shot."""
    
    def isActive(self):
        """Check if timer is active."""
    
    def remainingTime(self):
        """Get remaining time until next timeout."""
    
    # Signals
    timeout: pyTTkSignal  # Emitted when timer times out

Shortcut System

TTkShortcut provides keyboard shortcut handling for application actions.

class TTkShortcut:
    def __init__(self, keySequence, parent=None):
        """
        Initialize a keyboard shortcut.
        
        Parameters:
        - keySequence (str): Key sequence (e.g., "Ctrl+S", "Alt+F4")
        - parent: Parent widget for shortcut scope
        """
    
    def setKey(self, keySequence):
        """Set the key sequence."""
    
    def key(self):
        """Get the key sequence."""
    
    def setEnabled(self, enabled):
        """Enable/disable the shortcut."""
    
    def isEnabled(self):
        """Check if shortcut is enabled."""
    
    def setContext(self, context):
        """Set the shortcut context scope."""
    
    def context(self):
        """Get the shortcut context scope."""
    
    def setAutoRepeat(self, autoRepeat):
        """Enable/disable auto-repeat."""
    
    def autoRepeat(self):
        """Check if auto-repeat is enabled."""
    
    # Signals
    activated: pyTTkSignal  # Emitted when shortcut is activated
    activatedAmbiguously: pyTTkSignal  # Emitted for ambiguous activation

Usage Examples

Basic Signal-Slot Connection

import TermTk as ttk

class MyWidget(ttk.TTkWidget):
    # Define custom signal
    dataChanged = ttk.pyTTkSignal(str)
    
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._data = ""
    
    def setData(self, data):
        if self._data != data:
            self._data = data
            self.dataChanged.emit(data)  # Emit signal
    
    def data(self):
        return self._data

# Usage
root = ttk.TTk()
widget = MyWidget(parent=root)

# Define slot function
@ttk.pyTTkSlot(str)
def on_data_changed(new_data):
    print(f"Data changed to: {new_data}")

# Connect signal to slot
widget.dataChanged.connect(on_data_changed)

# Trigger signal
widget.setData("Hello World")  # Prints: "Data changed to: Hello World"

root.mainloop()

Button Click Handling

import TermTk as ttk

root = ttk.TTk()
container = ttk.TTkContainer(parent=root)
layout = ttk.TTkVBoxLayout()

button1 = ttk.TTkButton(text="Button 1")
button2 = ttk.TTkButton(text="Button 2")
label = ttk.TTkLabel(text="No button clicked yet")

# Define slot methods
@ttk.pyTTkSlot()
def button1_clicked():
    label.setText("Button 1 was clicked!")

@ttk.pyTTkSlot()
def button2_clicked():
    label.setText("Button 2 was clicked!")

# Connect signals to slots
button1.clicked.connect(button1_clicked)
button2.clicked.connect(button2_clicked)

layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(label)

container.setLayout(layout)
root.mainloop()

Timer Example

import TermTk as ttk

root = ttk.TTk()
container = ttk.TTkContainer(parent=root)

label = ttk.TTkLabel(text="Timer: 0", parent=container)
counter = 0

# Create timer
timer = ttk.TTkTimer()
timer.setInterval(1000)  # 1 second

# Define timer slot
@ttk.pyTTkSlot()
def update_counter():
    global counter
    counter += 1
    label.setText(f"Timer: {counter}")

# Connect timer to slot
timer.timeout.connect(update_counter)

# Start timer
timer.start()

root.mainloop()

Keyboard Event Handling

import TermTk as ttk

class KeyCaptureWidget(ttk.TTkWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setFocusPolicy(ttk.TTkConstant.StrongFocus)
        self._label = ttk.TTkLabel(parent=self, text="Press any key...")
    
    def keyEvent(self, evt):
        if evt.type() == ttk.TTkConstant.KeyPress:
            key_name = self.get_key_name(evt.key())
            text = f"Key pressed: {key_name}"
            
            if evt.modifiers() & ttk.TTkConstant.ControlModifier:
                text += " (with Ctrl)"
            if evt.modifiers() & ttk.TTkConstant.AltModifier:
                text += " (with Alt)"
            if evt.modifiers() & ttk.TTkConstant.ShiftModifier:
                text += " (with Shift)"
                
            self._label.setText(text)
            evt.accept()
        else:
            super().keyEvent(evt)
    
    def get_key_name(self, key):
        # Convert key code to readable name
        key_names = {
            ttk.TTkConstant.Key_Return: "Return",
            ttk.TTkConstant.Key_Escape: "Escape",
            ttk.TTkConstant.Key_Space: "Space",
            ttk.TTkConstant.Key_Up: "Up Arrow",
            ttk.TTkConstant.Key_Down: "Down Arrow",
            ttk.TTkConstant.Key_Left: "Left Arrow",
            ttk.TTkConstant.Key_Right: "Right Arrow",
        }
        return key_names.get(key, f"Key_{key}")

root = ttk.TTk()
widget = KeyCaptureWidget(parent=root)
widget.setFocus()

root.mainloop()

Mouse Event Handling

import TermTk as ttk

class ClickTracker(ttk.TTkWidget):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._click_count = 0
        self._label = ttk.TTkLabel(parent=self, text="Click count: 0")
    
    def mousePressEvent(self, evt):
        if evt.button() == ttk.TTkConstant.LeftButton:
            self._click_count += 1
            self._label.setText(f"Click count: {self._click_count}")
            print(f"Left click at ({evt.x()}, {evt.y()})")
        elif evt.button() == ttk.TTkConstant.RightButton:
            print(f"Right click at ({evt.x()}, {evt.y()})")
        
        evt.accept()

root = ttk.TTk()
tracker = ClickTracker(parent=root)

root.mainloop()

Keyboard Shortcuts

import TermTk as ttk

root = ttk.TTk()
container = ttk.TTkContainer(parent=root)
layout = ttk.TTkVBoxLayout()

label = ttk.TTkLabel(text="Use Ctrl+S to save, Ctrl+Q to quit")
text_edit = ttk.TTkTextEdit()

layout.addWidget(label)
layout.addWidget(text_edit)
container.setLayout(layout)

# Create shortcuts
save_shortcut = ttk.TTkShortcut("Ctrl+S", container)
quit_shortcut = ttk.TTkShortcut("Ctrl+Q", container)

# Define shortcut handlers
@ttk.pyTTkSlot()
def save_action():
    print("Save action triggered!")
    label.setText("File saved!")

@ttk.pyTTkSlot()
def quit_action():
    print("Quit action triggered!")
    root.quit()

# Connect shortcuts
save_shortcut.activated.connect(save_action)
quit_shortcut.activated.connect(quit_action)

root.mainloop()

Signal Chaining and Disconnection

import TermTk as ttk

root = ttk.TTk()
container = ttk.TTkContainer(parent=root)
layout = ttk.TTkVBoxLayout()

button = ttk.TTkButton(text="Click me")
toggle_button = ttk.TTkButton(text="Toggle Connection")
label = ttk.TTkLabel(text="Connection active")

@ttk.pyTTkSlot()
def button_clicked():
    label.setText("Button was clicked!")

@ttk.pyTTkSlot()
def toggle_connection():
    if button.clicked.isConnected():
        button.clicked.disconnect(button_clicked)
        toggle_button.setText("Connect")
        label.setText("Connection disabled")
    else:
        button.clicked.connect(button_clicked)
        toggle_button.setText("Disconnect")
        label.setText("Connection active")

# Initial connection
button.clicked.connect(button_clicked)
toggle_button.clicked.connect(toggle_connection)

layout.addWidget(button)
layout.addWidget(toggle_button)
layout.addWidget(label)

container.setLayout(layout)
root.mainloop()

Install with Tessl CLI

npx tessl i tessl/pypi-pytermtk

docs

color-drawing.md

container-widgets.md

core-widgets.md

display-widgets.md

event-system.md

file-dialogs.md

index.md

input-widgets.md

layouts.md

model-view.md

text-editing.md

utilities.md

tile.json