0
# Look and Feel Management
1
2
Simplified Look and Feel management with support for system LAFs and third-party themes, providing easy access to platform-specific appearance and custom styling.
3
4
## Capabilities
5
6
### LookAndFeelHelper
7
8
The central helper class for managing Look and Feel configuration with built-in support for popular LAFs.
9
10
```groovy { .api }
11
/**
12
* Singleton helper for Look and Feel management
13
*/
14
class LookAndFeelHelper {
15
/** Get singleton instance */
16
static LookAndFeelHelper getInstance()
17
18
/** Configure Look and Feel with attributes and initialization code */
19
LookAndFeel lookAndFeel(Object value, Map attributes = [:], Closure initClosure = null)
20
21
/** Register alias for Look and Feel class name */
22
String addLookAndFeelAlias(String alias, String className)
23
24
/** Add custom attribute handler for specific LAF */
25
String addLookAndFeelAttributeHandler(String className, String attr, Closure handler)
26
27
/** Check if this is a leaf node in builder pattern */
28
boolean isLeaf()
29
}
30
```
31
32
### Built-in Look and Feel Aliases
33
34
Pre-configured aliases for common Look and Feel implementations.
35
36
```groovy { .api }
37
// System Look and Feels
38
'system' // UIManager.getSystemLookAndFeelClassName()
39
'crossPlatform' // UIManager.getCrossPlatformLookAndFeelClassName()
40
41
// Platform-specific LAFs
42
'metal' // javax.swing.plaf.metal.MetalLookAndFeel
43
'nimbus' // com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel (if available)
44
'windows' // com.sun.java.swing.plaf.windows.WindowsLookAndFeel
45
'win2k' // com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel
46
'mac' // com.apple.laf.AquaLookAndFeel (if available)
47
'motif' // com.sun.java.swing.plaf.motif.MotifLookAndFeel
48
'gtk' // com.sun.java.swing.plaf.gtk.GTKLookAndFeel
49
'synth' // javax.swing.plaf.synth.SynthLookAndFeel
50
51
// Third-party LAFs (requires external libraries)
52
'plastic' // com.jgoodies.looks.plastic.PlasticLookAndFeel
53
'plastic3D' // com.jgoodies.looks.plastic.Plastic3DLookAndFeel
54
'plasticXP' // com.jgoodies.looks.plastic.PlasticXPLookAndFeel
55
'substance' // org.pushingpixels.substance.api.SubstanceLookAndFeel
56
'napkin' // net.sourceforge.napkinlaf.NapkinLookAndFeel
57
```
58
59
**Usage Examples:**
60
61
```groovy
62
import groovy.swing.SwingBuilder
63
64
// Set system Look and Feel
65
SwingBuilder.lookAndFeel('system')
66
67
// Try multiple LAFs in fallback order
68
SwingBuilder.lookAndFeel('nimbus', 'system', 'metal')
69
70
// Set LAF with configuration
71
SwingBuilder.lookAndFeel('metal', [
72
theme: 'ocean',
73
boldFonts: false
74
])
75
76
// Use LAF with initialization closure
77
SwingBuilder.lookAndFeel('nimbus') { laf ->
78
// Custom initialization code
79
UIManager.put('control', new Color(240, 240, 240))
80
}
81
```
82
83
### SwingBuilder LAF Integration
84
85
Look and Feel methods integrated into SwingBuilder for convenient usage.
86
87
```groovy { .api }
88
/**
89
* SwingBuilder static methods for LAF management
90
*/
91
class SwingBuilder {
92
/** Configure LAF with single parameter */
93
static LookAndFeel lookAndFeel(Object laf)
94
95
/** Configure LAF with initialization closure */
96
static LookAndFeel lookAndFeel(Object laf, Closure initCode)
97
98
/** Configure LAF with attributes and optional closure */
99
static LookAndFeel lookAndFeel(Map attributes = [:], Object laf = null, Closure initCode = null)
100
101
/** Try multiple LAFs in order until one succeeds */
102
static LookAndFeel lookAndFeel(Object... lafs)
103
}
104
```
105
106
**Usage Examples:**
107
108
```groovy
109
// Simple LAF setting
110
SwingBuilder.lookAndFeel('nimbus')
111
112
// LAF with initialization
113
SwingBuilder.lookAndFeel('metal') { laf ->
114
MetalLookAndFeel.setCurrentTheme(new OceanTheme())
115
}
116
117
// LAF with attributes
118
SwingBuilder.lookAndFeel([theme: 'steel'], 'metal')
119
120
// Fallback LAF selection
121
SwingBuilder.lookAndFeel('substance', 'nimbus', 'system')
122
```
123
124
### Metal Look and Feel Customization
125
126
Special support for Metal LAF themes and configuration.
127
128
```groovy { .api }
129
// Metal LAF extended attributes
130
[
131
theme: 'ocean' | 'steel' | MetalTheme, // Predefined or custom theme
132
boldFonts: boolean, // Enable/disable bold fonts
133
noxp: boolean // Disable XP styling
134
]
135
```
136
137
**Usage Examples:**
138
139
```groovy
140
// Ocean theme with bold fonts disabled
141
SwingBuilder.lookAndFeel('metal', [
142
theme: 'ocean',
143
boldFonts: false
144
])
145
146
// Steel theme (classic Metal)
147
SwingBuilder.lookAndFeel('metal', [theme: 'steel'])
148
149
// Custom Metal theme
150
import javax.swing.plaf.metal.*
151
152
class CustomMetalTheme extends DefaultMetalTheme {
153
String getName() { 'Custom Theme' }
154
ColorUIResource getPrimary1() { new ColorUIResource(66, 33, 66) }
155
}
156
157
SwingBuilder.lookAndFeel('metal', [theme: new CustomMetalTheme()])
158
```
159
160
### Substance Look and Feel Integration
161
162
Support for Substance LAF skins and themes (requires external library).
163
164
```groovy { .api }
165
// Substance LAF extended attributes
166
[
167
theme: Object, // Substance theme object
168
skin: Object, // Substance skin object
169
watermark: Object // Substance watermark object
170
]
171
```
172
173
**Usage Examples:**
174
175
```groovy
176
// Substance with skin (requires Substance library)
177
try {
178
SwingBuilder.lookAndFeel('substance', [
179
skin: 'org.pushingpixels.substance.api.skin.BusinessSkin'
180
])
181
} catch (Exception e) {
182
// Fallback to system LAF
183
SwingBuilder.lookAndFeel('system')
184
}
185
```
186
187
### Custom Look and Feel Registration
188
189
Methods for registering custom LAF aliases and attribute handlers.
190
191
```groovy { .api }
192
/**
193
* Register custom LAF alias
194
*/
195
String addLookAndFeelAlias(String alias, String className)
196
197
/**
198
* Add custom attribute handler for specific LAF
199
*/
200
String addLookAndFeelAttributeHandler(String className, String attr, Closure handler)
201
```
202
203
**Usage Examples:**
204
205
```groovy
206
def helper = LookAndFeelHelper.getInstance()
207
208
// Register custom LAF alias
209
helper.addLookAndFeelAlias('myLaf', 'com.example.MyLookAndFeel')
210
211
// Add custom attribute handler
212
helper.addLookAndFeelAttributeHandler(
213
'com.example.MyLookAndFeel',
214
'customProperty'
215
) { laf, value ->
216
laf.setCustomProperty(value)
217
}
218
219
// Use custom LAF
220
SwingBuilder.lookAndFeel('myLaf', [customProperty: 'value'])
221
```
222
223
### LAF Utilities and Helpers
224
225
Utility methods for LAF detection and management.
226
227
```groovy { .api }
228
/**
229
* Static utility methods for LAF detection
230
*/
231
class LookAndFeelHelper {
232
/** Get Nimbus LAF class name if available */
233
static String getNimbusLAFName()
234
235
/** Get Aqua LAF class name if available (Mac) */
236
static String getAquaLAFName()
237
238
/** Get Substance LAF class name if available */
239
static String getSubstanceLAFName()
240
}
241
242
// UIManager utilities
243
UIManager.getSystemLookAndFeelClassName()
244
UIManager.getCrossPlatformLookAndFeelClassName()
245
UIManager.getInstalledLookAndFeels()
246
UIManager.getLookAndFeel()
247
```
248
249
**Usage Examples:**
250
251
```groovy
252
// Check available LAFs
253
def installedLafs = UIManager.getInstalledLookAndFeels()
254
println "Available LAFs:"
255
installedLafs.each { lafInfo ->
256
println " ${lafInfo.name}: ${lafInfo.className}"
257
}
258
259
// Conditional LAF selection based on platform
260
def platformLaf = System.getProperty('os.name').toLowerCase().contains('mac') ? 'mac' : 'system'
261
SwingBuilder.lookAndFeel(platformLaf)
262
263
// Get current LAF information
264
def currentLaf = UIManager.getLookAndFeel()
265
println "Current LAF: ${currentLaf.name} (${currentLaf.class.name})"
266
```
267
268
### Application Integration
269
270
Best practices for integrating LAF management into applications.
271
272
```groovy { .api }
273
// Application startup LAF configuration
274
class Application {
275
static void initializeLookAndFeel() {
276
// Set LAF before creating any Swing components
277
SwingBuilder.lookAndFeel('nimbus', 'system')
278
279
// Configure global UI properties
280
UIManager.put('OptionPane.messageFont', new Font('Dialog', Font.PLAIN, 12))
281
UIManager.put('OptionPane.buttonFont', new Font('Dialog', Font.PLAIN, 12))
282
}
283
284
static void main(String[] args) {
285
SwingUtilities.invokeLater {
286
initializeLookAndFeel()
287
createAndShowGUI()
288
}
289
}
290
}
291
```
292
293
**Usage Examples:**
294
295
```groovy
296
// Complete application LAF setup
297
import groovy.swing.SwingBuilder
298
import javax.swing.*
299
300
class MyApplication {
301
static void main(String[] args) {
302
// Initialize LAF early
303
SwingUtilities.invokeLater {
304
// Try preferred LAFs with fallback
305
SwingBuilder.lookAndFeel('nimbus', 'system', 'metal')
306
307
// Create main GUI
308
def swing = new SwingBuilder()
309
def frame = swing.frame(
310
title: 'My Application',
311
defaultCloseOperation: JFrame.EXIT_ON_CLOSE,
312
size: [800, 600]
313
) {
314
menuBar {
315
menu(text: 'View') {
316
menu(text: 'Look and Feel') {
317
UIManager.installedLookAndFeels.each { lafInfo ->
318
menuItem(text: lafInfo.name) {
319
actionPerformed { e ->
320
try {
321
UIManager.setLookAndFeel(lafInfo.className)
322
SwingUtilities.updateComponentTreeUI(frame)
323
} catch (Exception ex) {
324
JOptionPane.showMessageDialog(frame,
325
"Failed to set LAF: ${ex.message}")
326
}
327
}
328
}
329
}
330
}
331
}
332
}
333
panel {
334
// main content
335
}
336
}
337
frame.visible = true
338
}
339
}
340
}
341
```
342
343
### Error Handling
344
345
Proper error handling for LAF operations.
346
347
```groovy { .api }
348
// LAF setting with error handling
349
try {
350
SwingBuilder.lookAndFeel('preferredLaf')
351
} catch (UnsupportedLookAndFeelException e) {
352
println "LAF not supported: ${e.message}"
353
SwingBuilder.lookAndFeel('system') // fallback
354
} catch (ClassNotFoundException e) {
355
println "LAF class not found: ${e.message}"
356
SwingBuilder.lookAndFeel('metal') // fallback
357
} catch (Exception e) {
358
println "LAF error: ${e.message}"
359
// Keep current LAF
360
}
361
```
362
363
**Usage Examples:**
364
365
```groovy
366
// Robust LAF selection with logging
367
def selectLookAndFeel() {
368
def candidates = ['nimbus', 'system', 'metal']
369
370
for (laf in candidates) {
371
try {
372
SwingBuilder.lookAndFeel(laf)
373
println "Successfully set LAF: $laf"
374
return
375
} catch (Exception e) {
376
println "Failed to set LAF $laf: ${e.message}"
377
}
378
}
379
380
println "Warning: Using default LAF"
381
}
382
383
// Dynamic LAF switching in running application
384
def switchLookAndFeel(String lafName, Component rootComponent) {
385
try {
386
def oldLaf = UIManager.getLookAndFeel()
387
SwingBuilder.lookAndFeel(lafName)
388
SwingUtilities.updateComponentTreeUI(rootComponent)
389
println "Switched from ${oldLaf.name} to ${UIManager.getLookAndFeel().name}"
390
} catch (Exception e) {
391
JOptionPane.showMessageDialog(rootComponent,
392
"Could not switch to $lafName: ${e.message}",
393
'Look and Feel Error',
394
JOptionPane.ERROR_MESSAGE)
395
}
396
}
397
```