Python Terminal Toolkit for creating sophisticated text-based user interfaces with Qt-like API and full widget support
—
Data-driven widgets using the Model-View pattern including tables and trees with support for various data sources and custom models.
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 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 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."""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."""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."""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()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()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()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