CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-groovy--groovy-swing

SwingBuilder for creating Swing GUIs in Groovy - provides DSL for declarative UI construction

Pending
Overview
Eval results
Files

tables.mddocs/

Table Support

Groovy Swing provides comprehensive table support with enhanced models, custom columns, renderers, and sorters for building data-driven table interfaces.

Basic Table Components

Core table components for displaying tabular data.

// Table component
def table(Map attributes = [:], Closure closure = null)

// Table structure
def tableModel(Map attributes = [:], Closure closure = null)
def columnModel(Map attributes = [:])
def tableColumn(Map attributes = [:])

// Column types
def column(Map attributes = [:])
def propertyColumn(Map attributes = [:])
def closureColumn(Map attributes = [:])

Table Models

Enhanced table models with ValueModel integration and data binding support.

// Default table model with enhanced features
class DefaultTableModel extends AbstractTableModel {
    DefaultTableModel()
    DefaultTableModel(List rowData, List columnNames)
    
    // ValueModel integration
    ValueModel getValueModel(int row, int column)
    void setValueModel(ValueModel model, int row, int column)
}

// Table model factory attributes:
// list: List - row data as list of maps or objects
// columns: List - column definitions
// sortable: boolean - enable sorting support

Basic Table Examples

def swing = new SwingBuilder()

// Simple table with data
def tableData = [
    [name: 'John', age: 30, city: 'New York'],
    [name: 'Jane', age: 25, city: 'Los Angeles'],
    [name: 'Bob', age: 35, city: 'Chicago']
]

swing.frame(title: 'Simple Table') {
    scrollPane {
        table(
            model: tableModel(list: tableData) {
                propertyColumn(header: 'Name', propertyName: 'name', width: 100)
                propertyColumn(header: 'Age', propertyName: 'age', width: 50)
                propertyColumn(header: 'City', propertyName: 'city', width: 120)
            }
        )
    }
}

// Table with explicit column model
swing.scrollPane {
    table {
        // Define table model
        tableModel(list: tableData)
        
        // Define column model
        columnModel {
            column(header: 'Name', width: 100)
            column(header: 'Age', width: 50)
            column(header: 'City', width: 120)
        }
    }
}

Column Types

Different column types for various data display and editing scenarios.

Property Columns

def propertyColumn(Map attributes = [:])

// PropertyColumn attributes:
// header: String - column header text
// propertyName: String - property name to bind to
// type: Class - property type for editing
// width: int - preferred column width
// editable: boolean - whether column is editable
// renderer: TableCellRenderer - custom renderer
// editor: TableCellEditor - custom editor

Closure Columns

def closureColumn(Map attributes = [:])

// ClosureColumn attributes:
// header: String - column header text
// read: Closure - closure to read value from row object
// write: Closure - closure to write value to row object (optional)
// type: Class - value type
// width: int - preferred column width
// editable: boolean - whether column is editable

Column Examples

def people = [
    new Person(firstName: 'John', lastName: 'Doe', age: 30),
    new Person(firstName: 'Jane', lastName: 'Smith', age: 25)
]

swing.scrollPane {
    table(model: tableModel(list: people)) {
        // Property-based columns
        propertyColumn(
            header: 'First Name',
            propertyName: 'firstName',
            width: 100,
            editable: true
        )
        
        propertyColumn(
            header: 'Last Name', 
            propertyName: 'lastName',
            width: 100,
            editable: true
        )
        
        propertyColumn(
            header: 'Age',
            propertyName: 'age',
            type: Integer,
            width: 50,
            editable: true
        )
        
        // Closure-based computed column
        closureColumn(
            header: 'Full Name',
            read: { row -> "${row.firstName} ${row.lastName}" },
            width: 150,
            editable: false
        )
        
        // Closure column with custom formatting
        closureColumn(
            header: 'Status',
            read: { row -> row.age >= 30 ? 'Senior' : 'Junior' },
            width: 80
        )
    }
}

Table Cell Renderers

Custom renderers for specialized cell display.

// Renderer factories
def tableCellRenderer(Map attributes = [:])
def listCellRenderer(Map attributes = [:])
def cellRenderer(Map attributes = [:])
def headerRenderer(Map attributes = [:])

// Renderer update factory
def onRender(Closure renderClosure)

Renderer Examples

swing.scrollPane {
    table(model: tableModel(list: salesData)) {
        propertyColumn(header: 'Product', propertyName: 'product')
        
        propertyColumn(header: 'Revenue', propertyName: 'revenue') {
            // Custom currency renderer
            tableCellRenderer { renderer, table, value, isSelected, hasFocus, row, column ->
                renderer.text = NumberFormat.getCurrencyInstance().format(value)
                if (value > 10000) {
                    renderer.foreground = Color.GREEN
                    renderer.font = renderer.font.deriveFont(Font.BOLD)
                } else {
                    renderer.foreground = Color.BLACK
                    renderer.font = renderer.font.deriveFont(Font.PLAIN)
                }
                return renderer
            }
        }
        
        propertyColumn(header: 'Status', propertyName: 'status') {
            // Icon renderer based on status
            tableCellRenderer { renderer, table, value, isSelected, hasFocus, row, column ->
                renderer.text = value
                renderer.icon = value == 'Active' ? activeIcon : inactiveIcon
                return renderer
            }
        }
        
        // Progress bar renderer for percentage column
        propertyColumn(header: 'Progress', propertyName: 'percentage') {
            tableCellRenderer { renderer, table, value, isSelected, hasFocus, row, column ->
                def progressBar = new JProgressBar(0, 100)
                progressBar.value = value
                progressBar.stringPainted = true
                progressBar.string = "${value}%"
                return progressBar
            }
        }
    }
}

Table Cell Editors

Custom editors for specialized cell editing.

// Editor factories
def cellEditor(Map attributes = [:])
def editorValue(Closure valueClosure)
def prepareEditor(Closure prepareClosure)

Editor Examples

swing.scrollPane {
    table(model: tableModel(list: employeeData)) {
        propertyColumn(header: 'Name', propertyName: 'name')
        
        propertyColumn(header: 'Department', propertyName: 'department') {
            // Combo box editor
            cellEditor {
                comboBox(items: ['Sales', 'Marketing', 'Engineering', 'HR'])
            }
        }
        
        propertyColumn(header: 'Salary', propertyName: 'salary') {
            // Formatted text field editor
            cellEditor {
                formattedTextField(format: NumberFormat.getCurrencyInstance())
            }
        }
        
        propertyColumn(header: 'Start Date', propertyName: 'startDate') {
            // Custom date picker editor
            cellEditor {
                bean(class: 'com.toedter.calendar.JDateChooser')
            }
            
            // Custom value extraction
            editorValue { editor ->
                return editor.date
            }
            
            // Custom editor preparation
            prepareEditor { editor, table, value, isSelected, row, column ->
                editor.date = value
                return editor
            }
        }
    }
}

Table Sorting

Built-in sorting support with TableSorter integration.

// TableSorter class for sortable table models
class TableSorter extends TableMap {
    TableSorter(TableModel model)
    
    void setTableHeader(JTableHeader tableHeader)
    boolean isSorting()
    int getSortingStatus(int column)
    void setSortingStatus(int column, int status)
}

// Sorting constants
// DESCENDING = -1
// NOT_SORTED = 0  
// ASCENDING = 1

Sorting Examples

import groovy.swing.table.TableSorter

def tableData = [
    [name: 'Alice', age: 30, salary: 50000],
    [name: 'Bob', age: 25, salary: 45000],
    [name: 'Charlie', age: 35, salary: 60000]
]

swing.frame(title: 'Sortable Table') {
    scrollPane {
        def tableModel = tableModel(list: tableData)
        def sorter = new TableSorter(tableModel)
        
        table(model: sorter) {
            // Connect sorter to table header for click sorting
            sorter.setTableHeader(it.tableHeader)
            
            propertyColumn(header: 'Name', propertyName: 'name')
            propertyColumn(header: 'Age', propertyName: 'age', type: Integer)
            propertyColumn(header: 'Salary', propertyName: 'salary', type: Integer)
        }
    }
}

// Programmatic sorting
sorter.setSortingStatus(1, TableSorter.ASCENDING)  // Sort by age ascending

Table Selection and Events

Table selection handling and event processing.

// Selection binding support
// selectedRow: int - selected row index
// selectedColumn: int - selected column index  
// selectedElement: Object - selected row object
// selectedElements: List - multiple selected objects

Selection Examples

def selectedPerson = new ValueHolder()

swing.frame(title: 'Table Selection') {
    borderLayout()
    
    // Table with selection binding
    scrollPane(constraints: BorderLayout.CENTER) {
        table(
            model: tableModel(list: people),
            selectedElement: bind(source: selectedPerson, sourceProperty: 'value')
        ) {
            propertyColumn(header: 'Name', propertyName: 'name')
            propertyColumn(header: 'Age', propertyName: 'age')
        }
    }
    
    // Detail panel showing selected person
    panel(constraints: BorderLayout.SOUTH) {
        label(text: bind(
            source: selectedPerson,
            sourceProperty: 'value',
            converter: { person ->
                person ? "Selected: ${person.name} (${person.age})" : "No selection"
            }
        ))
    }
}

// Multiple selection
swing.table(
    selectionMode: ListSelectionModel.MULTIPLE_INTERVAL_SELECTION,
    selectedElements: bind(source: selectedItems, sourceProperty: 'value')
) {
    // Table columns...
}

Advanced Table Features

Custom Table Models

// Custom table model with live data
class LiveDataTableModel extends DefaultTableModel {
    void startUpdating() {
        timer = new Timer(1000) { 
            // Update data periodically
            fireTableDataChanged()
        }
        timer.start()
    }
}

swing.table(model: new LiveDataTableModel()) {
    // Column definitions...
}

Table with Filtering

def originalData = [/* data */]
def filteredData = new FilteredListModel(originalData)
def filterText = new ValueHolder('')

swing.frame(title: 'Filtered Table') {
    borderLayout()
    
    // Filter input
    panel(constraints: BorderLayout.NORTH) {
        label(text: 'Filter:')
        textField(
            columns: 20,
            text: bind(source: filterText, sourceProperty: 'value')
        ) {
            // Apply filter on text change
            bind(source: filterText, sourceProperty: 'value') { newValue ->
                filteredData.filter = { item ->
                    item.name.toLowerCase().contains(newValue.toLowerCase())
                }
            }
        }
    }
    
    // Filtered table
    scrollPane(constraints: BorderLayout.CENTER) {
        table(model: tableModel(list: filteredData)) {
            propertyColumn(header: 'Name', propertyName: 'name')
            propertyColumn(header: 'Description', propertyName: 'description')
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-groovy--groovy-swing

docs

borders.md

components.md

core-builder.md

data-binding.md

index.md

layouts.md

menus.md

tables.md

tile.json