or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-transforms.mdcli.mdcore-language.mdindex.mdjson.mdsql.mdswing.mdtemplates.mdxml.md

swing.mddocs/

0

# Swing UI Building

1

2

Groovy provides powerful Swing integration through SwingBuilder, enabling declarative GUI construction with a fluent, builder-pattern API that simplifies desktop application development.

3

4

## SwingBuilder

5

6

### Core Builder Class

7

8

```groovy { .api }

9

class SwingBuilder extends FactoryBuilderSupport {

10

SwingBuilder()

11

SwingBuilder(boolean init)

12

13

Object invokeMethod(String name, Object args)

14

15

// Container methods

16

JFrame frame(Map attributes, Closure content)

17

JFrame frame(Closure content)

18

JDialog dialog(Map attributes, Closure content)

19

JPanel panel(Map attributes, Closure content)

20

JScrollPane scrollPane(Map attributes, Closure content)

21

JSplitPane splitPane(Map attributes, Closure content)

22

JTabbedPane tabbedPane(Map attributes, Closure content)

23

24

// Control methods

25

JButton button(Map attributes, Closure content)

26

JLabel label(Map attributes, Closure content)

27

JTextField textField(Map attributes)

28

JTextArea textArea(Map attributes)

29

JCheckBox checkBox(Map attributes)

30

JRadioButton radioButton(Map attributes)

31

JComboBox comboBox(Map attributes)

32

JList list(Map attributes)

33

JTable table(Map attributes)

34

JTree tree(Map attributes)

35

36

// Menu methods

37

JMenuBar menuBar(Map attributes, Closure content)

38

JMenu menu(Map attributes, Closure content)

39

JMenuItem menuItem(Map attributes, Closure content)

40

JPopupMenu popupMenu(Map attributes, Closure content)

41

42

// Layout methods

43

Object borderLayout(Map attributes)

44

Object flowLayout(Map attributes)

45

Object gridLayout(Map attributes)

46

Object gridBagLayout(Map attributes)

47

Object cardLayout(Map attributes)

48

Object boxLayout(Map attributes)

49

50

// Action methods

51

Action action(Map attributes, Closure closure)

52

void bind(Map attributes)

53

54

// Event handling

55

void edt(Closure closure)

56

void doLater(Closure closure)

57

void doOutside(Closure closure)

58

}

59

```

60

61

## Basic GUI Components

62

63

### Simple Window Creation

64

65

```groovy

66

import groovy.swing.SwingBuilder

67

import javax.swing.WindowConstants

68

69

def swing = new SwingBuilder()

70

71

def frame = swing.frame(

72

title: 'My Application',

73

size: [400, 300],

74

locationRelativeTo: null,

75

defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE

76

) {

77

panel {

78

label(text: 'Hello, Swing!')

79

button(text: 'Click Me', actionPerformed: {

80

println 'Button clicked!'

81

})

82

}

83

}

84

85

frame.setVisible(true)

86

```

87

88

### Layout Management

89

90

```groovy

91

import groovy.swing.SwingBuilder

92

import java.awt.BorderLayout

93

import java.awt.FlowLayout

94

import java.awt.GridLayout

95

96

def swing = new SwingBuilder()

97

98

def frame = swing.frame(title: 'Layout Examples', size: [500, 400]) {

99

// BorderLayout example

100

borderLayout()

101

102

panel(constraints: BorderLayout.NORTH) {

103

flowLayout()

104

label(text: 'North Panel')

105

button(text: 'Button 1')

106

button(text: 'Button 2')

107

}

108

109

panel(constraints: BorderLayout.CENTER) {

110

gridLayout(rows: 2, cols: 2, hgap: 5, vgap: 5)

111

button(text: 'Grid 1')

112

button(text: 'Grid 2')

113

button(text: 'Grid 3')

114

button(text: 'Grid 4')

115

}

116

117

panel(constraints: BorderLayout.SOUTH) {

118

flowLayout(alignment: FlowLayout.RIGHT)

119

button(text: 'OK')

120

button(text: 'Cancel')

121

}

122

}

123

124

frame.setVisible(true)

125

```

126

127

### Input Controls

128

129

```groovy

130

import groovy.swing.SwingBuilder

131

import javax.swing.border.TitledBorder

132

133

def swing = new SwingBuilder()

134

def model = [name: '', age: 0, subscribed: false, category: 'Bronze']

135

136

def frame = swing.frame(title: 'Input Form', size: [400, 300]) {

137

borderLayout()

138

139

panel(constraints: BorderLayout.CENTER, border: new TitledBorder('User Information')) {

140

gridBagLayout()

141

142

label(text: 'Name:', constraints: gbc(gridx: 0, gridy: 0, anchor: WEST))

143

textField(

144

columns: 20,

145

constraints: gbc(gridx: 1, gridy: 0, fill: HORIZONTAL),

146

text: bind(source: model, sourceProperty: 'name', mutual: true)

147

)

148

149

label(text: 'Age:', constraints: gbc(gridx: 0, gridy: 1, anchor: WEST))

150

spinner(

151

model: spinnerNumberModel(value: 18, minimum: 0, maximum: 120),

152

constraints: gbc(gridx: 1, gridy: 1),

153

stateChanged: { e -> model.age = e.source.value }

154

)

155

156

checkBox(

157

text: 'Subscribe to newsletter',

158

constraints: gbc(gridx: 0, gridy: 2, gridwidth: 2),

159

selected: bind(source: model, sourceProperty: 'subscribed', mutual: true)

160

)

161

162

label(text: 'Category:', constraints: gbc(gridx: 0, gridy: 3, anchor: WEST))

163

comboBox(

164

items: ['Bronze', 'Silver', 'Gold', 'Platinum'],

165

constraints: gbc(gridx: 1, gridy: 3),

166

selectedItem: bind(source: model, sourceProperty: 'category', mutual: true)

167

)

168

}

169

170

panel(constraints: BorderLayout.SOUTH) {

171

flowLayout()

172

button(text: 'Submit', actionPerformed: {

173

println "Name: ${model.name}"

174

println "Age: ${model.age}"

175

println "Subscribed: ${model.subscribed}"

176

println "Category: ${model.category}"

177

})

178

button(text: 'Reset', actionPerformed: {

179

model.name = ''

180

model.age = 18

181

model.subscribed = false

182

model.category = 'Bronze'

183

})

184

}

185

}

186

187

frame.setVisible(true)

188

```

189

190

## Advanced Components

191

192

### Table with Data

193

194

```groovy

195

import groovy.swing.SwingBuilder

196

import javax.swing.table.DefaultTableModel

197

198

def swing = new SwingBuilder()

199

200

// Sample data

201

def data = [

202

['John Doe', 30, 'Engineering', 75000],

203

['Jane Smith', 25, 'Marketing', 65000],

204

['Bob Johnson', 35, 'Sales', 70000],

205

['Alice Brown', 28, 'Engineering', 80000]

206

]

207

208

def columnNames = ['Name', 'Age', 'Department', 'Salary']

209

def tableModel = new DefaultTableModel(data as Object[][], columnNames as Object[])

210

211

def frame = swing.frame(title: 'Employee Table', size: [600, 400]) {

212

borderLayout()

213

214

scrollPane(constraints: BorderLayout.CENTER) {

215

table(

216

model: tableModel,

217

selectionMode: SINGLE_SELECTION,

218

mouseClicked: { e ->

219

if (e.clickCount == 2) {

220

def table = e.source

221

def row = table.selectedRow

222

if (row >= 0) {

223

def name = tableModel.getValueAt(row, 0)

224

swing.optionPane().showMessageDialog(

225

frame,

226

"Selected employee: $name",

227

'Selection',

228

swing.optionPane.INFORMATION_MESSAGE

229

)

230

}

231

}

232

}

233

)

234

}

235

236

panel(constraints: BorderLayout.SOUTH) {

237

flowLayout()

238

button(text: 'Add Employee', actionPerformed: {

239

def name = swing.optionPane().showInputDialog('Enter name:')

240

if (name) {

241

tableModel.addRow(['New Employee', 25, 'Department', 50000] as Object[])

242

}

243

})

244

button(text: 'Remove Selected', actionPerformed: {

245

def table = frame.contentPane.getComponent(0).viewport.view

246

def selectedRow = table.selectedRow

247

if (selectedRow >= 0) {

248

tableModel.removeRow(selectedRow)

249

}

250

})

251

}

252

}

253

254

frame.setVisible(true)

255

```

256

257

### Menu System

258

259

```groovy

260

import groovy.swing.SwingBuilder

261

import javax.swing.KeyStroke

262

import java.awt.event.KeyEvent

263

264

def swing = new SwingBuilder()

265

266

def frame = swing.frame(title: 'Menu Example', size: [500, 300]) {

267

menuBar {

268

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

269

menuItem(

270

text: 'New',

271

mnemonic: 'N',

272

accelerator: KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_MASK),

273

actionPerformed: { println 'New file' }

274

)

275

menuItem(

276

text: 'Open',

277

mnemonic: 'O',

278

accelerator: KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK),

279

actionPerformed: { println 'Open file' }

280

)

281

separator()

282

menuItem(

283

text: 'Exit',

284

mnemonic: 'x',

285

actionPerformed: { System.exit(0) }

286

)

287

}

288

289

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

290

menuItem(text: 'Cut', accelerator: KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK))

291

menuItem(text: 'Copy', accelerator: KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK))

292

menuItem(text: 'Paste', accelerator: KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_MASK))

293

}

294

295

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

296

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

297

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

298

separator()

299

300

// Radio button group

301

def group = buttonGroup()

302

radioButtonMenuItem(text: 'Small Icons', buttonGroup: group, selected: true)

303

radioButtonMenuItem(text: 'Large Icons', buttonGroup: group)

304

}

305

}

306

307

// Main content area

308

textArea(text: 'Main content area...', editable: false)

309

}

310

311

frame.setVisible(true)

312

```

313

314

## Data Binding

315

316

### Automatic Data Binding

317

318

```groovy

319

import groovy.swing.SwingBuilder

320

import groovy.beans.Bindable

321

322

class Person {

323

@Bindable String firstName = ''

324

@Bindable String lastName = ''

325

@Bindable int age = 0

326

@Bindable boolean employed = false

327

328

String getFullName() {

329

return "$firstName $lastName".trim()

330

}

331

}

332

333

def swing = new SwingBuilder()

334

def person = new Person()

335

336

def frame = swing.frame(title: 'Data Binding Example', size: [400, 250]) {

337

gridBagLayout()

338

339

label(text: 'First Name:', constraints: gbc(gridx: 0, gridy: 0, anchor: WEST))

340

textField(

341

columns: 15,

342

constraints: gbc(gridx: 1, gridy: 0, fill: HORIZONTAL),

343

text: bind(source: person, sourceProperty: 'firstName', mutual: true)

344

)

345

346

label(text: 'Last Name:', constraints: gbc(gridx: 0, gridy: 1, anchor: WEST))

347

textField(

348

columns: 15,

349

constraints: gbc(gridx: 1, gridy: 1, fill: HORIZONTAL),

350

text: bind(source: person, sourceProperty: 'lastName', mutual: true)

351

)

352

353

label(text: 'Age:', constraints: gbc(gridx: 0, gridy: 2, anchor: WEST))

354

spinner(

355

model: spinnerNumberModel(minimum: 0, maximum: 120),

356

constraints: gbc(gridx: 1, gridy: 2),

357

value: bind(source: person, sourceProperty: 'age', mutual: true)

358

)

359

360

checkBox(

361

text: 'Employed',

362

constraints: gbc(gridx: 0, gridy: 3, gridwidth: 2),

363

selected: bind(source: person, sourceProperty: 'employed', mutual: true)

364

)

365

366

separator(constraints: gbc(gridx: 0, gridy: 4, gridwidth: 2, fill: HORIZONTAL))

367

368

label(

369

text: bind(source: person, sourceProperty: 'fullName'),

370

constraints: gbc(gridx: 0, gridy: 5, gridwidth: 2, anchor: CENTER),

371

font: label().font.deriveFont(16f)

372

)

373

374

button(

375

text: 'Print Info',

376

constraints: gbc(gridx: 0, gridy: 6, gridwidth: 2),

377

actionPerformed: {

378

println "Person: ${person.fullName}, Age: ${person.age}, Employed: ${person.employed}"

379

}

380

)

381

}

382

383

frame.setVisible(true)

384

```

385

386

## Custom Components

387

388

### Custom Panel Component

389

390

```groovy

391

import groovy.swing.SwingBuilder

392

import javax.swing.JPanel

393

import java.awt.Graphics

394

import java.awt.Color

395

396

class DrawingPanel extends JPanel {

397

private List<Point> points = []

398

399

DrawingPanel() {

400

background = Color.WHITE

401

addMouseListener([

402

mouseClicked: { e ->

403

points.add(new Point(e.x, e.y))

404

repaint()

405

}

406

] as java.awt.event.MouseAdapter)

407

}

408

409

@Override

410

protected void paintComponent(Graphics g) {

411

super.paintComponent(g)

412

g.color = Color.BLUE

413

points.each { point ->

414

g.fillOval(point.x - 3, point.y - 3, 6, 6)

415

}

416

}

417

418

void clearPoints() {

419

points.clear()

420

repaint()

421

}

422

}

423

424

def swing = new SwingBuilder()

425

426

def drawingPanel = new DrawingPanel()

427

428

def frame = swing.frame(title: 'Custom Drawing Panel', size: [500, 400]) {

429

borderLayout()

430

431

widget(drawingPanel, constraints: BorderLayout.CENTER)

432

433

panel(constraints: BorderLayout.SOUTH) {

434

flowLayout()

435

button(text: 'Clear', actionPerformed: {

436

drawingPanel.clearPoints()

437

})

438

button(text: 'Count Points', actionPerformed: {

439

swing.optionPane().showMessageDialog(

440

frame,

441

"Points drawn: ${drawingPanel.points.size()}",

442

'Point Count',

443

swing.optionPane.INFORMATION_MESSAGE

444

)

445

})

446

}

447

}

448

449

frame.setVisible(true)

450

```

451

452

## Threading and EDT

453

454

### Event Dispatch Thread Management

455

456

```groovy

457

import groovy.swing.SwingBuilder

458

import javax.swing.SwingUtilities

459

import java.util.concurrent.Executors

460

461

def swing = new SwingBuilder()

462

463

def frame = swing.frame(title: 'Threading Example', size: [400, 200]) {

464

borderLayout()

465

466

def progressBar = progressBar(

467

minimum: 0,

468

maximum: 100,

469

value: 0,

470

stringPainted: true,

471

constraints: BorderLayout.CENTER

472

)

473

474

panel(constraints: BorderLayout.SOUTH) {

475

flowLayout()

476

477

button(text: 'Start Task', actionPerformed: {

478

// Run long task in background thread

479

swing.doOutside {

480

(1..100).each { i ->

481

Thread.sleep(50) // Simulate work

482

483

// Update UI on EDT

484

swing.edt {

485

progressBar.value = i

486

progressBar.string = "Processing ${i}%"

487

}

488

}

489

490

// Final update on EDT

491

swing.edt {

492

progressBar.string = "Complete!"

493

swing.optionPane().showMessageDialog(

494

frame,

495

'Task completed successfully!',

496

'Success',

497

swing.optionPane.INFORMATION_MESSAGE

498

)

499

}

500

}

501

})

502

503

button(text: 'Reset', actionPerformed: {

504

progressBar.value = 0

505

progressBar.string = null

506

})

507

}

508

}

509

510

frame.setVisible(true)

511

```

512

513

### Timer-based Updates

514

515

```groovy

516

import groovy.swing.SwingBuilder

517

import javax.swing.Timer

518

import java.text.SimpleDateFormat

519

520

def swing = new SwingBuilder()

521

def dateFormat = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss')

522

523

def frame = swing.frame(title: 'Clock Example', size: [300, 100]) {

524

borderLayout()

525

526

def timeLabel = label(

527

text: dateFormat.format(new Date()),

528

constraints: BorderLayout.CENTER,

529

horizontalAlignment: swing.label.CENTER,

530

font: label().font.deriveFont(18f)

531

)

532

533

// Update every second

534

def timer = new Timer(1000) { e ->

535

timeLabel.text = dateFormat.format(new Date())

536

}

537

timer.start()

538

539

// Stop timer when window closes

540

addWindowListener([

541

windowClosing: { e -> timer.stop() }

542

] as java.awt.event.WindowAdapter)

543

}

544

545

frame.setVisible(true)

546

```

547

548

## Styling and Look & Feel

549

550

### Custom Look and Feel

551

552

```groovy

553

import groovy.swing.SwingBuilder

554

import javax.swing.UIManager

555

import javax.swing.plaf.nimbus.NimbusLookAndFeel

556

557

// Set look and feel

558

try {

559

UIManager.setLookAndFeel(new NimbusLookAndFeel())

560

} catch (Exception e) {

561

println "Could not set Nimbus L&F: ${e.message}"

562

}

563

564

def swing = new SwingBuilder()

565

566

def frame = swing.frame(title: 'Styled Application', size: [400, 300]) {

567

borderLayout()

568

569

panel(constraints: BorderLayout.NORTH, background: java.awt.Color.LIGHT_GRAY) {

570

flowLayout()

571

label(text: 'Styled Header', font: label().font.deriveFont(16f))

572

}

573

574

tabbedPane(constraints: BorderLayout.CENTER) {

575

panel(name: 'Tab 1') {

576

gridLayout(rows: 3, cols: 2, hgap: 10, vgap: 10)

577

label(text: 'Name:')

578

textField(columns: 15)

579

label(text: 'Email:')

580

textField(columns: 15)

581

label(text: 'Notes:')

582

scrollPane {

583

textArea(rows: 3, columns: 15)

584

}

585

}

586

587

panel(name: 'Tab 2') {

588

boxLayout(axis: swing.boxLayout.Y_AXIS)

589

checkBox(text: 'Option 1')

590

checkBox(text: 'Option 2')

591

checkBox(text: 'Option 3')

592

separator()

593

radioButton(text: 'Choice A')

594

radioButton(text: 'Choice B')

595

}

596

}

597

598

panel(constraints: BorderLayout.SOUTH) {

599

flowLayout()

600

button(text: 'OK', preferredSize: [80, 30])

601

button(text: 'Cancel', preferredSize: [80, 30])

602

button(text: 'Apply', preferredSize: [80, 30])

603

}

604

}

605

606

frame.setVisible(true)

607

```

608

609

This comprehensive documentation covers all the major aspects of Groovy's Swing integration, from basic components to advanced features like data binding, custom components, and threading. The SwingBuilder provides a powerful and expressive way to create desktop applications with minimal boilerplate code.