or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

borders.mdcomponents.mdcore-builder.mddata-binding.mdindex.mdlayouts.mdmenus.mdtables.md

menus.mddocs/

0

# Menu System

1

2

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

3

4

## Menu Components

5

6

Core menu components for building application menu systems.

7

8

```groovy { .api }

9

// Menu containers

10

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

11

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

12

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

13

14

// Menu items

15

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

16

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

17

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

18

19

// Separators

20

def separator(Map attributes = [:])

21

```

22

23

## Basic Menu Structure

24

25

Creating standard application menus with menu bars and menu items.

26

27

### Menu Bar Examples

28

29

```groovy

30

swing.frame(title: 'Menu Example') {

31

// Create menu bar

32

menuBar {

33

// File menu

34

menu(text: 'File', mnemonic: 'F') {

35

menuItem(text: 'New', mnemonic: 'N', accelerator: shortcut('N')) {

36

actionPerformed { println 'New file' }

37

}

38

menuItem(text: 'Open', mnemonic: 'O', accelerator: shortcut('O')) {

39

actionPerformed { println 'Open file' }

40

}

41

menuItem(text: 'Save', mnemonic: 'S', accelerator: shortcut('S')) {

42

actionPerformed { println 'Save file' }

43

}

44

separator()

45

menuItem(text: 'Exit', mnemonic: 'x') {

46

actionPerformed { System.exit(0) }

47

}

48

}

49

50

// Edit menu

51

menu(text: 'Edit', mnemonic: 'E') {

52

menuItem(text: 'Cut', accelerator: shortcut('X')) {

53

actionPerformed { println 'Cut' }

54

}

55

menuItem(text: 'Copy', accelerator: shortcut('C')) {

56

actionPerformed { println 'Copy' }

57

}

58

menuItem(text: 'Paste', accelerator: shortcut('V')) {

59

actionPerformed { println 'Paste' }

60

}

61

}

62

63

// View menu with checkboxes

64

menu(text: 'View', mnemonic: 'V') {

65

checkBoxMenuItem(text: 'Show Toolbar', selected: true) {

66

actionPerformed { e ->

67

println "Toolbar ${e.source.selected ? 'shown' : 'hidden'}"

68

}

69

}

70

checkBoxMenuItem(text: 'Show Status Bar', selected: false) {

71

actionPerformed { e ->

72

println "Status bar ${e.source.selected ? 'shown' : 'hidden'}"

73

}

74

}

75

}

76

}

77

78

// Main content

79

panel {

80

label(text: 'Application content')

81

}

82

}

83

```

84

85

## Action Integration

86

87

Using Action objects for consistent menu and toolbar integration.

88

89

```groovy { .api }

90

// Action factory for reusable actions

91

def action(Map attributes = [:])

92

93

// Action attributes:

94

// name: String - action name/text

95

// closure: Closure - action code

96

// mnemonic: String/int - keyboard mnemonic

97

// accelerator: KeyStroke - keyboard shortcut

98

// smallIcon: Icon - small icon for toolbar

99

// largeIcon: Icon - large icon

100

// shortDescription: String - tooltip text

101

// longDescription: String - detailed description

102

// enabled: boolean - whether action is enabled

103

```

104

105

### Action Examples

106

107

```groovy

108

def swing = new SwingBuilder()

109

110

// Define reusable actions

111

def newAction = swing.action(

112

name: 'New',

113

closure: { println 'Creating new document' },

114

mnemonic: 'N',

115

accelerator: swing.shortcut('N'),

116

smallIcon: swing.imageIcon('/icons/new.png'),

117

shortDescription: 'Create a new document'

118

)

119

120

def saveAction = swing.action(

121

name: 'Save',

122

closure: { println 'Saving document' },

123

mnemonic: 'S',

124

accelerator: swing.shortcut('S'),

125

smallIcon: swing.imageIcon('/icons/save.png'),

126

shortDescription: 'Save the current document'

127

)

128

129

def exitAction = swing.action(

130

name: 'Exit',

131

closure: { System.exit(0) },

132

mnemonic: 'x',

133

shortDescription: 'Exit the application'

134

)

135

136

// Use actions in both menu and toolbar

137

swing.frame(title: 'Action Integration') {

138

borderLayout()

139

140

// Menu bar using actions

141

menuBar {

142

menu(text: 'File') {

143

menuItem(action: newAction)

144

separator()

145

menuItem(action: saveAction)

146

separator()

147

menuItem(action: exitAction)

148

}

149

}

150

151

// Toolbar using same actions

152

toolBar(constraints: BorderLayout.NORTH) {

153

button(action: newAction)

154

button(action: saveAction)

155

separator()

156

button(action: exitAction)

157

}

158

159

// Content area

160

panel(constraints: BorderLayout.CENTER) {

161

label(text: 'Document content')

162

}

163

}

164

```

165

166

## Popup Menus

167

168

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

169

170

```groovy { .api }

171

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

172

173

// PopupMenu is typically shown via:

174

// component.componentPopupMenu = popupMenu

175

// or programmatically with show(component, x, y)

176

```

177

178

### Popup Menu Examples

179

180

```groovy

181

// Create popup menu

182

def contextMenu = swing.popupMenu {

183

menuItem(text: 'Cut') {

184

actionPerformed { println 'Cut from context menu' }

185

}

186

menuItem(text: 'Copy') {

187

actionPerformed { println 'Copy from context menu' }

188

}

189

menuItem(text: 'Paste') {

190

actionPerformed { println 'Paste from context menu' }

191

}

192

separator()

193

menuItem(text: 'Properties') {

194

actionPerformed { println 'Show properties' }

195

}

196

}

197

198

// Attach popup to component

199

swing.textArea(

200

rows: 10,

201

columns: 40,

202

componentPopupMenu: contextMenu

203

)

204

205

// Manual popup triggering

206

swing.panel {

207

mouseClicked { e ->

208

if (e.button == MouseEvent.BUTTON3) { // Right click

209

contextMenu.show(e.component, e.x, e.y)

210

}

211

}

212

}

213

```

214

215

## Menu Item Types

216

217

Different types of menu items for various interaction patterns.

218

219

### Checkbox Menu Items

220

221

```groovy

222

def viewSettings = [

223

showToolbar: true,

224

showStatusBar: false,

225

showSidebar: true

226

]

227

228

swing.menu(text: 'View') {

229

checkBoxMenuItem(

230

text: 'Show Toolbar',

231

selected: bind(source: viewSettings, sourceProperty: 'showToolbar')

232

) {

233

actionPerformed { e ->

234

viewSettings.showToolbar = e.source.selected

235

updateToolbarVisibility(viewSettings.showToolbar)

236

}

237

}

238

239

checkBoxMenuItem(

240

text: 'Show Status Bar',

241

selected: bind(source: viewSettings, sourceProperty: 'showStatusBar')

242

) {

243

actionPerformed { e ->

244

viewSettings.showStatusBar = e.source.selected

245

updateStatusBarVisibility(viewSettings.showStatusBar)

246

}

247

}

248

}

249

```

250

251

### Radio Button Menu Items

252

253

```groovy

254

def documentMode = new ValueHolder('edit')

255

256

swing.menu(text: 'Mode') {

257

def modeGroup = buttonGroup()

258

259

radioButtonMenuItem(

260

text: 'Edit Mode',

261

buttonGroup: modeGroup,

262

selected: bind(source: documentMode, sourceProperty: 'value',

263

converter: { it == 'edit' })

264

) {

265

actionPerformed {

266

documentMode.value = 'edit'

267

switchToEditMode()

268

}

269

}

270

271

radioButtonMenuItem(

272

text: 'Preview Mode',

273

buttonGroup: modeGroup,

274

selected: bind(source: documentMode, sourceProperty: 'value',

275

converter: { it == 'preview' })

276

) {

277

actionPerformed {

278

documentMode.value = 'preview'

279

switchToPreviewMode()

280

}

281

}

282

283

radioButtonMenuItem(

284

text: 'Presentation Mode',

285

buttonGroup: modeGroup,

286

selected: bind(source: documentMode, sourceProperty: 'value',

287

converter: { it == 'presentation' })

288

) {

289

actionPerformed {

290

documentMode.value = 'presentation'

291

switchToPresentationMode()

292

}

293

}

294

}

295

```

296

297

## Dynamic Menus

298

299

Creating menus that change based on application state.

300

301

### Recent Files Menu

302

303

```groovy

304

class RecentFilesManager {

305

List<String> recentFiles = []

306

int maxFiles = 5

307

308

void addFile(String filename) {

309

recentFiles.remove(filename) // Remove if already exists

310

recentFiles.add(0, filename) // Add to beginning

311

if (recentFiles.size() > maxFiles) {

312

recentFiles = recentFiles[0..<maxFiles]

313

}

314

}

315

}

316

317

def recentFilesManager = new RecentFilesManager()

318

319

def updateRecentFilesMenu = { menu ->

320

// Clear existing recent file items

321

menu.removeAll()

322

323

if (recentFilesManager.recentFiles.empty) {

324

def item = swing.menuItem(text: 'No recent files', enabled: false)

325

menu.add(item)

326

} else {

327

recentFilesManager.recentFiles.eachWithIndex { filename, index ->

328

def item = swing.menuItem(

329

text: "&${index + 1} ${new File(filename).name}",

330

toolTipText: filename

331

) {

332

actionPerformed {

333

openFile(filename)

334

}

335

}

336

menu.add(item)

337

}

338

}

339

}

340

341

swing.frame(title: 'Dynamic Menu Example') {

342

menuBar {

343

menu(text: 'File') {

344

menuItem(text: 'New') { actionPerformed { /* new file logic */ } }

345

menuItem(text: 'Open') {

346

actionPerformed {

347

def filename = showOpenDialog()

348

if (filename) {

349

openFile(filename)

350

recentFilesManager.addFile(filename)

351

updateRecentFilesMenu(recentFilesMenu)

352

}

353

}

354

}

355

separator()

356

357

// Recent files submenu

358

def recentFilesMenu = menu(text: 'Recent Files')

359

updateRecentFilesMenu(recentFilesMenu)

360

}

361

}

362

}

363

```

364

365

## Menu Styling and Icons

366

367

Customizing menu appearance with icons, fonts, and colors.

368

369

```groovy

370

swing.menuBar {

371

menu(text: 'File', font: new Font('Arial', Font.BOLD, 12)) {

372

menuItem(

373

text: 'New Document',

374

icon: swing.imageIcon('/icons/document-new.png'),

375

accelerator: swing.shortcut('N')

376

) {

377

actionPerformed { println 'New document' }

378

}

379

380

menuItem(

381

text: 'Open Document',

382

icon: swing.imageIcon('/icons/document-open.png'),

383

accelerator: swing.shortcut('O')

384

) {

385

actionPerformed { println 'Open document' }

386

}

387

388

separator()

389

390

menuItem(

391

text: 'Recent Documents',

392

icon: swing.imageIcon('/icons/document-recent.png')

393

) {

394

// Submenu with recent files

395

}

396

}

397

398

menu(text: 'Tools') {

399

menuItem(

400

text: 'Preferences',

401

icon: swing.imageIcon('/icons/preferences.png'),

402

foreground: Color.BLUE

403

) {

404

actionPerformed { showPreferences() }

405

}

406

}

407

}

408

```

409

410

## Keyboard Navigation

411

412

Setting up proper keyboard navigation and mnemonics.

413

414

```groovy

415

swing.menuBar {

416

menu(text: 'File', mnemonic: 'F') { // Alt+F to open

417

menuItem(

418

text: 'New',

419

mnemonic: 'N', // Alt+F, N to activate

420

accelerator: swing.shortcut('N') // Ctrl+N direct shortcut

421

)

422

menuItem(

423

text: 'Open Recent',

424

mnemonic: 'R'

425

) {

426

// Submenu

427

menuItem(text: 'Document 1.txt', mnemonic: '1')

428

menuItem(text: 'Document 2.txt', mnemonic: '2')

429

}

430

}

431

432

menu(text: 'Edit', mnemonic: 'E') { // Alt+E to open

433

menuItem(

434

text: 'Undo',

435

mnemonic: 'U',

436

accelerator: swing.shortcut('Z')

437

)

438

menuItem(

439

text: 'Redo',

440

mnemonic: 'R',

441

accelerator: swing.shortcut('Y')

442

)

443

}

444

}

445

```

446

447

## Menu State Management

448

449

Managing menu item states based on application context.

450

451

```groovy

452

class MenuStateManager {

453

boolean hasSelection = false

454

boolean hasContent = false

455

boolean canUndo = false

456

boolean canRedo = false

457

458

def cutAction, copyAction, pasteAction, undoAction, redoAction

459

460

void updateMenuStates() {

461

cutAction?.enabled = hasSelection

462

copyAction?.enabled = hasSelection

463

undoAction?.enabled = canUndo

464

redoAction?.enabled = canRedo

465

}

466

}

467

468

def stateManager = new MenuStateManager()

469

470

// Create actions with initial states

471

stateManager.cutAction = swing.action(

472

name: 'Cut',

473

enabled: false,

474

closure: { performCut() }

475

)

476

477

stateManager.copyAction = swing.action(

478

name: 'Copy',

479

enabled: false,

480

closure: { performCopy() }

481

)

482

483

// Update states based on events

484

textComponent.selectionListener = { e ->

485

stateManager.hasSelection = (e.source.selectedText != null)

486

stateManager.updateMenuStates()

487

}

488

489

// Use in menu

490

swing.menuBar {

491

menu(text: 'Edit') {

492

menuItem(action: stateManager.cutAction)

493

menuItem(action: stateManager.copyAction)

494

// ... other items

495

}

496

}

497

```