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

model-view.mddocs/

Model-View Widgets

Data-driven widgets using the Model-View pattern including tables and trees with support for various data sources and custom models.

Capabilities

Abstract Base Classes

Base classes for implementing the Model-View architecture pattern.

class TTkAbstractItemModel:
    def __init__(self, parent=None):
        """Initialize abstract item model."""
    
    def rowCount(self, parent=None):
        """Get number of rows in the model."""
    
    def columnCount(self, parent=None):
        """Get number of columns in the model."""
    
    def data(self, index, role=None):
        """Get data for the specified model index and role."""
    
    def setData(self, index, value, role=None):
        """Set data for the specified model index and role."""
    
    def headerData(self, section, orientation, role=None):
        """Get header data for the specified section."""
    
    def flags(self, index):
        """Get item flags for the specified index."""
    
    def index(self, row, column, parent=None):
        """Create a model index for the specified position."""
    
    def parent(self, index):
        """Get the parent index for the specified index."""
    
    def hasChildren(self, parent=None):
        """Check if the specified index has children."""
    
    def insertRows(self, row, count, parent=None):
        """Insert rows into the model."""
    
    def removeRows(self, row, count, parent=None):
        """Remove rows from the model."""
    
    def insertColumns(self, column, count, parent=None):
        """Insert columns into the model."""
    
    def removeColumns(self, column, count, parent=None):
        """Remove columns from the model."""
    
    # Signals
    dataChanged: pyTTkSignal        # Emitted when data changes
    rowsInserted: pyTTkSignal       # Emitted when rows are inserted
    rowsRemoved: pyTTkSignal        # Emitted when rows are removed
    columnsInserted: pyTTkSignal    # Emitted when columns are inserted
    columnsRemoved: pyTTkSignal     # Emitted when columns are removed
    modelReset: pyTTkSignal         # Emitted when model is reset

class TTkAbstractTableModel(TTkAbstractItemModel):
    def __init__(self, parent=None):
        """Initialize abstract table model."""
    
    def rowCount(self, parent=None):
        """Get number of rows in the table."""
    
    def columnCount(self, parent=None):
        """Get number of columns in the table."""
    
    def data(self, index, role=None):
        """Get data for table cell."""
    
    def setData(self, index, value, role=None):
        """Set data for table cell."""
    
    def headerData(self, section, orientation, role=None):
        """Get header data for row or column."""

class TTkModelIndex:
    def __init__(self, row=-1, column=-1, parent=None, model=None):
        """
        Initialize a model index.
        
        Parameters:
        - row (int): Row number
        - column (int): Column number
        - parent: Parent index
        - model: Associated model
        """
    
    def row(self):
        """Get the row number."""
    
    def column(self):
        """Get the column number."""
    
    def parent(self):
        """Get the parent index."""
    
    def model(self):
        """Get the associated model."""
    
    def isValid(self):
        """Check if the index is valid."""
    
    def data(self, role=None):
        """Get data from the model for this index."""
    
    def sibling(self, row, column):
        """Get sibling index at specified row and column."""

Table Widgets

Table widgets for displaying and editing tabular data.

class TTkTable(TTkAbstractScrollArea):
    def __init__(self, parent=None, **kwargs):
        """
        Initialize a table widget.
        
        Parameters:
        - model: Data model for the table
        """
    
    def setModel(self, model):
        """Set the data model for the table."""
    
    def model(self):
        """Get the current data model."""
    
    def setSelectionBehavior(self, behavior):
        """Set selection behavior (rows, columns, items)."""
    
    def selectionBehavior(self):
        """Get current selection behavior."""
    
    def setSelectionMode(self, mode):
        """Set selection mode (single, multi, extended)."""
    
    def selectionMode(self):
        """Get current selection mode."""
    
    def currentIndex(self):
        """Get current selected index."""
    
    def setCurrentIndex(self, index):
        """Set current selected index."""
    
    def selectedIndexes(self):
        """Get list of selected indexes."""
    
    def selectRow(self, row):
        """Select entire row."""
    
    def selectColumn(self, column):
        """Select entire column."""
    
    def clearSelection(self):
        """Clear current selection."""
    
    def setRowHeight(self, row, height):
        """Set height for specific row."""
    
    def setColumnWidth(self, column, width):
        """Set width for specific column."""
    
    def rowHeight(self, row):
        """Get height of specific row."""
    
    def columnWidth(self, column):
        """Get width of specific column."""
    
    def hideRow(self, row):
        """Hide specific row."""
    
    def hideColumn(self, column):
        """Hide specific column."""
    
    def showRow(self, row):
        """Show specific row."""
    
    def showColumn(self, column):
        """Show specific column."""
    
    def isRowHidden(self, row):
        """Check if row is hidden."""
    
    def isColumnHidden(self, column):
        """Check if column is hidden."""
    
    def resizeRowsToContents(self):
        """Resize all rows to fit content."""
    
    def resizeColumnsToContents(self):
        """Resize all columns to fit content."""
    
    # Signals
    clicked: pyTTkSignal            # Emitted when cell is clicked
    doubleClicked: pyTTkSignal      # Emitted when cell is double-clicked
    entered: pyTTkSignal            # Emitted when mouse enters cell
    pressed: pyTTkSignal            # Emitted when cell is pressed

class TTkTableWidget(TTkTable):
    def __init__(self, parent=None, **kwargs):
        """
        Initialize a table widget with built-in model.
        
        Parameters:
        - rows (int): Number of rows
        - columns (int): Number of columns
        """
    
    def setRowCount(self, rows):
        """Set number of rows."""
    
    def setColumnCount(self, columns):
        """Set number of columns."""
    
    def rowCount(self):
        """Get number of rows."""
    
    def columnCount(self):
        """Get number of columns."""
    
    def setItem(self, row, column, item):
        """Set item at specified position."""
    
    def item(self, row, column):
        """Get item at specified position."""
    
    def takeItem(self, row, column):
        """Remove and return item at position."""
    
    def setHorizontalHeaderLabels(self, labels):
        """Set horizontal header labels."""
    
    def setVerticalHeaderLabels(self, labels):
        """Set vertical header labels."""
    
    def horizontalHeaderItem(self, column):
        """Get horizontal header item."""
    
    def verticalHeaderItem(self, row):
        """Get vertical header item."""
    
    def setHorizontalHeaderItem(self, column, item):
        """Set horizontal header item."""
    
    def setVerticalHeaderItem(self, row, item):
        """Set vertical header item."""
    
    def clear(self):
        """Clear all items."""
    
    def clearContents(self):
        """Clear item contents but keep headers."""

class TTkHeaderView(TTkWidget):
    def __init__(self, orientation, parent=None):
        """
        Initialize a header view.
        
        Parameters:
        - orientation: Horizontal or vertical orientation
        """
    
    def setModel(self, model):
        """Set the model for the header."""
    
    def model(self):
        """Get the current model."""
    
    def setOrientation(self, orientation):
        """Set header orientation."""
    
    def orientation(self):
        """Get header orientation."""
    
    def setSectionResizeMode(self, mode):
        """Set section resize mode."""
    
    def sectionResizeMode(self):
        """Get section resize mode."""
    
    def setStretchLastSection(self, stretch):
        """Set whether last section stretches."""
    
    def stretchLastSection(self):
        """Check if last section stretches."""
    
    def resizeSection(self, section, size):
        """Resize specific section."""
    
    def sectionSize(self, section):
        """Get size of specific section."""
    
    def hideSection(self, section):
        """Hide specific section."""
    
    def showSection(self, section):
        """Show specific section."""
    
    def isSectionHidden(self, section):
        """Check if section is hidden."""

Tree Widgets

Tree widgets for displaying hierarchical data structures.

class TTkTree(TTkAbstractScrollArea):
    def __init__(self, parent=None, **kwargs):
        """Initialize a tree widget."""
    
    def setModel(self, model):
        """Set the data model for the tree."""
    
    def model(self):
        """Get the current data model."""
    
    def setRootIndex(self, index):
        """Set the root index for the tree view."""
    
    def rootIndex(self):
        """Get the root index."""
    
    def currentIndex(self):
        """Get current selected index."""
    
    def setCurrentIndex(self, index):
        """Set current selected index."""
    
    def selectedIndexes(self):
        """Get list of selected indexes."""
    
    def expand(self, index):
        """Expand item at index."""
    
    def collapse(self, index):
        """Collapse item at index."""
    
    def isExpanded(self, index):
        """Check if item is expanded."""
    
    def expandAll(self):
        """Expand all items."""
    
    def collapseAll(self):
        """Collapse all items."""
    
    def setItemsExpandable(self, expandable):
        """Set whether items are expandable."""
    
    def itemsExpandable(self):
        """Check if items are expandable."""
    
    def setAutoExpandDelay(self, delay):
        """Set auto-expand delay in milliseconds."""
    
    def autoExpandDelay(self):
        """Get auto-expand delay."""
    
    def setIndentation(self, indentation):
        """Set indentation width."""
    
    def indentation(self):
        """Get indentation width."""
    
    def setUniformRowHeights(self, uniform):
        """Set whether all rows have uniform height."""
    
    def uniformRowHeights(self):
        """Check if rows have uniform height."""
    
    # Signals
    clicked: pyTTkSignal            # Emitted when item is clicked
    doubleClicked: pyTTkSignal      # Emitted when item is double-clicked
    expanded: pyTTkSignal           # Emitted when item is expanded
    collapsed: pyTTkSignal          # Emitted when item is collapsed

class TTkTreeWidget(TTkTree):
    def __init__(self, parent=None, **kwargs):
        """Initialize a tree widget with built-in model."""
    
    def setColumnCount(self, columns):
        """Set number of columns."""
    
    def columnCount(self):
        """Get number of columns."""
    
    def setHeaderLabels(self, labels):
        """Set header labels for columns."""
    
    def headerItem(self):
        """Get header item."""
    
    def setHeaderItem(self, item):
        """Set header item."""
    
    def invisibleRootItem(self):
        """Get invisible root item."""
    
    def addTopLevelItem(self, item):
        """Add top-level item."""
    
    def insertTopLevelItem(self, index, item):
        """Insert top-level item at index."""
    
    def takeTopLevelItem(self, index):
        """Remove and return top-level item."""
    
    def topLevelItemCount(self):
        """Get number of top-level items."""
    
    def topLevelItem(self, index):
        """Get top-level item at index."""
    
    def currentItem(self):
        """Get current selected item."""
    
    def setCurrentItem(self, item):
        """Set current selected item."""
    
    def selectedItems(self):
        """Get list of selected items."""
    
    def findItems(self, text, flags):
        """Find items by text and flags."""
    
    def clear(self):
        """Clear all items."""

class TTkTreeWidgetItem:
    def __init__(self, parent=None, strings=None):
        """
        Initialize a tree widget item.
        
        Parameters:
        - parent: Parent item or tree widget
        - strings: List of column texts
        """
    
    def setText(self, column, text):
        """Set text for specific column."""
    
    def text(self, column):
        """Get text for specific column."""
    
    def setIcon(self, column, icon):
        """Set icon for specific column."""
    
    def icon(self, column):
        """Get icon for specific column."""
    
    def setData(self, column, role, value):
        """Set data for column and role."""
    
    def data(self, column, role):
        """Get data for column and role."""
    
    def setFlags(self, flags):
        """Set item flags."""
    
    def flags(self):
        """Get item flags."""
    
    def parent(self):
        """Get parent item."""
    
    def child(self, index):
        """Get child item at index."""
    
    def childCount(self):
        """Get number of child items."""
    
    def addChild(self, child):
        """Add child item."""
    
    def insertChild(self, index, child):
        """Insert child item at index."""
    
    def takeChild(self, index):
        """Remove and return child item."""
    
    def removeChild(self, child):
        """Remove child item."""
    
    def indexOfChild(self, child):
        """Get index of child item."""
    
    def setExpanded(self, expanded):
        """Set expanded state."""
    
    def isExpanded(self):
        """Check if item is expanded."""
    
    def setSelected(self, selected):
        """Set selected state."""
    
    def isSelected(self):
        """Check if item is selected."""
    
    def setHidden(self, hidden):
        """Set hidden state."""
    
    def isHidden(self):
        """Check if item is hidden."""
    
    def clone(self):
        """Create a copy of this item."""

Table Data Models

Concrete implementations of table models for different data sources.

class TTkTableModelList(TTkAbstractTableModel):
    def __init__(self, data=None):
        """
        Initialize table model with list data.
        
        Parameters:
        - data: List of lists representing table data
        """
    
    def setData(self, data):
        """Set the table data."""
    
    def data(self):
        """Get the table data."""
    
    def addRow(self, row_data):
        """Add a row to the table."""
    
    def insertRow(self, index, row_data):
        """Insert a row at specific index."""
    
    def removeRow(self, index):
        """Remove row at index."""
    
    def addColumn(self, column_data):
        """Add a column to the table."""
    
    def insertColumn(self, index, column_data):
        """Insert a column at specific index."""
    
    def removeColumn(self, index):
        """Remove column at index."""
    
    def setHeaders(self, headers):
        """Set column headers."""
    
    def headers(self):
        """Get column headers."""

class TTkTableModelCSV(TTkAbstractTableModel):
    def __init__(self, filename=None):
        """
        Initialize table model with CSV data.
        
        Parameters:
        - filename (str): Path to CSV file
        """
    
    def loadFromFile(self, filename):
        """Load data from CSV file."""
    
    def saveToFile(self, filename):
        """Save data to CSV file."""
    
    def setDelimiter(self, delimiter):
        """Set CSV delimiter character."""
    
    def delimiter(self):
        """Get CSV delimiter character."""
    
    def setHasHeader(self, has_header):
        """Set whether CSV has header row."""
    
    def hasHeader(self):
        """Check if CSV has header row."""

class TTkTableModelSQLite3(TTkAbstractTableModel):
    def __init__(self, database=None):
        """
        Initialize table model with SQLite database.
        
        Parameters:
        - database (str): Path to SQLite database file
        """
    
    def setDatabase(self, database):
        """Set database connection."""
    
    def database(self):
        """Get database connection."""
    
    def setTable(self, table_name):
        """Set table name to query."""
    
    def table(self):
        """Get current table name."""
    
    def setQuery(self, query):
        """Set custom SQL query."""
    
    def query(self):
        """Get current SQL query."""
    
    def refresh(self):
        """Refresh data from database."""
    
    def submitAll(self):
        """Submit all changes to database."""
    
    def revertAll(self):
        """Revert all changes."""

File Tree Widgets

Specialized tree widgets for displaying file system structures.

class TTkFileTree(TTkTree):
    def __init__(self, parent=None, **kwargs):
        """Initialize a file tree widget."""
    
    def setRootPath(self, path):
        """Set root directory path."""
    
    def rootPath(self):
        """Get root directory path."""
    
    def setNameFilters(self, filters):
        """Set file name filters."""
    
    def nameFilters(self):
        """Get file name filters."""
    
    def setFilter(self, filter_flags):
        """Set file filter flags."""
    
    def filter(self):
        """Get file filter flags."""
    
    def refresh(self):
        """Refresh file tree."""
    
    def mkdir(self, path):
        """Create directory."""
    
    def remove(self, path):
        """Remove file or directory."""
    
    def filePath(self, index):
        """Get file path for index."""
    
    def fileName(self, index):
        """Get file name for index."""
    
    def fileInfo(self, index):
        """Get file information for index."""
    
    def isDir(self, index):
        """Check if index represents directory."""

class TTkFileTreeWidget(TTkFileTree):
    def __init__(self, parent=None, **kwargs):
        """Initialize file tree widget with built-in model."""
    
    def currentPath(self):
        """Get current selected path."""
    
    def setCurrentPath(self, path):
        """Set current selected path."""
    
    def selectedPaths(self):
        """Get list of selected paths."""

class TTkFileTreeWidgetItem(TTkTreeWidgetItem):
    def __init__(self, parent=None, path=""):
        """
        Initialize file tree item.
        
        Parameters:
        - parent: Parent item
        - path (str): File system path
        """
    
    def setPath(self, path):
        """Set file system path."""
    
    def path(self):
        """Get file system path."""
    
    def fileName(self):
        """Get file name without path."""
    
    def isDir(self):
        """Check if item represents directory."""
    
    def isFile(self):
        """Check if item represents file."""
    
    def size(self):
        """Get file size."""
    
    def lastModified(self):
        """Get last modified timestamp."""

Usage Examples

Simple Table with Custom Model

import TermTk as ttk

class CustomTableModel(ttk.TTkAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data
        self._headers = ['Name', 'Age', 'City']
    
    def rowCount(self, parent=None):
        return len(self._data)
    
    def columnCount(self, parent=None):
        return len(self._headers)
    
    def data(self, index, role=None):
        if index.isValid():
            return self._data[index.row()][index.column()]
        return None
    
    def headerData(self, section, orientation, role=None):
        if orientation == ttk.TTkConstant.Horizontal:
            return self._headers[section]
        return str(section + 1)

# Sample data
data = [
    ['Alice', '25', 'New York'],
    ['Bob', '30', 'Los Angeles'],
    ['Charlie', '35', 'Chicago'],
    ['Diana', '28', 'Miami']
]

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

# Create table with custom model
model = CustomTableModel(data)
table = ttk.TTkTable(parent=container)
table.setModel(model)

# Handle selection
@ttk.pyTTkSlot(ttk.TTkModelIndex)
def cell_clicked(index):
    value = model.data(index)
    print(f"Clicked: {value} at ({index.row()}, {index.column()})")

table.clicked.connect(cell_clicked)

root.mainloop()

Tree Widget with Custom Items

import TermTk as ttk

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

# Create tree widget
tree = ttk.TTkTreeWidget(parent=container)
tree.setHeaderLabels(['Item', 'Type', 'Value'])

# Create tree structure
root_item = tree.invisibleRootItem()

# Add categories
ui_category = ttk.TTkTreeWidgetItem(root_item, ['UI Components', 'Category', ''])
data_category = ttk.TTkTreeWidgetItem(root_item, ['Data Models', 'Category', ''])

# Add UI components
button_item = ttk.TTkTreeWidgetItem(ui_category, ['Button', 'Widget', 'Interactive'])
label_item = ttk.TTkTreeWidgetItem(ui_category, ['Label', 'Widget', 'Display'])
input_item = ttk.TTkTreeWidgetItem(ui_category, ['LineEdit', 'Widget', 'Input'])

# Add data models
table_model = ttk.TTkTreeWidgetItem(data_category, ['Table Model', 'Model', 'Tabular'])
tree_model = ttk.TTkTreeWidgetItem(data_category, ['Tree Model', 'Model', 'Hierarchical'])

# Expand categories
ui_category.setExpanded(True)
data_category.setExpanded(True)

# Handle item selection
@ttk.pyTTkSlot(ttk.TTkTreeWidgetItem)
def item_selected(item):
    print(f"Selected: {item.text(0)} - {item.text(1)}")

tree.currentItemChanged.connect(item_selected)

root.mainloop()

CSV Table Viewer

import TermTk as ttk

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

# Create CSV model and table
csv_model = ttk.TTkTableModelCSV()
table = ttk.TTkTableWidget(parent=container)

# Load CSV file
try:
    csv_model.loadFromFile('sample_data.csv')
    table.setModel(csv_model)
except FileNotFoundError:
    # Create sample data if file doesn't exist
    sample_data = [
        ['Product', 'Price', 'Stock'],
        ['Laptop', '$999', '15'],
        ['Mouse', '$25', '50'],
        ['Keyboard', '$75', '30'],
        ['Monitor', '$299', '8']
    ]
    
    list_model = ttk.TTkTableModelList(sample_data[1:])
    list_model.setHeaders(sample_data[0])
    table.setModel(list_model)

# Add toolbar
toolbar_layout = ttk.TTkHBoxLayout()
refresh_btn = ttk.TTkButton(text="Refresh")
export_btn = ttk.TTkButton(text="Export CSV")
toolbar_layout.addWidget(refresh_btn)
toolbar_layout.addWidget(export_btn)
toolbar_layout.addStretch(1)

# Add status bar
status = ttk.TTkLabel(text=f"Loaded {table.model().rowCount()} rows")

# Connect buttons
@ttk.pyTTkSlot()
def refresh_data():
    table.model().refresh()
    status.setText(f"Refreshed - {table.model().rowCount()} rows")

@ttk.pyTTkSlot()
def export_data():
    # Export logic here
    status.setText("Data exported")

refresh_btn.clicked.connect(refresh_data)
export_btn.clicked.connect(export_data)

layout.addLayout(toolbar_layout)
layout.addWidget(table)
layout.addWidget(status)

container.setLayout(layout)
root.mainloop()

File Tree Browser

import TermTk as ttk
import os

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

# Create file tree
file_tree = ttk.TTkFileTreeWidget(parent=container)
file_tree.setRootPath(os.path.expanduser("~"))  # Start at home directory

# Create path bar
path_layout = ttk.TTkHBoxLayout()
path_label = ttk.TTkLabel(text="Path:")
path_edit = ttk.TTkLineEdit(text=file_tree.rootPath())
go_btn = ttk.TTkButton(text="Go")

path_layout.addWidget(path_label)
path_layout.addWidget(path_edit, stretch=1)
path_layout.addWidget(go_btn)

# File info panel
info_panel = ttk.TTkContainer()
info_layout = ttk.TTkVBoxLayout()
name_label = ttk.TTkLabel(text="Name: ")
type_label = ttk.TTkLabel(text="Type: ")
size_label = ttk.TTkLabel(text="Size: ")

info_layout.addWidget(name_label)
info_layout.addWidget(type_label)
info_layout.addWidget(size_label)
info_layout.addStretch(1)
info_panel.setLayout(info_layout)

# Split layout
main_splitter = ttk.TTkSplitter(orientation=ttk.TTkConstant.Horizontal)
main_splitter.addWidget(file_tree)
main_splitter.addWidget(info_panel)
main_splitter.setSizes([70, 30])

# Handle file selection
@ttk.pyTTkSlot(str)
def file_selected(path):
    if os.path.exists(path):
        name_label.setText(f"Name: {os.path.basename(path)}")
        
        if os.path.isdir(path):
            type_label.setText("Type: Directory")
            size_label.setText("Size: -")
        else:
            type_label.setText("Type: File")
            try:
                size = os.path.getsize(path)
                size_label.setText(f"Size: {size} bytes")
            except OSError:
                size_label.setText("Size: Unknown")

file_tree.currentPathChanged.connect(file_selected)

# Handle path navigation
@ttk.pyTTkSlot()
def navigate_to_path():
    path = path_edit.text()
    if os.path.exists(path) and os.path.isdir(path):
        file_tree.setRootPath(path)
        path_edit.setText(path)

go_btn.clicked.connect(navigate_to_path)

layout.addLayout(path_layout)
layout.addWidget(main_splitter)

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