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

menus.mddocs/

Menu System

Groovy Swing provides comprehensive menu system support with factories for creating menu bars, menus, menu items, and popup menus with full action integration.

Menu Components

Core menu components for building application menu systems.

// Menu containers
def menuBar(Map attributes = [:], Closure closure = null)
def menu(Map attributes = [:], Closure closure = null)
def popupMenu(Map attributes = [:], Closure closure = null)

// Menu items
def menuItem(Map attributes = [:], Closure closure = null)
def checkBoxMenuItem(Map attributes = [:], Closure closure = null)
def radioButtonMenuItem(Map attributes = [:], Closure closure = null)

// Separators
def separator(Map attributes = [:])

Basic Menu Structure

Creating standard application menus with menu bars and menu items.

Menu Bar Examples

swing.frame(title: 'Menu Example') {
    // Create menu bar
    menuBar {
        // File menu
        menu(text: 'File', mnemonic: 'F') {
            menuItem(text: 'New', mnemonic: 'N', accelerator: shortcut('N')) {
                actionPerformed { println 'New file' }
            }
            menuItem(text: 'Open', mnemonic: 'O', accelerator: shortcut('O')) {
                actionPerformed { println 'Open file' }
            }
            menuItem(text: 'Save', mnemonic: 'S', accelerator: shortcut('S')) {
                actionPerformed { println 'Save file' }
            }
            separator()
            menuItem(text: 'Exit', mnemonic: 'x') {
                actionPerformed { System.exit(0) }
            }
        }
        
        // Edit menu
        menu(text: 'Edit', mnemonic: 'E') {
            menuItem(text: 'Cut', accelerator: shortcut('X')) {
                actionPerformed { println 'Cut' }
            }
            menuItem(text: 'Copy', accelerator: shortcut('C')) {
                actionPerformed { println 'Copy' }
            }
            menuItem(text: 'Paste', accelerator: shortcut('V')) {
                actionPerformed { println 'Paste' }
            }
        }
        
        // View menu with checkboxes
        menu(text: 'View', mnemonic: 'V') {
            checkBoxMenuItem(text: 'Show Toolbar', selected: true) {
                actionPerformed { e ->
                    println "Toolbar ${e.source.selected ? 'shown' : 'hidden'}"
                }
            }
            checkBoxMenuItem(text: 'Show Status Bar', selected: false) {
                actionPerformed { e ->
                    println "Status bar ${e.source.selected ? 'shown' : 'hidden'}"
                }
            }
        }
    }
    
    // Main content
    panel {
        label(text: 'Application content')
    }
}

Action Integration

Using Action objects for consistent menu and toolbar integration.

// Action factory for reusable actions
def action(Map attributes = [:])

// Action attributes:
// name: String - action name/text
// closure: Closure - action code
// mnemonic: String/int - keyboard mnemonic
// accelerator: KeyStroke - keyboard shortcut
// smallIcon: Icon - small icon for toolbar
// largeIcon: Icon - large icon
// shortDescription: String - tooltip text
// longDescription: String - detailed description
// enabled: boolean - whether action is enabled

Action Examples

def swing = new SwingBuilder()

// Define reusable actions
def newAction = swing.action(
    name: 'New',
    closure: { println 'Creating new document' },
    mnemonic: 'N',
    accelerator: swing.shortcut('N'),
    smallIcon: swing.imageIcon('/icons/new.png'),
    shortDescription: 'Create a new document'
)

def saveAction = swing.action(
    name: 'Save',
    closure: { println 'Saving document' },
    mnemonic: 'S', 
    accelerator: swing.shortcut('S'),
    smallIcon: swing.imageIcon('/icons/save.png'),
    shortDescription: 'Save the current document'
)

def exitAction = swing.action(
    name: 'Exit',
    closure: { System.exit(0) },
    mnemonic: 'x',
    shortDescription: 'Exit the application'
)

// Use actions in both menu and toolbar
swing.frame(title: 'Action Integration') {
    borderLayout()
    
    // Menu bar using actions
    menuBar {
        menu(text: 'File') {
            menuItem(action: newAction)
            separator()
            menuItem(action: saveAction)
            separator()
            menuItem(action: exitAction)
        }
    }
    
    // Toolbar using same actions
    toolBar(constraints: BorderLayout.NORTH) {
        button(action: newAction)
        button(action: saveAction)
        separator()
        button(action: exitAction)
    }
    
    // Content area
    panel(constraints: BorderLayout.CENTER) {
        label(text: 'Document content')
    }
}

Popup Menus

Context menus that appear on right-click or other triggers.

def popupMenu(Map attributes = [:], Closure closure = null)

// PopupMenu is typically shown via:
// component.componentPopupMenu = popupMenu
// or programmatically with show(component, x, y)

Popup Menu Examples

// Create popup menu
def contextMenu = swing.popupMenu {
    menuItem(text: 'Cut') {
        actionPerformed { println 'Cut from context menu' }
    }
    menuItem(text: 'Copy') {
        actionPerformed { println 'Copy from context menu' }
    }
    menuItem(text: 'Paste') {
        actionPerformed { println 'Paste from context menu' }
    }
    separator()
    menuItem(text: 'Properties') {
        actionPerformed { println 'Show properties' }
    }
}

// Attach popup to component
swing.textArea(
    rows: 10,
    columns: 40,
    componentPopupMenu: contextMenu
)

// Manual popup triggering
swing.panel {
    mouseClicked { e ->
        if (e.button == MouseEvent.BUTTON3) {  // Right click
            contextMenu.show(e.component, e.x, e.y)
        }
    }
}

Menu Item Types

Different types of menu items for various interaction patterns.

Checkbox Menu Items

def viewSettings = [
    showToolbar: true,
    showStatusBar: false,
    showSidebar: true
]

swing.menu(text: 'View') {
    checkBoxMenuItem(
        text: 'Show Toolbar',
        selected: bind(source: viewSettings, sourceProperty: 'showToolbar')
    ) {
        actionPerformed { e ->
            viewSettings.showToolbar = e.source.selected
            updateToolbarVisibility(viewSettings.showToolbar)
        }
    }
    
    checkBoxMenuItem(
        text: 'Show Status Bar',
        selected: bind(source: viewSettings, sourceProperty: 'showStatusBar')
    ) {
        actionPerformed { e ->
            viewSettings.showStatusBar = e.source.selected
            updateStatusBarVisibility(viewSettings.showStatusBar)
        }
    }
}

Radio Button Menu Items

def documentMode = new ValueHolder('edit')

swing.menu(text: 'Mode') {
    def modeGroup = buttonGroup()
    
    radioButtonMenuItem(
        text: 'Edit Mode',
        buttonGroup: modeGroup,
        selected: bind(source: documentMode, sourceProperty: 'value', 
                      converter: { it == 'edit' })
    ) {
        actionPerformed {
            documentMode.value = 'edit'
            switchToEditMode()
        }
    }
    
    radioButtonMenuItem(
        text: 'Preview Mode',
        buttonGroup: modeGroup, 
        selected: bind(source: documentMode, sourceProperty: 'value',
                      converter: { it == 'preview' })
    ) {
        actionPerformed {
            documentMode.value = 'preview'
            switchToPreviewMode()
        }
    }
    
    radioButtonMenuItem(
        text: 'Presentation Mode',
        buttonGroup: modeGroup,
        selected: bind(source: documentMode, sourceProperty: 'value',
                      converter: { it == 'presentation' })
    ) {
        actionPerformed {
            documentMode.value = 'presentation'
            switchToPresentationMode()
        }
    }
}

Dynamic Menus

Creating menus that change based on application state.

Recent Files Menu

class RecentFilesManager {
    List<String> recentFiles = []
    int maxFiles = 5
    
    void addFile(String filename) {
        recentFiles.remove(filename)  // Remove if already exists
        recentFiles.add(0, filename)  // Add to beginning
        if (recentFiles.size() > maxFiles) {
            recentFiles = recentFiles[0..<maxFiles]
        }
    }
}

def recentFilesManager = new RecentFilesManager()

def updateRecentFilesMenu = { menu ->
    // Clear existing recent file items
    menu.removeAll()
    
    if (recentFilesManager.recentFiles.empty) {
        def item = swing.menuItem(text: 'No recent files', enabled: false)
        menu.add(item)
    } else {
        recentFilesManager.recentFiles.eachWithIndex { filename, index ->
            def item = swing.menuItem(
                text: "&${index + 1} ${new File(filename).name}",
                toolTipText: filename
            ) {
                actionPerformed {
                    openFile(filename)
                }
            }
            menu.add(item)
        }
    }
}

swing.frame(title: 'Dynamic Menu Example') {
    menuBar {
        menu(text: 'File') {
            menuItem(text: 'New') { actionPerformed { /* new file logic */ } }
            menuItem(text: 'Open') { 
                actionPerformed { 
                    def filename = showOpenDialog()
                    if (filename) {
                        openFile(filename)
                        recentFilesManager.addFile(filename)
                        updateRecentFilesMenu(recentFilesMenu)
                    }
                }
            }
            separator()
            
            // Recent files submenu
            def recentFilesMenu = menu(text: 'Recent Files')
            updateRecentFilesMenu(recentFilesMenu)
        }
    }
}

Menu Styling and Icons

Customizing menu appearance with icons, fonts, and colors.

swing.menuBar {
    menu(text: 'File', font: new Font('Arial', Font.BOLD, 12)) {
        menuItem(
            text: 'New Document',
            icon: swing.imageIcon('/icons/document-new.png'),
            accelerator: swing.shortcut('N')
        ) {
            actionPerformed { println 'New document' }
        }
        
        menuItem(
            text: 'Open Document',
            icon: swing.imageIcon('/icons/document-open.png'),
            accelerator: swing.shortcut('O')
        ) {
            actionPerformed { println 'Open document' }
        }
        
        separator()
        
        menuItem(
            text: 'Recent Documents',
            icon: swing.imageIcon('/icons/document-recent.png')
        ) {
            // Submenu with recent files
        }
    }
    
    menu(text: 'Tools') {
        menuItem(
            text: 'Preferences',
            icon: swing.imageIcon('/icons/preferences.png'),
            foreground: Color.BLUE
        ) {
            actionPerformed { showPreferences() }
        }
    }
}

Keyboard Navigation

Setting up proper keyboard navigation and mnemonics.

swing.menuBar {
    menu(text: 'File', mnemonic: 'F') {  // Alt+F to open
        menuItem(
            text: 'New',
            mnemonic: 'N',  // Alt+F, N to activate
            accelerator: swing.shortcut('N')  // Ctrl+N direct shortcut
        )
        menuItem(
            text: 'Open Recent',
            mnemonic: 'R'
        ) {
            // Submenu
            menuItem(text: 'Document 1.txt', mnemonic: '1')
            menuItem(text: 'Document 2.txt', mnemonic: '2')
        }
    }
    
    menu(text: 'Edit', mnemonic: 'E') {  // Alt+E to open
        menuItem(
            text: 'Undo',
            mnemonic: 'U',
            accelerator: swing.shortcut('Z')
        )
        menuItem(
            text: 'Redo', 
            mnemonic: 'R',
            accelerator: swing.shortcut('Y')
        )
    }
}

Menu State Management

Managing menu item states based on application context.

class MenuStateManager {
    boolean hasSelection = false
    boolean hasContent = false
    boolean canUndo = false
    boolean canRedo = false
    
    def cutAction, copyAction, pasteAction, undoAction, redoAction
    
    void updateMenuStates() {
        cutAction?.enabled = hasSelection
        copyAction?.enabled = hasSelection
        undoAction?.enabled = canUndo
        redoAction?.enabled = canRedo
    }
}

def stateManager = new MenuStateManager()

// Create actions with initial states
stateManager.cutAction = swing.action(
    name: 'Cut',
    enabled: false,
    closure: { performCut() }
)

stateManager.copyAction = swing.action(
    name: 'Copy', 
    enabled: false,
    closure: { performCopy() }
)

// Update states based on events
textComponent.selectionListener = { e ->
    stateManager.hasSelection = (e.source.selectedText != null)
    stateManager.updateMenuStates()
}

// Use in menu
swing.menuBar {
    menu(text: 'Edit') {
        menuItem(action: stateManager.cutAction)
        menuItem(action: stateManager.copyAction)
        // ... other items
    }
}

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