 |
Home | Changes | Index | Search | Go
JComponentBreadboard-based Address Book Example Implementation
Can it align components across other components? For example, can it both left and right align the 'phone' text field with the 'city' text field on the other side of the two address fields?
Yes.
Does your manager know about platform specific gaps and spacing among components. Just curious.
No. But it's easy to introduce arbitrary spacing into any grid via the xSpace and
ySpace static methods (see code below).
Can the text fields, labels, etc grow and shrink when the text is localized?
Because field sizes are always based on the "preferred size" computed by Swing (which should vary appropriately with each locale) I think the answer is yes.
Just how much code do I have to write? Java code? Declarative XML?
It's all pure Java, and as the example illustrates, there's very little of it. For
many forms, most of the work involves defining a single 2-D array into which component
references are placed, which mimics their relative positions on the form.
Can I nest panels?
Yes, though the basic grid is so flexible it's very rare to nest more than one
level deep.
Can it align components along a baseline. For example, the new GroupLayout" can align labels and text fields along the text baseline...that's nice.
No..however, in addition to the natural alignment of
the component as a whole via the grid, the xAlign and yAlign methods allow
you to left/right, top/bottom (or some intermediate fraction thereof) justify
within the grid-cell-block occupied by each JComponent. Using these methods, you
could at least fake the alignment along a text baseline. I've never seen the
need for this kind of thing, but I'm not terribly demanding when it comes to
things looking nice...getting them all into the little boxes is about where I stop.
What's the licensing?
The no-hassle BSD, which means it's wide open for use in both open source and commercial applications.
Will this work for bi-directional locales? How difficult would it be to mirror the layout for a right-to-left locale?
No--you would have to define a separate "breadboard array" for each locale (or stick to one
standard layout for all locales). It would be quite feasible to add such a capability in a
future version, given how the code is organized, though. Maybe someone reading
this blog will decide to do it...
What else should we evaluate?
The one feature JComponentBreadboard's layout manager has that I've never seen
anywhere else is the explicit use of a 2-D array to specify the basic layout.
This means that there is a one-to-one correspondence between the position of a
component in this array and it's position on the JPanel. Thus, you can actually
see the position of your components by looking at the code--sort of like a
plain-text, poor-man's GUI builder. For certain simple forms "one or two
evolutionary steps beyond JOptionPane" it's pretty much an ideal approach.
Strictly speaking, JComponentBreadboard isn't a layout manager, it has a layout
manager (analogous to how the JDK's Box class has a BoxLayout). It can create
complete, full-functional, forms, and includes (greatly streamlined) data
binding, data validation, worker thread/progress cancel feedback, full
JComponent array support (e.g. indexed, bound, getter/setter methods), and more.
Even if you prefer a GUI builder for most of your forms, it can still fill a
valuable niche in your toolbox as a "better JOptionPane". It's dedicated to the
principle that you shouldn't have to leave your text editor to ask the user a
couple of questions via a simple, full-functional, form.
The web site provides links to the javadocs/users guide (there's lots of good
examples in the User's guide, including a pretty good date-chooser), source
code, and downloads:
Web site: http://jcbreadboard.sourceforge.net/
For the layout manager focused reader, a detailed technical description of the
layout manager's GridBagLayout-motivated algorithm is provided within the
setBreadboard method's javadocs.
This shows the form at application startup:
This shows what the form looks like after being resized via the sizing border:
// LayoutManagerShowdown.java
import javax.swing.*;
import net.sourceforge.jcomponentbreadboard.JComponentBreadboard;
@SuppressWarnings("serial")
// JComponentBreadboard extends JPanel, and thus can be used anywhere a JPanel can.
public class LayoutManagerShowdown extends JComponentBreadboard {
public LayoutManagerShowdown() {
JComponent nonScrollingList =
new JList(new String[] {"Bunny, Bugs", "Bird, Tweety", "Sailorman, Popeye"});
// xyFill, xyAlign, etc. are JComponentBreadboard static methods that
// define special layout-manager-recognized client properties of
// their JComponent argument, returning that argument as their result.
JComponent list = xyFill(xyAlign(0,0, new JScrollPane(nonScrollingList,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED)));
JComponent firstLbl = xAlign(0, new JLabel("First Name "));
JComponent first = xFill(new JTextField(10));
JComponent lastLbl = xAlign(1, new JLabel("Last Name"));
JComponent last = xFill(new JTextField(10));
JComponent phoneLbl = xAlign(1, new JLabel("Phone"));
JComponent phone = xFill(new JTextField(10));
JComponent emailLbl = xAlign(0, new JLabel("Email "));
JComponent email = xFill(new JTextField(10));
JComponent address1Lbl = xAlign(1, new JLabel("Address 1"));
JComponent address1 = xFill(new JTextField(10));
JComponent address2Lbl = xAlign(1, new JLabel("Address 2"));
JComponent address2 = xFill(new JTextField(10));
JComponent cityLbl = xAlign(1, new JLabel("City"));
JComponent city = xFill(new JTextField(10));
JComponent stateLbl = xAlign(1, new JLabel("State"));
JComponent state = xFill(new JTextField(10));
JComponent postalLbl = xAlign(0, new JLabel("Postal Code "));
JComponent postalCode = xFill(new JTextField(10));
JComponent countryLbl = xAlign(1, new JLabel("Country"));
JComponent country = xFill(new JTextField(10));
JButton newButton = new JButton("New");
JButton deleteButton = new JButton("Delete");
JButton editButton = new JButton("Edit");
JButton saveButton = new JButton("Save");
JButton cancelButton = new JButton("Cancel");
// These JComponentBreadboards are nested to allow, for example,
// the buttons to be aligned independently of the rest of the
// grid. Note that unlike the GroupLayout example, which is deeply
// nested, only one, simple, level of such nesting is required, so
// the basic "one grid" simplicity of layout specification is
// retained. This is just one of many basic design ideas I stole
// from GridBagLayout--my layout manager is essentially a better,
// simpler, easier-to-use, less quirky, GridBagLayout.
// Note how simple row/column scaling directives replace the
// (quite bewildering, in my view) weighting factors of
// GridBagLayout. Scaling across the grid is uniform and
// proportional to the preferred size determined row and column
// widths and heights of the grid (a full description of the
// layout manager's algorithm is available in
// JComponentBreadboard's javadocs under the setBreadboard
// method).
JComponent emailPanel = xFill(new JComponentBreadboard(new Object[][] {
{null, NOSCALE, EXPANDS},
{NOSCALE, emailLbl, xFill(email)}
}));
JComponent postalPanel = xFill(new JComponentBreadboard(new Object[][] {
{null, NOSCALE, EXPANDS},
{NOSCALE, postalLbl, xFill(postalCode)}
}));
// by default, without directive headers, every row and column get the
// NOSCALE directive.
//
// xSpace, ySpace are static convenience methods that return JPanels
// of a specified width or height, to facilitated introducing spacing between rows
// and columns of the grid.
//
JComponent buttonBar = new JComponentBreadboard( new Object[][] {
{xSpace(15), newButton, xSpace(5), deleteButton, xSpace(5), editButton,
xSpace(5), saveButton, xSpace(5), cancelButton}
});
//
// The 1-pixel high (ySpace(1)), but stretchable (BISCALE) last row allows the list
// to expand to fill out any extra vertical space when the user resizes the parent.
//
setBreadboard(new Object[][] {
{null, EXPANDS, NOSCALE, NOSCALE, NOSCALE, EXPANDS, NOSCALE, NOSCALE, EXPANDS},
{NOSCALE, list, xSpace(15), lastLbl, xSpace(5), last, xSpace(5), firstLbl, first},
{"" , "", ySpace(5), null, null, null, null, null, null},
{"" , "", null, phoneLbl, null, phone, null, emailPanel, __},
{"" , "", ySpace(5), null, null, null, null, null, null},
{"" , "", null, address1Lbl, null, address1, __, __, __},
{"" , "", ySpace(5), null, null, null, null, null, null},
{"" , "", null, address2Lbl, null, address2, __, __, __},
{"" , "", ySpace(5), null, null, null, null, null, null},
{"" , "", null, cityLbl, null, city, null, null, null},
{"" , "", ySpace(5), null, null, null, null, null, null},
{"" , "", null, stateLbl, null, state, null, postalPanel,__},
{"" , "", ySpace(5), null, null, null, null, null, null},
{"" , "", null, countryLbl, null, country, null, null, null},
{"" , "", ySpace(5), null, null, null, null, null, null},
{"" , "", null, buttonBar, __, __, __, __, __},
{BISCALE, "", ySpace(1), null, null, null, null, null, null}
});
setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
}
public static void main(String[] args) {
// showMessageBreadboard is JComponentBreadboard's answer to
// JOptionPane.showMessageDialog--see User's Guide for details.
showMessageBreadboard(null, new LayoutManagerShowdown(),
"Address Book Demo");
}
}
|