DBListModel and DBListDataBinder
If you have not installed JDataStore, please install it before running this sample. Follow the instructions on Installing JDataStore in Developing Database Applications.
This sample borrows IntlDemo's data but it doesn't enforce IntlDemo's data consistency rules: we don't add line items for each new order, we don't calculate order totals, we don't automatically number orders and keep track of the next available order number, and so on. To prevent changes that might cause trouble when the IntlDemo application is run, we've disabled saving of changes. We recommend that you add or modify any data you need to experiment with this application but let all your changes be discarded when you exit.
A lookup seems quite different from a picklist: it is a way of translating the values in a column, for instance by displaying each customer's name instead of their Customer Number. The actual data type and contents of the column does not change - in this example, it is still a column of numbers - but the displayed contents (and data type, sometimes) do change. A lookup is used to display data, while a picklist's main purpose is to control editing of data.
What picklists and lookups have in common is that they are similar in their internal workings and in the way you define them. Both are defined by the pickList property of a data set column. The picklist definition points to a column in another data set, called the picklist data set, that provides the list of all allowed values for the column whose picklist is being defined. Selecting a value from the list identifies a row in the picklist data set. The picklist definition also specifies which values from this row should be filled into which columns of the data set being edited. A lookup borrows this part of the picklist definition to specify which row in the picklist data set provides the translated value for each column value.
In dbSwing, picklists and lookups are displayed through JdbList and JdbComboBox components. A combo box component takes up less space than a picklist component, so is generally more useful. But a picklist component has the advantage that it displays some or all of the values we're selecting from all the time. The main picklist here - the one that changes as you select different options - results from setting the picklist property of the Customer Number column in the ORDERS data set. This column is displayed in a JdbComboBox. The values in this picklist come from the Customer Number column of the CUSTOMERS data set. We've also defined a picklist on the Payment Method column of the ORDERS data set, which is displayed in a JList. This is intended as a demonstration of DBListModel and DBListDataBinder.
At runtime: Select picklist, fill-in, and lookup options in the
panel at the left and see how they affect the display and editing of an order record.
Every available combination of options creates a different picklist. That's why picklists are sometimes hard to understand - because there are so many choices. By the way, what we call Name Lookup in Drop-down isn't a distinct picklist descriptor option - we just choose to display a different column from the picklist data set. We show it here because it's a useful variation.
You may want to experiment with picklist options here until you like what you see, find the call to setPickList() that corresponds to that set of options, and model the code in your application after it. Calls to setPickList() in PickListsFrame.java are grouped and commented so you can find the one you want. You can even copy the parameters from this call into the only call to SetPickList in jbInit, then switch to design mode, open the editor for the picklist property, and see what settings in the editor give the desired results. One thing to keep in mind when you open the picklist property editor: in this sample, columns in the CUSTOMERS data set have the same names as columns in ORDERS. So in our calls to setPickList(), the second and fourth parameters are always identical: the second parameter is the list of columns in CUSTOMERS to copy from, and the fourth parameter is the list of columns in ORDERS to copy to. It would be clearer if the source and target column names differed, but they don't in our data sets.
Ordinarily, a data set is opened when a component that is bound to it opens. When you use a dbSwing model, you must open its data set. Similarly, when a dbSwing binder is bound to a component indirectly - because you have set its model property to a model which in turn is bound to a component - you must open its data set.
Here's how you can see the JList's data-awareness in action at runtime: Select the Payment Method page of the tabbed pane, insert a new row ("Discover", for example), and save it. Back on the Order Form page, notice that the list of values for Payment Method has been notified of the change by the DBListModel, and therefore includes the new value. Navigate through the Orders data set, and notice that the selection in the JList component changes to show the correct payment method for each order. Change an order's payment method and save the changes. Confirm on the Orders Table page of the tabbed pane that the change was made. This is done by the JdbListDataBinder.
Note: If an application includes a JdbNavToolBar but not a JdbStatusLabel, the dialog that displays ValidationExceptions will be suppressed. If you include a JdbNavToolBar in your application, it is a good idea to include a JdbStatusLabel as well, unless you write your own exception handling.
Before it displays a message, JdbStatusLabel sends a StatusLabelEvent to all registered listeners. By writing a listener for StatusLabelEvent, you can suppress or modify status messages. When the listener wants to modify a message, it writes its desired text to the JdbStatusLabel using setText() and throws a VetoException, which instructs JdbStatusLabel to do nothing further with the StatusEvent. If no listener vetoes a StatusEvent, JdbStatusLabel displays it as usual.
You might use a StatusEventListener to suppress non-essential messages or to add additional detail to terse messages. In this sample, we simply add an icon to each message to show its type. We define three types:
At runtime: Notice the status message when you change a picklist definition or toggle combo box editability. The icon is intended to show that the message comes from the application. Try to save an Order row with the Last Name or First Name field blank; now the message and icon indicate that this input is not valid. Other messages, mostly of the form "Record n of m" come from the statusLabel itself or from data set StatusEvents; they have a third icon that shows that their source is a data set.
You can customize the dbSwing exception dialog by dropping DBExceptionHandler from the component palette into your application and setting its properties. JBuilder doesn't automatically create a new instance of DBExceptionHandler. Instead, it calls getInstance(), which ensures that there's only a single instance of DBExceptionHandler in the application. This lets you set properties for the exception dialog once and have them used throughout your application. If you like the default exception dialog, you don't even need an instance of DBExceptionHandler. Just call its static handleException() method in catch blocks in your code, passing it the exception.
If DBExceptionHandler doesn't give you enough control, you can instantiate the dialog it displays, DBExceptionDialog, set properties of the dialog, and call its show() method. But unless you feel strongly about the look of the dialog or want to change the text of an error message, this isn't worth the effort.
For more control over exceptions, you can implement the ExceptionListener interface.
To register as a listener, call DataSetException's static addExceptionListener() method.
To ensure that this static reference is never garbage collected, create an object data
member and set it to DataSet.class:
Object classHolder = DataSet.class;
Handle exceptions in the ExceptionListener's exception() method. In this case, you must
handle all exceptions yourself. You can't call handleException(); if you do, the handler
will send the exception right back to you (because you've registered as a listener),
causing a stack overflow.
In this application, we just set a property on the exception handler and use it in a catch block. To see the exception dialog, change the file name of one of the icons that's loaded in PickListsStatusListener's constructor to an invalid value. Run the application and you'll see the exception dialog.
Tabbed Pane: This sample uses Swing's JTabbedPane to fit a lot of components onto a single frame. Here's what you need to know to work with JTabbedPane in the UI Designer:
Tooltips: Tooltips are used in several places to explain the expected input:
dbSwing tools: In addition to DBExceptionHandler, which is discussed above, the dbSwing samples demonstrate two other valuable and easy-to-use dbSwing components: