From d6c3ac971f8807dea4c969007b589e838f7f0d5b Mon Sep 17 00:00:00 2001 From: Pier CeccoPierangioliEugenio Date: Sun, 21 Dec 2025 22:39:03 +0000 Subject: [PATCH] docs: improve table tests documentation (#559) --- tests/t.ui/test.ui.032.table.01.py | 48 +++++++++++++++++-- tests/t.ui/test.ui.032.table.02.py | 26 +++++++++- tests/t.ui/test.ui.032.table.03.py | 17 +++++++ tests/t.ui/test.ui.032.table.04.py | 31 ++++++++++-- tests/t.ui/test.ui.032.table.05.py | 25 ++++++++++ tests/t.ui/test.ui.032.table.06.py | 33 +++++++++++-- tests/t.ui/test.ui.032.table.07.py | 20 ++++++++ tests/t.ui/test.ui.032.table.08.py | 18 +++++++ tests/t.ui/test.ui.032.table.09.py | 18 +++++++ tests/t.ui/test.ui.032.table.10.sqlite.py | 48 +++++++++++++++---- .../test.ui.032.table.11.pyside.align.01.py | 21 ++++++++ .../test.ui.032.table.11.pyside.insert.01.py | 22 +++++++++ .../test.ui.032.table.11.pyside.insert.02.py | 23 +++++++++ tests/t.ui/test.ui.032.table.12.py | 32 +++++++++++-- .../t.ui/test.ui.032.table.13.alignment.01.py | 20 ++++++++ ...i.032.table.13.alignment.02.overloading.py | 30 +++++++++++- ...test.ui.032.table.13.alignment.03.mixin.py | 37 +++++++++++++- .../t.ui/test.ui.032.table.14.list.01.item.py | 31 ++++++++++-- .../test.ui.032.table.14.list.02.custom.py | 33 +++++++++++-- .../test.ui.032.table.15.test.clipboard.py | 34 +++++++++++-- 20 files changed, 524 insertions(+), 43 deletions(-) diff --git a/tests/t.ui/test.ui.032.table.01.py b/tests/t.ui/test.ui.032.table.01.py index 76ffe142..31bca15a 100755 --- a/tests/t.ui/test.ui.032.table.01.py +++ b/tests/t.ui/test.ui.032.table.01.py @@ -25,6 +25,24 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Basic Example +====================== + +This example demonstrates the fundamental usage of TTkTable widget with a custom table model. + +Key Features Demonstrated: +- Creating a custom table model by extending TTkAbstractTableModel +- Implementing required methods: rowCount(), columnCount(), data() +- Adding custom header data with headerData() +- Implementing column sorting functionality +- Resizing columns to fit content +- Enabling sorting by clicking column headers + +The example displays a table of chemical solvents with their physical properties +(boiling point, melting point, density) and allows sorting by any column. +''' + import os import sys import argparse @@ -33,27 +51,40 @@ import operator sys.path.append(os.path.join(sys.path[0],'../..')) import TermTk as ttk +# Custom table model that provides data to the TTkTable widget class MyTableModel(ttk.TTkAbstractTableModel): def __init__(self, mylist, header, *args): super().__init__(*args) - self.mylist = mylist - self.header = header + self.mylist = mylist # Store the data as a list of tuples + self.header = header # Store column headers + + # Return the number of rows in the table def rowCount(self): return len(self.mylist) + + # Return the number of columns in the table def columnCount(self): return len(self.mylist[0]) + + # Return the data at the specified row and column def data(self, row, col): return self.mylist[row][col] + # Provide header labels for columns and rows def headerData(self, num, orientation): if orientation == ttk.TTkK.HORIZONTAL: - return self.header[num] + return self.header[num] # Return column header text return super().headerData(num, orientation) + + # Sort the table data by the specified column def sort(self, col, order): """sort table by given column number col""" + # Sort the list by the specified column self.mylist = sorted(self.mylist, key=operator.itemgetter(col)) + # Reverse if descending order is requested if order == ttk.TTkK.DescendingOrder: self.mylist.reverse() + # Notify the table that the data has changed self.dataChanged.emit() # the solvent data ... @@ -118,6 +149,7 @@ data_list = [ ('WATER', 100.0, 0.0, 1.0), ('XYLENES', 139.1, -47.8, 0.86)] +# Parse command line arguments for display options parser = argparse.ArgumentParser() parser.add_argument('-f', help='Full Screen (default)', action='store_true') parser.add_argument('-w', help='Windowed', action='store_true') @@ -127,6 +159,7 @@ args = parser.parse_args() fullScreen = not args.w mouseTrack = args.t +# Create the main TTk application root = ttk.TTk(title="pyTermTk Table Demo", mouseTrack=mouseTrack) if fullScreen: rootTable = root @@ -134,17 +167,22 @@ if fullScreen: else: rootTable = ttk.TTkWindow(parent=root,pos = (0,0), size=(150,40), title="Test Table 1", layout=ttk.TTkGridLayout(), border=True) +# Create a vertical splitter to hold the table and log viewer splitter = ttk.TTkSplitter(parent=rootTable,orientation=ttk.TTkK.VERTICAL) +# Create the table model with our data table_model = MyTableModel(data_list, header) +# Create the table widget and attach the model table = ttk.TTkTable(parent=splitter, tableModel=table_model) -# set column width to fit contents (set font first!) +# Automatically resize columns to fit their contents table.resizeColumnsToContents() -# enable sorting + +# Enable column sorting by clicking on column headers table.setSortingEnabled(True) +# Add a log viewer at the bottom of the splitter splitter.addWidget(ttk.TTkLogViewer(),size=10,title="LOGS") root.mainloop() \ No newline at end of file diff --git a/tests/t.ui/test.ui.032.table.02.py b/tests/t.ui/test.ui.032.table.02.py index 001d9df6..aef72193 100755 --- a/tests/t.ui/test.ui.032.table.02.py +++ b/tests/t.ui/test.ui.032.table.02.py @@ -25,6 +25,24 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Advanced Example with Images and Multi-line Text +========================================================= + +This example extends the basic table functionality by demonstrating: + +Key Features: +- Displaying ANSI art images within table cells +- Multi-line text in cells +- Long text handling +- Custom vertical header labels with prefixes +- Mixed content types (text, numbers, and images) +- Custom color modifiers for alternating row colors + +The table contains chemical solvents data with embedded images and +demonstrates how TTkTable handles complex cell content. +''' + import os import sys import argparse @@ -34,10 +52,12 @@ import json sys.path.append(os.path.join(sys.path[0],'../..')) import TermTk as ttk +# Load ANSI art images from JSON file +# These images were created using the Dumb Paint Tool and can be displayed in table cells imagesFile = os.path.join(os.path.dirname(os.path.abspath(__file__)),'ansi.images.json') with open(imagesFile) as f: d = json.load(f) - # Image exported by the Dumb Paint Tool + # Decompress base64-encoded ANSI art images pepper = ttk.TTkUtil.base64_deflate_2_obj(d['compressed']['pepper']) python = ttk.TTkUtil.base64_deflate_2_obj(d['compressed']['python']) fire = ttk.TTkUtil.base64_deflate_2_obj(d['compressed']['fire']) @@ -55,10 +75,12 @@ class MyTableModel(ttk.TTkAbstractTableModel): return len(self.mylist[0]) def data(self, row, col): return self.mylist[row][col] + # Provide custom header labels for both columns and rows def headerData(self, num, orientation): if orientation == ttk.TTkK.HORIZONTAL: - return self.header[num] + return self.header[num] # Column headers if orientation == ttk.TTkK.VERTICAL: + # Create custom row headers with rotating prefixes prefix = ['aa','bb','cc','dd','ee','ff','gg','Euge'] return f"{prefix[num%len(prefix)]}:{num:03}" return super().headerData(num, orientation) diff --git a/tests/t.ui/test.ui.032.table.03.py b/tests/t.ui/test.ui.032.table.03.py index b231951c..87886e6e 100755 --- a/tests/t.ui/test.ui.032.table.03.py +++ b/tests/t.ui/test.ui.032.table.03.py @@ -25,6 +25,23 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Wide Table Example +============================ + +This example demonstrates table behavior with many columns (20+ columns). + +Key Features: +- Horizontal scrolling for wide tables +- Handling tables that exceed screen width +- Same features as previous examples (images, multi-line text) +- Many columns (20 columns total) +- Demonstrates column navigation and viewport management + +Useful for testing horizontal scrolling performance and column +visibility management in wide data sets. +''' + import os import sys import argparse diff --git a/tests/t.ui/test.ui.032.table.04.py b/tests/t.ui/test.ui.032.table.04.py index 4cc212b8..d7ef0c33 100755 --- a/tests/t.ui/test.ui.032.table.04.py +++ b/tests/t.ui/test.ui.032.table.04.py @@ -25,6 +25,23 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Custom Size Example +============================= + +This example shows how to create a table model with a custom/fixed size +that may differ from the actual data size. + +Key Features: +- Table model with optional size parameter +- Demonstrates rowCount() and columnCount() override with custom dimensions +- Wide table with 21 columns (including 'KK-Last' column) +- Shows how to handle tables where displayed size differs from data size + +This is useful when you want to display a subset of data or when +implementing lazy loading / virtual scrolling. +''' + import os import sys import argparse @@ -49,15 +66,19 @@ class MyTableModel(ttk.TTkAbstractTableModel): super().__init__(*args) self.mylist = mylist self.header = header - self.size = size + self.size = size # Optional (rows, cols) tuple to override actual data size + + # Return custom row count if size is specified, otherwise use actual data length def rowCount(self): if self.size: - return self.size[0] - return len(self.mylist) + return self.size[0] # Use custom row count + return len(self.mylist) # Use actual data row count + + # Return custom column count if size is specified, otherwise use actual data length def columnCount(self): if self.size: - return self.size[1] - return len(self.mylist[0]) + return self.size[1] # Use custom column count + return len(self.mylist[0]) # Use actual data column count def data(self, row, col): return self.mylist[row][col] def headerData(self, num, orientation): diff --git a/tests/t.ui/test.ui.032.table.05.py b/tests/t.ui/test.ui.032.table.05.py index d025a5d6..0e399409 100755 --- a/tests/t.ui/test.ui.032.table.05.py +++ b/tests/t.ui/test.ui.032.table.05.py @@ -25,6 +25,25 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Large Dataset Example +================================ + +This example demonstrates table performance with large datasets (5000 rows). + +Key Features: +- Handling large datasets (5000+ rows) efficiently +- Custom color modifiers for creating rainbow and pattern effects +- Multiple table models with different dataset sizes +- Cell selection demonstration (setSelection) +- Dynamic style switching with custom colors +- Performance testing with varied content (text, images, numbers) +- Rich content mixing: TTkStrings with colors, ANSI images, multiline text + +This is useful for performance testing and understanding how TTkTable +handles large amounts of data and complex rendering scenarios. +''' + import os import sys import argparse @@ -53,7 +72,13 @@ with open(imagesFile) as f: images = [fireMini,pepper,python] +# Custom color modifier that creates complex color patterns for table rows +# This class extends TTkAlternateColor to provide custom alternating colors class CustomColorModifier(ttk.TTkAlternateColor): + # Define a color palette with various effects: + # - Blue shades for grouping + # - Green shades for contrast + # - Rainbow effects for visual interest colors = ( [ ttk.TTkColor.bg("#000066"), ttk.TTkColor.bg("#0000FF") ] * 3 + [ ttk.TTkColor.bg("#003300"), ttk.TTkColor.bg("#006600") ] + diff --git a/tests/t.ui/test.ui.032.table.06.py b/tests/t.ui/test.ui.032.table.06.py index 749b7f8e..de9663d5 100755 --- a/tests/t.ui/test.ui.032.table.06.py +++ b/tests/t.ui/test.ui.032.table.06.py @@ -25,6 +25,27 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable CSV and Multiple Models Example +========================================= + +This example demonstrates advanced table features including CSV support +and management of multiple table models. + +Key Features: +- CSV file loading support (via --csv argument) +- Switching between multiple table models +- Custom table model for CSV data (MyTableModelCSV) +- Complex color modifiers with rainbow effects +- Large datasets with mixed content +- Dynamic model switching +- Cell selection and highlighting + +Usage: + python test.ui.032.table.06.py --csv yourfile.csv # Load CSV file + python test.ui.032.table.06.py -f # Full screen mode +''' + import os import sys import csv @@ -48,14 +69,16 @@ args = parser.parse_args() fullScreen = not args.w mouseTrack = args.t +# CSV file parsing support (currently commented out) +# This code shows how to load CSV files into the table: # csvData = [] # if args.csv: -# sniffer = csv.Sniffer() -# has_header = sniffer.has_header(args.csv.read(2048)) -# args.csv.seek(0) -# csvreader = csv.reader(args.csv) +# sniffer = csv.Sniffer() # Detect CSV format +# has_header = sniffer.has_header(args.csv.read(2048)) # Check for headers +# args.csv.seek(0) # Reset file pointer +# csvreader = csv.reader(args.csv) # Create CSV reader # for row in csvreader: -# csvData.append(row) +# csvData.append(row) # Store each row imagesFile = os.path.join(os.path.dirname(os.path.abspath(__file__)),'../ansi.images.json') diff --git a/tests/t.ui/test.ui.032.table.07.py b/tests/t.ui/test.ui.032.table.07.py index ceb05653..04175da0 100755 --- a/tests/t.ui/test.ui.032.table.07.py +++ b/tests/t.ui/test.ui.032.table.07.py @@ -25,6 +25,26 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTableModelList Example +========================== + +This example demonstrates using TTkTableModelList, a ready-made list-based +table model that simplifies table creation. + +Key Features: +- Using TTkTableModelList instead of custom TTkAbstractTableModel +- Simplified table creation with list data +- No need to implement rowCount(), columnCount(), data() methods +- Full theming and styling support +- Large dataset handling (5000+ rows) +- Custom color modifiers +- Dynamic style switching + +TTkTableModelList is ideal when your data is already in a list format +and you don't need custom data access logic. +''' + import os import sys import csv diff --git a/tests/t.ui/test.ui.032.table.08.py b/tests/t.ui/test.ui.032.table.08.py index f6f807d3..972be04d 100755 --- a/tests/t.ui/test.ui.032.table.08.py +++ b/tests/t.ui/test.ui.032.table.08.py @@ -25,6 +25,24 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTableModelList Multi-line Cell Example +========================================== + +This example focuses on displaying multi-line text content in table cells. + +Key Features: +- Multi-line text formatting in cells +- Automatic row height adjustment with resizeRowsToContents() +- TTkTableModelList for simplified data management +- Mixed content (short text, long multi-line text) +- Custom row header labels +- Item flags customization (editable vs read-only cells) + +This demonstrates how TTkTable handles cells with varying heights +and properly wraps/displays multi-line content. +''' + import os import sys import csv diff --git a/tests/t.ui/test.ui.032.table.09.py b/tests/t.ui/test.ui.032.table.09.py index 2c6adea9..317cfe1b 100755 --- a/tests/t.ui/test.ui.032.table.09.py +++ b/tests/t.ui/test.ui.032.table.09.py @@ -25,6 +25,24 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Interactive Example with Mouse Tracking +================================================ + +This example demonstrates interactive table features with mouse tracking enabled. + +Key Features: +- Mouse tracking enabled by default (mouseTrack=True) +- Multi-line cell content +- Interactive cell hover effects +- Row and column selection +- Item flags for controlling cell editability +- Custom row heights with resizeRowsToContents() + +Mouse tracking allows the table to respond to mouse movements, +enabling hover effects and improved interactivity. +''' + import os import sys import csv diff --git a/tests/t.ui/test.ui.032.table.10.sqlite.py b/tests/t.ui/test.ui.032.table.10.sqlite.py index 05369846..ed89c970 100755 --- a/tests/t.ui/test.ui.032.table.10.sqlite.py +++ b/tests/t.ui/test.ui.032.table.10.sqlite.py @@ -22,6 +22,28 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +''' +TTkTableModelSQLite3 Example +============================= + +This example demonstrates using TTkTableModelSQLite3 to display data +directly from an SQLite3 database. + +Key Features: +- Direct SQLite3 database integration with TTkTableModelSQLite3 +- Automatic table loading from database +- Database creation if file doesn't exist +- Column sorting support +- Automatic column resizing +- No need to load all data into memory (efficient for large tables) + +Usage: + python test.ui.032.table.10.sqlite.py mydatabase.db # Use existing DB + python test.ui.032.table.10.sqlite.py newfile.db # Create new DB + +The database will be created with sample user data if it doesn't exist. +''' + import os import sys import csv @@ -58,14 +80,15 @@ fullScreen = not args.w mouseTrack = True path = args.file +# Helper function to create a sample SQLite database with test data def _createDB(fileName): - # Connect to a database (or create one if it doesn't exist) + # Connect to a database (creates the file if it doesn't exist) conn = sqlite3.connect(fileName) - # Create a cursor object + # Create a cursor object for executing SQL commands cur = conn.cursor() - # Create a table + # Create a users table with various column types cur.execute('''CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT, @@ -73,18 +96,21 @@ def _createDB(fileName): location TEXT, code INTEGER, age INTEGER)''') - # Insert data + # Insert sample data using parameterized queries (prevents SQL injection) sqlDef = "INSERT INTO users (name, surname, location, code, age) VALUES (?, ?, ?, ?, ?)" + # Generate 20 rows of random data for _ in range(20): cur.execute(sqlDef, - (random.choice(words), random.choice(words), - random.choice(words), - random.randint(0x10000,0x100000000), random.randint(18,70))) + (random.choice(words), random.choice(words), # Random name and surname + random.choice(words), # Random location + random.randint(0x10000,0x100000000), random.randint(18,70))) # Random code and age + # Commit changes to the database conn.commit() + # Close the connection conn.close() -# Create the DB if the file does not exists +# Create the database file with sample data if it doesn't already exist if not os.path.exists(path): _createDB(path) @@ -102,8 +128,14 @@ if fullScreen: else: rootTable = ttk.TTkWindow(parent=root,pos = (0,0), size=(150,40), title="Test Table", layout=ttk.TTkGridLayout(), border=True) +# Create a table model that connects directly to the SQLite database +# This model reads data on-demand, making it efficient for large tables basicTableModel = ttk.TTkTableModelSQLite3(fileName=path, table='users') + +# Create the table widget with the SQLite model and enable sorting table = ttk.TTkTable(parent=root, tableModel=basicTableModel, sortingEnabled=True) + +# Automatically resize columns to fit their content table.resizeColumnsToContents() root.mainloop() \ No newline at end of file diff --git a/tests/t.ui/test.ui.032.table.11.pyside.align.01.py b/tests/t.ui/test.ui.032.table.11.pyside.align.01.py index 01a773b8..c77888cd 100755 --- a/tests/t.ui/test.ui.032.table.11.pyside.align.01.py +++ b/tests/t.ui/test.ui.032.table.11.pyside.align.01.py @@ -22,6 +22,27 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +''' +PySide6 QTableView Alignment Example (for comparison) +====================================================== + +This is a PySide6/Qt reference example showing how text alignment works +in QTableView. It's provided for comparison with TTkTable alignment. + +Key Concepts: +- QAbstractTableModel for data handling +- Qt.DisplayRole for showing data +- Qt.TextAlignmentRole for alignment +- Combining flags: Qt.AlignLeft | Qt.AlignTop + +Alignment Options in Qt: +- Horizontal: AlignLeft, AlignCenter, AlignRight, AlignJustify +- Vertical: AlignTop, AlignVCenter, AlignBottom + +Compare this with TTkTable alignment in test.ui.032.table.13.alignment.*.py +to see how pyTermTk implements similar functionality in a terminal UI. +''' + from PySide6.QtWidgets import QApplication, QTableView from PySide6.QtCore import Qt, QAbstractTableModel diff --git a/tests/t.ui/test.ui.032.table.11.pyside.insert.01.py b/tests/t.ui/test.ui.032.table.11.pyside.insert.01.py index a730aeb4..3b036906 100755 --- a/tests/t.ui/test.ui.032.table.11.pyside.insert.01.py +++ b/tests/t.ui/test.ui.032.table.11.pyside.insert.01.py @@ -22,6 +22,28 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +''' +PySide6 QTableWidget Column Insertion Example (for comparison) +=============================================================== + +This is a PySide6/Qt reference example showing how to insert columns +into QTableWidget. It's provided for comparison with TTkTable. + +Key Operations: +- QTableWidget: Simpler than QTableView, manages data internally +- setHorizontalHeaderLabels(): Set column titles +- setItem(): Place data in cells +- insertColumn(): Add a new column at specific index +- setHorizontalHeaderItem(): Set header for new column + +This demonstrates the widget approach (data stored in widget) +rather than the model/view approach used by TTkTable. + +Qt provides both approaches: +- QTableWidget: Simple, data in widget (used here) +- QTableView + Model: More flexible, data separate (like TTkTable) +''' + from PySide6.QtWidgets import QApplication, QTableWidget, QTableWidgetItem app = QApplication([]) diff --git a/tests/t.ui/test.ui.032.table.11.pyside.insert.02.py b/tests/t.ui/test.ui.032.table.11.pyside.insert.02.py index 74050f2b..6183213e 100755 --- a/tests/t.ui/test.ui.032.table.11.pyside.insert.02.py +++ b/tests/t.ui/test.ui.032.table.11.pyside.insert.02.py @@ -22,6 +22,29 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +''' +PySide6 QTableView with QStandardItemModel Column Insertion (for comparison) +============================================================================ + +This is a PySide6/Qt reference example showing how to insert columns +using the model/view pattern with QStandardItemModel. + +Key Concepts: +- QStandardItemModel: Pre-built model for common use cases +- QTableView: View component that displays the model +- insertColumn(): Add column to model +- setHeaderData(): Set column header text +- Qt.Horizontal: Specify horizontal (column) orientation + +Model/View Pattern Benefits: +- Separation of data (model) and presentation (view) +- Multiple views can share one model +- Easier to update data without affecting display + +This is the pattern that TTkTable follows, providing similar +flexibility and power in a terminal-based interface. +''' + from PySide6.QtWidgets import QApplication, QTableView from PySide6.QtGui import QStandardItemModel, QStandardItem from PySide6.QtCore import Qt diff --git a/tests/t.ui/test.ui.032.table.12.py b/tests/t.ui/test.ui.032.table.12.py index 31755ba2..71e60461 100755 --- a/tests/t.ui/test.ui.032.table.12.py +++ b/tests/t.ui/test.ui.032.table.12.py @@ -25,6 +25,25 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Cell Edit Flags Example +================================= + +This example demonstrates controlling cell editability through ItemFlags. + +Key Features: +- Custom flags() method to control cell behavior per column +- ItemIsEnabled: Cell can receive focus +- ItemIsEditable: Cell content can be edited +- ItemIsSelectable: Cell can be selected +- Column 0: Only enabled and selectable (not editable) +- Column 1: Enabled and editable (can modify content) +- Other columns: Use default flags + +Useful for creating tables with mixed editable/read-only columns, +like forms where some fields are locked and others are user-editable. +''' + import os import sys import csv @@ -138,15 +157,20 @@ class MyTableModel(ttk.TTkTableModelList): return f"{prefix[num%len(prefix)]}:{num:03}" return super().headerData(num, orientation) + # Control cell behavior through flags + # This method determines what the user can do with each cell def flags(self, row: int, col: int) -> ttk.TTkConstant.ItemFlag: if col==0: + # Column 0: Read-only, can be selected but not edited return ( - ttk.TTkK.ItemFlag.ItemIsEnabled | - ttk.TTkK.ItemFlag.ItemIsSelectable ) + ttk.TTkK.ItemFlag.ItemIsEnabled | # Can receive focus + ttk.TTkK.ItemFlag.ItemIsSelectable ) # Can be selected if col==1: + # Column 1: Editable, user can modify content return ( - ttk.TTkK.ItemFlag.ItemIsEnabled | - ttk.TTkK.ItemFlag.ItemIsEditable ) + ttk.TTkK.ItemFlag.ItemIsEnabled | # Can receive focus + ttk.TTkK.ItemFlag.ItemIsEditable ) # Can be edited + # Other columns use default flags return super().flags(row, col) diff --git a/tests/t.ui/test.ui.032.table.13.alignment.01.py b/tests/t.ui/test.ui.032.table.13.alignment.01.py index 93afedaf..ca5573da 100755 --- a/tests/t.ui/test.ui.032.table.13.alignment.01.py +++ b/tests/t.ui/test.ui.032.table.13.alignment.01.py @@ -26,6 +26,26 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Cell Alignment Example +================================ + +This example demonstrates text alignment within table cells. + +Key Features: +- displayData() method returning (TTkString, Alignment) tuples +- Horizontal alignment: LEFT, CENTER, RIGHT, JUSTIFY +- Vertical alignment: TOP, CENTER, BOTTOM +- Combined alignments (e.g., LEFT|TOP, CENTER|CENTER, RIGHT|BOTTOM) +- Per-cell alignment control +- Multi-line text with different alignments + +The displayData() method allows returning both the cell content and +its desired alignment, providing fine-grained control over cell presentation. + +Alignment constants can be combined using the | (bitwise OR) operator. +''' + import os import sys import csv diff --git a/tests/t.ui/test.ui.032.table.13.alignment.02.overloading.py b/tests/t.ui/test.ui.032.table.13.alignment.02.overloading.py index f6d65504..b2dcf4d2 100755 --- a/tests/t.ui/test.ui.032.table.13.alignment.02.overloading.py +++ b/tests/t.ui/test.ui.032.table.13.alignment.02.overloading.py @@ -25,6 +25,21 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Alignment Example (Method Overloading) + +This example demonstrates how to control text alignment in table cells using method overloading. +Each column displays a different alignment type (LEFT, CENTER, RIGHT, JUSTIFIED) by overriding +the displayData() method to return a tuple of (data, alignment). + +Key features: +- Custom alignment per column using modulo arithmetic +- Method overloading of headerData() to label alignment types +- Method overloading of displayData() to return (TTkString, Alignment) tuple +- Multi-line cell content demonstrating alignment effects +- Automatic row/column resizing to fit content +''' + import os import sys import csv @@ -47,7 +62,9 @@ args = parser.parse_args() fullScreen = not args.w mouseTrack = True +# Custom table model that overrides display methods to control alignment class MyTableModel(ttk.TTkTableModelList): + # Override headerData() to label each column with its alignment type def headerData(self, num, orientation): if orientation == ttk.TTkK.HORIZONTAL: if 0 == num%4: @@ -60,7 +77,10 @@ class MyTableModel(ttk.TTkTableModelList): return f"{num} Justified" return super().headerData(num, orientation) + # Override displayData() to return (data, alignment) tuple + # This method determines how each cell's content is aligned def displayData(self:ttk.TTkTableModelList, row:int, col:int) -> Tuple[ttk.TTkString, ttk.TTkK.Alignment]: + # Cycle through alignment types based on column number if 0 == col%4: return self.ttkStringData(row, col), ttk.TTkK.Alignment.LEFT_ALIGN if 1 == col%4: @@ -71,25 +91,31 @@ class MyTableModel(ttk.TTkTableModelList): return self.ttkStringData(row, col), ttk.TTkK.Alignment.JUSTIFY return super().displayData(row,col) +# Create sample data with multi-line content in first column data_list1 = [[f"{y:03}\npippo\npeppo-ooo"]+[str(x) for x in range(10) ] for y in range(20)] + +# Add long multi-line text to specific cells to demonstrate alignment data_list1[1][1] = "abc def ghi\ndef ghi\nghi\njkl - pippo" data_list1[2][2] = "abc def ghi\ndef ghi\nghi\njkl - pippo" data_list1[3][3] = "abc def ghi\ndef ghi a b c de fgh s\nghi\njkl - pippo" data_list1[4][4] = "abc def ghi\ndef ghi\nghi\njkl - pippo" data_list1[5][5] = "abc def ghi\ndef ghi\nghi\njkl - pippo" +# Initialize the main application root = ttk.TTk(title="pyTermTk Table Demo", mouseTrack=mouseTrack) +# Setup layout - either fullscreen or windowed if fullScreen: rootTable = root root.setLayout(ttk.TTkGridLayout()) else: rootTable = ttk.TTkWindow(parent=root,pos = (0,0), size=(150,40), title="Test Table 1", layout=ttk.TTkGridLayout(), border=True) +# Create table with custom model and auto-resize to fit content table_model1 = MyTableModel(data=data_list1) table = ttk.TTkTable(parent=rootTable, tableModel=table_model1) -table.resizeRowsToContents() -table.resizeColumnsToContents() +table.resizeRowsToContents() # Adjust row heights for multi-line content +table.resizeColumnsToContents() # Adjust column widths for content root.mainloop() \ No newline at end of file diff --git a/tests/t.ui/test.ui.032.table.13.alignment.03.mixin.py b/tests/t.ui/test.ui.032.table.13.alignment.03.mixin.py index 44cc0ebf..3566a0a8 100755 --- a/tests/t.ui/test.ui.032.table.13.alignment.03.mixin.py +++ b/tests/t.ui/test.ui.032.table.13.alignment.03.mixin.py @@ -25,6 +25,22 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable Alignment Example (Mixin Pattern) + +This example demonstrates using a mixin class to control text alignment in table cells. +The mixin pattern allows reusing alignment logic across multiple table models by inheriting +from both the mixin class and the base table model class. + +Key features: +- Mixin class (MyTableMixin) containing reusable alignment logic +- Custom alignment per column using modulo arithmetic +- Multiple inheritance combining mixin with TTkTableModelList +- Preserves parent class functionality using super() calls +- Column-specific edit flags (column 0: selectable only, column 1: editable) +- Multi-line cell content demonstrating alignment effects +''' + import os import sys import csv @@ -47,7 +63,10 @@ args = parser.parse_args() fullScreen = not args.w mouseTrack = True +# Mixin class containing reusable alignment logic +# This can be combined with any table model class via multiple inheritance class MyTableMixin(): + # Override headerData() to label each column with its alignment type def headerData(self, num, orientation): if orientation == ttk.TTkK.HORIZONTAL: if 0 == num%4: @@ -60,8 +79,11 @@ class MyTableMixin(): return f"{num} Justified" return super().headerData(num, orientation) + # Override displayData() to apply custom alignment + # Note: Uses super() to get data from parent class, then modifies alignment def displayData(self:ttk.TTkTableModelList, row:int, col:int) -> Tuple[ttk.TTkString, ttk.TTkK.Alignment]: data, legacy_align = super().displayData(row,col) + # Cycle through alignment types based on column number if 0 == col%4: return data, ttk.TTkK.Alignment.LEFT_ALIGN if 1 == col%4: @@ -72,37 +94,48 @@ class MyTableMixin(): return data, ttk.TTkK.Alignment.JUSTIFY return data, legacy_align +# Final table model using multiple inheritance (mixin + base model) +# Order matters: MyTableMixin is checked first for method resolution class MyTableModel(MyTableMixin, ttk.TTkTableModelList): + # Override flags() to control which cells are editable def flags(self, row: int, col: int) -> ttk.TTkConstant.ItemFlag: if col==0: + # Column 0: Selectable but not editable return ( ttk.TTkK.ItemFlag.ItemIsEnabled | ttk.TTkK.ItemFlag.ItemIsSelectable ) if col==1: + # Column 1: Fully editable return ( ttk.TTkK.ItemFlag.ItemIsEnabled | ttk.TTkK.ItemFlag.ItemIsEditable ) return super().flags(row, col) +# Create sample data with multi-line content in first column data_list1 = [[f"{y:03}\npippo\npeppo-ooo"]+[str(x) for x in range(10) ] for y in range(20)] + +# Add long multi-line text to specific cells to demonstrate alignment data_list1[1][1] = "abc def ghi\ndef ghi\nghi\njkl - pippo" data_list1[2][2] = "abc def ghi\ndef ghi\nghi\njkl - pippo" data_list1[3][3] = "abc def ghi\ndef ghi a b c de fgh s\nghi\njkl - pippo" data_list1[4][4] = "abc def ghi\ndef ghi\nghi\njkl - pippo" data_list1[5][5] = "abc def ghi\ndef ghi\nghi\njkl - pippo" +# Initialize the main application root = ttk.TTk(title="pyTermTk Table Demo", mouseTrack=mouseTrack) +# Setup layout - either fullscreen or windowed if fullScreen: rootTable = root root.setLayout(ttk.TTkGridLayout()) else: rootTable = ttk.TTkWindow(parent=root,pos = (0,0), size=(150,40), title="Test Table 1", layout=ttk.TTkGridLayout(), border=True) +# Create table with custom model using mixin pattern table_model1 = MyTableModel(data=data_list1) table = ttk.TTkTable(parent=rootTable, tableModel=table_model1) -table.resizeRowsToContents() -table.resizeColumnsToContents() +table.resizeRowsToContents() # Adjust row heights for multi-line content +table.resizeColumnsToContents() # Adjust column widths for content root.mainloop() \ No newline at end of file diff --git a/tests/t.ui/test.ui.032.table.14.list.01.item.py b/tests/t.ui/test.ui.032.table.14.list.01.item.py index 93cbcf0f..13167717 100755 --- a/tests/t.ui/test.ui.032.table.14.list.01.item.py +++ b/tests/t.ui/test.ui.032.table.14.list.01.item.py @@ -25,6 +25,24 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable with TTkCellListType Example +====================================== + +This example demonstrates using TTkCellListType for dropdown lists in cells. + +Key Features: +- TTkCellListType: Creates a dropdown/combo box within a cell +- Mixed cell types: booleans, strings, and list selectors +- value parameter: The currently selected item +- items parameter: List of available options +- Interactive selection: Click cell to see dropdown menu +- Automatic cell editor for list types + +TTkCellListType is useful for creating tables where users can select +from predefined options, similar to dropdown menus in spreadsheet applications. +''' + import os import sys import argparse @@ -46,18 +64,23 @@ fullScreen = not args.w mouseTrack = True +# Create a list of options for the dropdown cells data_list = [ 'Pippo', 'Pluto', 'Paperino', 'Qui', 'Quo', 'Qua', # L'accento non ci va 'Minnie', 'Topolino' ] +# Generate table data with mixed types: +# Column 0: Boolean checkboxes +# Column 1-2: Simple strings +# Column 3: TTkCellListType dropdown with random selection from data_list data = [ [ - bool(random.randint(0,1)), - 'Pippo', - 'Pluto', - ttk.TTkCellListType(value=random.choice(data_list), items=data_list) + bool(random.randint(0,1)), # Random True/False + 'Pippo', # Fixed string + 'Pluto', # Fixed string + ttk.TTkCellListType(value=random.choice(data_list), items=data_list) # Dropdown list ] for y in range(20) ] diff --git a/tests/t.ui/test.ui.032.table.14.list.02.custom.py b/tests/t.ui/test.ui.032.table.14.list.02.custom.py index bffe9f80..37c4d5a5 100755 --- a/tests/t.ui/test.ui.032.table.14.list.02.custom.py +++ b/tests/t.ui/test.ui.032.table.14.list.02.custom.py @@ -25,6 +25,27 @@ # Demo inspired from: # https://www.daniweb.com/programming/software-development/code/447834/applying-pyside-s-qabstracttablemodel +''' +TTkTable with Custom Enum Types Example +======================================== + +This example demonstrates displaying Python Enum types in table cells. + +Key Features: +- Custom Enum classes with auto() values +- Enum display using __str__() method +- Boolean Enum (MyEnumYesNo) with True/False values +- Mixed Enum types in different columns +- Automatic enum value rendering +- Random enum selection for variety + +The table automatically displays enum values by calling their __str__() method, +making it easy to show meaningful names instead of raw enum values. + +Useful for displaying categorical data, status fields, or any predefined +set of options in a human-readable format. +''' + import os import sys import argparse @@ -47,20 +68,26 @@ args = parser.parse_args() fullScreen = not args.w mouseTrack = True +# Custom Enum for demonstrating enum display in tables class MyEnum(Enum): - Foo=auto() + Foo=auto() # auto() generates sequential values automatically Bar=auto() Baz=auto() + # Override __str__ to display the enum name instead of the full value def __str__(self): return self.name +# Boolean-like Enum that maps to True/False values class MyEnumYesNo(Enum): - Yes=True - No=False + Yes=True # Maps to boolean True + No=False # Maps to boolean False + # Display as "Yes" or "No" instead of "MyEnumYesNo.Yes" def __str__(self): return self.name + + # Allow the enum to be used in boolean contexts def __bool__(self): return self.value diff --git a/tests/t.ui/test.ui.032.table.15.test.clipboard.py b/tests/t.ui/test.ui.032.table.15.test.clipboard.py index 1d6b305a..abfc431f 100755 --- a/tests/t.ui/test.ui.032.table.15.test.clipboard.py +++ b/tests/t.ui/test.ui.032.table.15.test.clipboard.py @@ -22,6 +22,34 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +''' +TTkTable Clipboard Operations Example +====================================== + +This example demonstrates table clipboard functionality and complex data types. + +Key Features: +- Clipboard operations (copy/paste) with Ctrl+C/Ctrl+Z signals enabled +- Mixed data types in cells: + * Hex numbers (formatted strings) + * TTkString with colors + * Boolean values + * TTkCellListType (dropdown lists) + * Custom Enum types + * datetime.time objects + * datetime.date objects + * datetime.datetime objects +- Random data generation for dates and times +- Signal mask configuration for clipboard shortcuts + +Usage: +- Select cells and press Ctrl+C to copy +- Use Ctrl+Z for undo (if enabled in application) + +This example shows how TTkTable handles various Python data types +and provides built-in clipboard support. +''' + import os import sys import argparse @@ -45,21 +73,21 @@ args = parser.parse_args() fullScreen = not args.w mouseTrack = True -# Random date between two dates +# Helper function to generate random dates within a range def random_date(start_date, end_date): time_between = end_date - start_date days_between = time_between.days random_days = random.randrange(days_between) return start_date + datetime.timedelta(days=random_days) -# Random time +# Helper function to generate random times def random_time(): hour = random.randint(0, 23) minute = random.randint(0, 59) second = random.randint(0, 59) return datetime.time(hour, minute, second) -# Random datetime +# Helper function to generate random datetimes within a range def random_datetime(start_datetime, end_datetime): time_between = end_datetime - start_datetime total_seconds = int(time_between.total_seconds())