72
71
* This example creates a panel with 3 columns and 3 rows.
74
73
* FormLayout layout = new FormLayout(
75
* "right:pref, 6dlu, 50dlu, 4dlu, default", // columns
76
* "pref, 3dlu, pref, 3dlu, pref"); // rows
74
* "pref, $lcgap, 50dlu, $rgap, default", // columns
75
* "pref, $lg, pref, $lg, pref"); // rows
78
77
* PanelBuilder builder = new PanelBuilder(layout);
79
78
* CellConstraints cc = new CellConstraints();
80
* builder.addLabel("&Title", cc.xy (1, 1));
81
* builder.add(new JTextField(), cc.xywh(3, 1, 3, 1));
82
* builder.addLabel("&Price", cc.xy (1, 3));
83
* builder.add(new JTextField(), cc.xy (3, 3));
84
* builder.addLabel("&Author", cc.xy (1, 5));
85
* builder.add(new JTextField(), cc.xy (3, 5));
86
* builder.add(new JButton("..."), cc.xy (5, 5));
79
* builder.addLabel("&Title:", cc.xy (1, 1));
80
* builder.add(new JTextField(), cc.xywh(3, 1, 3, 1));
81
* builder.addLabel("&Price:", cc.xy (1, 3));
82
* builder.add(new JTextField(), cc.xy (3, 3));
83
* builder.addLabel("&Author:", cc.xy (1, 5));
84
* builder.add(new JTextField(), cc.xy (3, 5));
85
* builder.add(new JButton("\u2026"), cc.xy (5, 5));
87
86
* return builder.getPanel();
90
89
* @author Karsten Lentzsch
91
* @version $Revision: 1.7 $
90
* @version $Revision: 1.15 $
93
92
* @see com.jgoodies.forms.factories.ComponentFactory
94
93
* @see I15dPanelBuilder
126
170
public PanelBuilder(FormLayout layout, JPanel panel){
127
171
super(layout, panel);
131
// Accessors ************************************************************
172
labelForFeatureEnabled = labelForFeatureEnabledDefault;
176
// Global Defaults ********************************************************
179
* Returns the global default for the enablement of the setLabelFor feature.
180
* This can be overridden per PanelBuilder using
181
* {@link #setLabelForFeatureEnabled(boolean)}.
182
* The feature is globally disabled by default.
184
* @return true for globally enabled, false for globally disabled
186
public static boolean getLabelForFeatureEnabledDefault() {
187
return labelForFeatureEnabledDefault;
192
* Sets the default value for the setLabelFor feature enablement.
193
* This can be overridden per PanelBuilder using
194
* {@link #setLabelForFeatureEnabled(boolean)}.
195
* The default value is used to set the initial PanelBuilder
196
* setting for this feature.
197
* The feature is globally disabled by default.
199
* @param b true for globally enabled, false for globally disabled
201
public static void setLabelForFeatureEnabledDefault(boolean b) {
202
labelForFeatureEnabledDefault = b;
206
// Configuration **********************************************************
209
* Returns whether the setLabelFor feature is enabled for this PanelBuilder.
210
* The value is initialized from the global default value for this feature
211
* {@link #getLabelForFeatureEnabledDefault()}. It is globally disabled
214
* @return true for enabled, false for disabled
216
public boolean isLabelForFeatureEnabled() {
217
return labelForFeatureEnabled;
222
* Enables or disables the setLabelFor feature for this PanelBuilder.
223
* The value is initialized from the global default value
224
* {@link #getLabelForFeatureEnabledDefault()}. It is globally disabled
227
* @param b true for enabled, false for disabled
229
public void setLabelForFeatureEnabled(boolean b) {
230
labelForFeatureEnabled = b;
234
// Accessors **************************************************************
134
237
* Returns the panel used to build the form.
264
// Adding Label with related Component ************************************
267
* Adds a label and component to the panel using the given cell constraints.
268
* Sets the given label as <i>the</i> component label using
269
* {@link JLabel#setLabelFor(java.awt.Component)}.<p>
271
* <strong>Note:</strong> The {@link CellConstraints} objects for the label
272
* and the component must be different. Cell constraints are implicitly
273
* cloned by the <code>FormLayout</code> when added to the container.
274
* However, in this case you may be tempted to reuse a
275
* <code>CellConstraints</code> object in the same way as with many other
276
* builder methods that require a single <code>CellConstraints</code>
278
* The pitfall is that the methods <code>CellConstraints.xy*(...)</code>
279
* just set the coordinates but do <em>not</em> create a new instance.
280
* And so the second invocation of <code>xy*(...)</code> overrides
281
* the settings performed in the first invocation before the object
282
* is cloned by the <code>FormLayout</code>.<p>
284
* <strong>Wrong:</strong><pre>
285
* CellConstraints cc = new CellConstraints();
288
* cc.xy(1, 7), // will be modified by the code below
290
* cc.xy(3, 7) // sets the single instance to (3, 7)
293
* <strong>Correct:</strong><pre>
294
* // Using a single CellConstraints instance and cloning
295
* CellConstraints cc = new CellConstraints();
298
* (CellConstraints) cc.xy(1, 7).clone(), // cloned before the next modification
300
* cc.xy(3, 7) // sets this instance to (3, 7)
303
* // Using two CellConstraints instances
304
* CellConstraints cc1 = new CellConstraints();
305
* CellConstraints cc2 = new CellConstraints();
308
* cc1.xy(1, 7), // sets instance 1 to (1, 7)
310
* cc2.xy(3, 7) // sets instance 2 to (3, 7)
314
* @param label the label to add
315
* @param labelConstraints the label's cell constraints
316
* @param component the component to add
317
* @param componentConstraints the component's cell constraints
318
* @return the added label
319
* @throws IllegalArgumentException if the same cell constraints instance
320
* is used for the label and the component
322
* @see JLabel#setLabelFor(java.awt.Component)
323
* @see DefaultFormBuilder
325
public final JLabel add(JLabel label, CellConstraints labelConstraints,
326
Component component, CellConstraints componentConstraints) {
327
if (labelConstraints == componentConstraints)
328
throw new IllegalArgumentException(
329
"You must provide two CellConstraints instances, " +
330
"one for the label and one for the component.\n" +
331
"Consider using #clone(). See the JavaDocs for details.");
333
add(label, labelConstraints);
334
add(component, componentConstraints);
335
label.setLabelFor(component);
341
368
* Adds a label and component to the panel using the given cell constraints.
342
369
* Sets the given label as <i>the</i> component label using
444
// Adding Labels for Read-Only Components ---------------------------------
447
* Adds a textual label intended for labeling read-only components
448
* to the form using the default constraints.<p>
451
* addROLabel("Name:"); // No Mnemonic
452
* addROLabel("N&ame:"); // Mnemonic is 'a'
453
* addROLabel("Save &as:"); // Mnemonic is the second 'a'
454
* addROLabel("Look&&Feel:"); // No mnemonic, text is "look&feel"
457
* @param textWithMnemonic the label's text -
458
* may contain an ampersand (<tt>&</tt>) to mark a mnemonic
459
* @return the new label
461
* @see ComponentFactory2
465
public final JLabel addROLabel(String textWithMnemonic) {
466
return addROLabel(textWithMnemonic, cellConstraints());
471
* Adds a textual label intended for labeling read-only components
472
* to the form using the specified constraints.<p>
475
* addROLabel("Name:", cc.xy(1, 1)); // No Mnemonic
476
* addROLabel("N&ame:", cc.xy(1, 1)); // Mnemonic is 'a'
477
* addROLabel("Save &as:", cc.xy(1, 1)); // Mnemonic is the second 'a'
478
* addROLabel("Look&&Feel:", cc.xy(1, 1)); // No mnemonic, text is "look&feel"
481
* @param textWithMnemonic the label's text -
482
* may contain an ampersand (<tt>&</tt>) to mark a mnemonic
483
* @param constraints the label's cell constraints
484
* @return the new label
486
* @see ComponentFactory2
490
public final JLabel addROLabel(String textWithMnemonic, CellConstraints constraints) {
491
ComponentFactory factory = getComponentFactory();
492
ComponentFactory2 factory2;
493
if (factory instanceof ComponentFactory2) {
494
factory2 = (ComponentFactory2) factory;
496
factory2 = DefaultComponentFactory.getInstance();
498
JLabel label = factory2.createReadOnlyLabel(textWithMnemonic);
499
add(label, constraints);
505
* Adds a textual label intended for labeling read-only components
506
* to the form using the specified constraints.<p>
509
* addROLabel("Name:", "1, 1"); // No Mnemonic
510
* addROLabel("N&ame:", "1, 1"); // Mnemonic is 'a'
511
* addROLabel("Save &as:", "1, 1"); // Mnemonic is the second 'a'
512
* addROLabel("Look&&Feel:", "1, 1"); // No mnemonic, text is "look&feel"
515
* @param textWithMnemonic the label's text -
516
* may contain an ampersand (<tt>&</tt>) to mark a mnemonic
517
* @param encodedConstraints a string representation for the constraints
518
* @return the new label
520
* @see ComponentFactory2
524
public final JLabel addROLabel(String textWithMnemonic, String encodedConstraints) {
525
return addROLabel(textWithMnemonic, new CellConstraints(encodedConstraints));
530
* Adds a label and component to the panel using the given cell constraints.
531
* Sets the given label as <i>the</i> component label using
532
* {@link JLabel#setLabelFor(java.awt.Component)}.<p>
534
* <strong>Note:</strong> The {@link CellConstraints} objects for the label
535
* and the component must be different. Cell constraints are implicitly
536
* cloned by the FormLayout when added to the container.
537
* However, in this case you may be tempted to reuse a
538
* <code>CellConstraints</code> object in the same way as with many other
539
* builder methods that require a single <code>CellConstraints</code>
541
* The pitfall is that the methods <code>CellConstraints.xy*(...)</code>
542
* just set the coordinates but do <em>not</em> create a new instance.
543
* And so the second invocation of <code>xy*(...)</code> overrides
544
* the settings performed in the first invocation before the object
545
* is cloned by the <code>FormLayout</code>.<p>
547
* <strong>Wrong:</strong><pre>
548
* builder.addROLabel(
549
* "&Name:", // Mnemonic is 'N'
550
* cc.xy(1, 7), // will be modified by the code below
552
* cc.xy(3, 7) // sets the single instance to (3, 7)
555
* <strong>Correct:</strong><pre>
556
* // Using a single CellConstraints instance and cloning
557
* CellConstraints cc = new CellConstraints();
558
* builder.addROLabel(
560
* (CellConstraints) cc.xy(1, 7).clone(), // cloned before the next modification
562
* cc.xy(3, 7) // sets this instance to (3, 7)
565
* // Using two CellConstraints instances
566
* CellConstraints cc1 = new CellConstraints();
567
* CellConstraints cc2 = new CellConstraints();
568
* builder.addROLabel(
569
* "&Name:", // Mnemonic is 'N'
570
* cc1.xy(1, 7), // sets instance 1 to (1, 7)
572
* cc2.xy(3, 7) // sets instance 2 to (3, 7)
576
* @param textWithMnemonic the label's text -
577
* may contain an ampersand (<tt>&</tt>) to mark a mnemonic
578
* @param labelConstraints the label's cell constraints
579
* @param component the component to add
580
* @param componentConstraints the component's cell constraints
581
* @return the added label
582
* @throws IllegalArgumentException if the same cell constraints instance
583
* is used for the label and the component
585
* @see JLabel#setLabelFor(java.awt.Component)
586
* @see ComponentFactory2
587
* @see DefaultFormBuilder
591
public final JLabel addROLabel(
592
String textWithMnemonic, CellConstraints labelConstraints,
593
Component component, CellConstraints componentConstraints) {
595
if (labelConstraints == componentConstraints)
596
throw new IllegalArgumentException(
597
"You must provide two CellConstraints instances, " +
598
"one for the label and one for the component.\n" +
599
"Consider using #clone(). See the JavaDocs for details.");
601
JLabel label = addROLabel(textWithMnemonic, labelConstraints);
602
add(component, componentConstraints);
603
label.setLabelFor(component);
417
609
// Adding Titles ----------------------------------------------------------
766
* Adds a label and component to the panel using the given cell constraints.
767
* Sets the given label as <i>the</i> component label using
768
* {@link JLabel#setLabelFor(java.awt.Component)}.<p>
770
* <strong>Note:</strong> The {@link CellConstraints} objects for the label
771
* and the component must be different. Cell constraints are implicitly
772
* cloned by the <code>FormLayout</code> when added to the container.
773
* However, in this case you may be tempted to reuse a
774
* <code>CellConstraints</code> object in the same way as with many other
775
* builder methods that require a single <code>CellConstraints</code>
777
* The pitfall is that the methods <code>CellConstraints.xy*(...)</code>
778
* just set the coordinates but do <em>not</em> create a new instance.
779
* And so the second invocation of <code>xy*(...)</code> overrides
780
* the settings performed in the first invocation before the object
781
* is cloned by the <code>FormLayout</code>.<p>
783
* <strong>Wrong:</strong><pre>
784
* CellConstraints cc = new CellConstraints();
787
* cc.xy(1, 7), // will be modified by the code below
789
* cc.xy(3, 7) // sets the single instance to (3, 7)
792
* <strong>Correct:</strong><pre>
793
* // Using a single CellConstraints instance and cloning
794
* CellConstraints cc = new CellConstraints();
797
* (CellConstraints) cc.xy(1, 7).clone(), // cloned before the next modification
799
* cc.xy(3, 7) // sets this instance to (3, 7)
802
* // Using two CellConstraints instances
803
* CellConstraints cc1 = new CellConstraints();
804
* CellConstraints cc2 = new CellConstraints();
807
* cc1.xy(1, 7), // sets instance 1 to (1, 7)
809
* cc2.xy(3, 7) // sets instance 2 to (3, 7)
813
* @param label the label to add
814
* @param labelConstraints the label's cell constraints
815
* @param component the component to add
816
* @param componentConstraints the component's cell constraints
817
* @return the added label
818
* @throws IllegalArgumentException if the same cell constraints instance
819
* is used for the label and the component
821
* @see JLabel#setLabelFor(java.awt.Component)
822
* @see DefaultFormBuilder
824
public final JLabel add(JLabel label, CellConstraints labelConstraints,
825
Component component, CellConstraints componentConstraints) {
826
if (labelConstraints == componentConstraints)
827
throw new IllegalArgumentException(
828
"You must provide two CellConstraints instances, " +
829
"one for the label and one for the component.\n" +
830
"Consider using #clone(). See the JavaDocs for details.");
832
add(label, labelConstraints);
833
add(component, componentConstraints);
834
label.setLabelFor(component);
573
839
// Accessing the ComponentFactory *****************************************
870
// Overriding Superclass Behavior *****************************************
873
* Adds a component to the panel using the given cell constraints.
874
* In addition to the superclass behavior, this implementation
875
* tracks the most recently added label, and associates it with
876
* the next added component that is applicable for being set as component
879
* @param component the component to add
880
* @param cellConstraints the component's cell constraints
881
* @return the added component
883
* @see #isLabelForFeatureEnabled()
884
* @see #isLabelForApplicable(JLabel, Component)
886
public Component add(Component component, CellConstraints cellConstraints) {
887
Component result = super.add(component, cellConstraints);
888
if (!isLabelForFeatureEnabled()) {
891
JLabel mostRecentlyAddedLabel = getMostRecentlyAddedLabel();
892
if ( (mostRecentlyAddedLabel != null)
893
&& isLabelForApplicable(mostRecentlyAddedLabel, component)) {
894
setLabelFor(mostRecentlyAddedLabel, component);
895
clearMostRecentlyAddedLabel();
897
if (component instanceof JLabel) {
898
setMostRecentlyAddedLabel((JLabel) component);
904
// Default Behavior *******************************************************
907
* Checks and answers whether the given component shall be set
908
* as component for a previously added label using
909
* {@link JLabel#setLabelFor(Component)}.
911
* This default implementation checks whether the component is focusable,
912
* and - if a JComponent - whether it is already labeled by a JLabel.
913
* Subclasses may override.
915
* @param label the candidate for labeling {@code component}
916
* @param component the component that could be labeled by {@code label}
917
* @return true if focusable, false otherwise
919
protected boolean isLabelForApplicable(JLabel label, Component component) {
920
// 1) Is the label labeling a component?
921
if (label.getLabelFor() != null) {
925
// 2) Is the component focusable?
926
if (!component.isFocusable()) {
930
// 3) Is the component labeled by another label?
931
if (!(component instanceof JComponent)) {
934
JComponent c = (JComponent) component;
935
return c.getClientProperty(LABELED_BY_PROPERTY) == null;
940
* Sets {@code label} as labeling label for {@code component} or an
941
* appropriate child. In case of a JScrollPane as given component,
942
* this default implementation labels the view of the scroll pane's
945
* @param label the labeling label
946
* @param component the component to be labeled, or the parent of
947
* the labeled component
949
protected void setLabelFor(JLabel label, Component component) {
950
Component labeledComponent;
951
if (component instanceof JScrollPane) {
952
JScrollPane scrollPane = (JScrollPane) component;
953
labeledComponent = scrollPane.getViewport().getView();
955
labeledComponent = component;
957
label.setLabelFor(labeledComponent);
961
// Helper Code ************************************************************
964
* Returns the most recently added JLabel that has a mnemonic set
965
* - if any, <code>null</code>, if none has been set, or if it has
966
* been cleared after setting an association before, or if it has been
967
* cleared by the garbage collector.
969
* @return the most recently added JLabel that has a mnemonic set
970
* and has not been associated with a component applicable for this
971
* feature. <code>null</code> otherwise.
973
private JLabel getMostRecentlyAddedLabel() {
974
if (mostRecentlyAddedLabelReference == null) {
977
JLabel label = (JLabel) mostRecentlyAddedLabelReference.get();
986
* Sets the given label as most recently added label using a weak reference.
988
* @param label the label to be set
990
private void setMostRecentlyAddedLabel(JLabel label) {
991
mostRecentlyAddedLabelReference = new WeakReference(label);
996
* Clears the reference to the most recently added mnemonic label.
998
private void clearMostRecentlyAddedLabel() {
999
mostRecentlyAddedLabelReference = null;