 | Level: Introductory Michael Abernethy (mabernet@us.ibm.com), Software Engineer II, IBM
12 Oct 2004 This article introduces the TableModel Free (TMF) framework which eliminates the need to use TableModels with Swing JTables. The TMF framework allows for more configurable JTables by moving all of table-specific data outside of the compiled code and into a configurable XML file. Framework developer and Java UI enthusiast Michael Abernethy walks you through TMF framework, helping you reduce the size of a TableModel from hundreds of lines of code to just a single line, making management a snap.
The "reintroduction of the Java™ Desktop" underscored this year's JavaOne conference. A renewed effort on Swing and GUI development doesn't come as welcome news to those of you who swore off Swing as too slow, too hard to use, or too ugly. Well, if you haven't worked with Swing lately, you'll be glad to hear that many of these problems have disappeared. Swing has been reworked to perform better and to take better advantage of the Java 2D API. The Swing developers have improved the look and feel support in 1.4 and even more so in the recently released 5.0. Swing is back and better than ever before.
What the Swing community needs right now are tools to make GUI development a smoother, easier process. And that's where this article comes in.
This article introduces the TableModel Free (TMF) framework, a GUI development package that relieves the need to create TableModels (which I'll call classic TableModels in this article to distinguish them from the new structures I introduce for the framework) for every JTable; in the process, you'll be able to make your JTables much more configurable and maintainable.
If you've ever used a JTable, you've also been forced to use a TableModel. You've probably also noticed that nearly all of the code in each TableModel is identical to the code in every other TableModel, and the code that is different doesn't really belong in a compiled Java class anyway. This article will dissect the current methods of TableModel/JTable design, illustrate the shortcomings of this design, and show how it hasn't accomplished the true goals of the Model-View-Controller (MVC) pattern. You will see the framework and code that makes up the TMF framework -- a combination of code that I've written and commonly used open source projects. With this framework, developers can reduce the size of a TableModel from hundreds of lines of code to a single line, and put the important table information in an external XML file. After reading this article, you will be able to manage your JTable's data using the single line of code shown here:
TableUtilities.setViewToModel("tableconfig.xml", "My Table",
myJTable, CollectionUtilities.observableList(myData));
|
 |
Open source packages in the TMF framework
Let's take a brief look at the two open source packages I used to help build the TMF framework. By combining open source packages and adding some creativity, you can develop some very powerful programs. See the Resources for links to these packages.
Apache Jakarta Commons Collections
Perhaps the best known and most utilized open source projects are those under the Apache umbrella. The Apache Jakarta project contains many Java-specific extensions and packages, and one of these packages is the Commons project. Its goal, as stated right on the Web site, is "creating and maintaining reusable Java components." There are too many of these components to list here, but the one that is used in this article is the Jakarta Commons Collections framework, which offers a broad array of extensions to the Java Collections framework.
Castor
Castor is a widely used XML parsing tool, and although there are many XML parsers out there already, the strengths of Castor make it very popular. With Castor, it is very easy to create complex Java objects from simple XML documents. It moves a lot of the dirty work of the XML-to-Java-object conversion away from the XML file, and places the burden of these complex conversions on a mapping file that acts as the intermediary between Java and XML. With some savvy developer work in the mapping file, even the most difficult transformations can be made from XML files that are easy to read and update. As a result, the Castor tool is most powerful in parsing XML files that are used as configuration files -- ones that will be updated by the end user and thus must be easy to read.
|
|
MVC problems with JTable and TableModel
MVC has become a very popular UI design pattern, as it cleanly separates out the business logic from the view of the data. Struts is a very good example of the MVC design in use on the Web. One of the big initial selling points of Swing was its use of the MVC -- separating the view from the model -- the idea being that the code was modular enough that you could swap out the view without changing any code in the model. I think anyone who has ever worked with JTables and TableModels will laugh and tell you that that's flat-out impossible. Ideally, using the MVC design pattern, a developer should be able to substitute a JList or a JComboBox for a JTable with no change to the code in the model representing the data. However, you can't do that in Swing. Swing makes it impossible to hot swap a JTable, JList, and JComboBox into an application, even if all three components were to provide views of the same data model. That's a big deficiency in the MVC design with Swing. If you want to swap a JList for a JTable, you must rewrite the entire model behind the view to accommodate it.
Another MVC deficiency specific to JTable/TableModel is the fact that the view does not update itself when the model changes. A developer must keep a reference of the model and call a function so that the model tells the view to update itself; ideally, however this should just happen without any additional code.
Ultimately, the problem with the design of the JTable and TableModel components is that they are too intertwined with one another. If you change code in the JTable, you need to make sure that you haven't broken your TableModel in the process, and vice versa. In what is supposed to be a design pattern built on modularity, the current implementation is more a design of dependencies.
The TMF framework better adheres to the MVC goals by more cleanly separating the tasks of the view and the model in a JTable. Though it doesn't reach the higher goal of making the components hot swappable, it is a step in the right direction.
Introducing the framework
Let's examine the TMF framework and see how it makes the classic TableModel obsolete. The first part of designing the framework consisted of learning about the uses of a JTable -- how developers use it, what it displays -- to understand what could be internalized and made generic and what had to stay configurable for the developer. The same thinking went for TableModels -- I had to determine what I could move out of the code and what had to stay. Once I had these issues figured out, it came down to deciding the best technique to make the code generic enough to use so that everyone could use it, but configurable enough so that, once again, everyone could use it.
The framework is divided into three basic parts -- a generic TableModel that can handle any type of data, an external XML file that allows for the configuration of the table parts that change from table to table, and a bridge between the model and the view.
Click on the Code icon (or see the Download section) to download the source code, third party JAR files, and Javadocs discussed in this article. In this article, you can find all the source code presented in this article under the src folder. The TMF-specific code is located in the com.ibm.j2x.swing.table package.
com.ibm.j2x.swing.table.BeanTableModel
The BeanTableModel is the first part of the framework. It acts as a generic TableModel that you can use with any type of data. I know, you're saying, "How can you be sure that it will work with all data?" Well, I can't, obviously, and in fact I'm sure there are some instances where it won't. But from my experience using JTables, I'd be willing to bet (even if I had a small kicker) that 99 percent of JTables are used to display a list of data objects (that is, an ArrayList of JavaBeans components). Using this assumption, I created a generic table model that can be used to display any list of data objects: the BeanTableModel.
The BeanTableModel makes heavy use of Java introspection to examine the fields in a bean and to display the correct data. It uses two classes from the Jakarta Commons Collections framework (see the sidebar for more information) to assist in this design as well.
Let me explain a few concepts from the class before I get into the code. Because I can use introspection on beans, I need to know information about the bean itself -- mainly, what the names of the fields are. I could do that through normal introspection: I could inspect the bean and find out its fields. However, this isn't good enough for a table, because most developers want their tables to display fields in a specified order. In addition, there is one piece of information needed for table display that I could not get from the bean through introspection: the column name. Thus, to display correctly, you need two pieces of information about each column in the table: the column name, and the field in the bean to display. I represent this information in the form of a key-value pairing, where the column name acts as the key and the field as the value.
This is where the two classes I've used from the Collections framework fit in. The BeanMap acts a utility class for dealing with introspection by taking all of the nasty work out of it. Normal introspection development requires lots of try/catch blocks, which is unnecessary for a table. The BeanMap takes a bean as input and treats it like a HashMap -- where the key is the field (firstName, for example) in the bean and the value is the result of the get function (getFirstName(), for example). The BeanTableModel uses the BeanMap extensively to remove the hassles of working with introspection, and makes accessing information in the beans much easier.
The LinkedMap is the other class used throughout the BeanTableModel. Going back to the key-value data setup for the column name-field mapping, the obvious choice for a data object would be a HashMap. However, a HashPap does not preserve the order of insertion, which is an important part of the table -- a developer would want the columns appearing in a set order every time the table is displayed. Thus, the order of insertion must be preserved. The LinkedMap is the solution -- it is a combination of a LinkedList and a HashMap, and it preserves both column and column order information. Take a look at Listing 1 to see how I use the LinkedMap and BeanMap to set up the table's information.
Listing 1. LinkedMap and BeanMap setting up the table information
protected List mapValues = new ArrayList();
protected LinkedMap columnInfo = new LinkedMap();
protected void initializeValues(Collection values)
{
List listValues = new ArrayList(values);
mapValues.clear();
for (Iterator i=listValues.iterator(); i.hasNext();)
{
mapValues.add(new BeanMap(i.next()));
}
} |
The interesting code to examine in the BeanTableModel is the actual generic TableModel part of it -- the code that extends the AbstractTableModel. You can see the similarities between the code in Listing 2 and the code you'd normally use to create a classic TableModel.
Listing 2. Generic TableModel code in BeanTableModel
/**
* Returns the number of BeanMaps, therefore the number of JavaBeans
*/
public int getRowCount()
{
return mapValues.size();
}
/**
* Returns the number of key-value pairings in the column LinkedMap
*/
public int getColumnCount()
{
return columnInfo.size();
}
/**
* Gets the key from the LinkedMap at the specified index (and a
* good example of why a LinkedMap is needed instead of a HashMap)
*/
public String getColumnName(int col)
{
return columnInfo.get(col).toString();
}
/**
* Gets the class of the column. A lot of developers wonder what
* this is even used for. It is used by the JTable to use custom
* cell renderers, some of which are built into JTables already
* (Boolean, Integer, String for example). If you write a custom cell
* renderer it would get loaded by the JTable for use in display if that
* specified class were returned here.
* The function uses the BeanMap to get the actual value out of the
* JavaBean and determine its class. However, because the BeanMap
* autoboxes things -- it converts the primitives to Objects for you
* (e.g. ints to Integers) -- the code needs to unautobox it, since the
* function must return a Class Object. Thus, it recognizes any primitives
* and converts them to their respective Object class.
*/
public Class getColumnClass(int col)
{
BeanMap map = (BeanMap)mapValues.get(0);
Class c = map.getType(columnInfo.getValue(col).toString());
if (c == null)
return Object.class;
else if (c.isPrimitive())
return ClassUtilities.convertPrimitiveToObject(c);
else
return c;
}
/**
* The BeanTableModel automatically returns false, and if you
* need to make an editable table, you'll have to subclass
* BeanTableModel and override this function.
*/
public boolean isCellEditable(int row, int col)
{
return false;
}
/**
* The function that returns the value that you see in the JTable. It gets
* the BeanMap wrapping the JavaBean based on the row, it uses the
* column number to get the field from the column information LinkedMap,
* and then uses the field to retrieve the value out of the BeanMap.
*/
public Object getValueAt(int row, int col)
{
BeanMap map = (BeanMap)mapValues.get(row);
return map.get(columnInfo.getValue(col));
}
/**
* The opposite function of the getValueAt -- it duplicates the work of the
* getValueAt, but instead puts the Object value into the BeanMap instead
* of retrieving its value.
*/
public void setValueAt(Object value, int row, int col)
{
BeanMap map = (BeanMap)mapValues.get(row);
map.put(columnInfo.getValue(col), value);
super.fireTableRowsUpdated(row, row);
}
/**
* The BeanTableModel implements the CollectionListener interface
* (1 of the 3 parts of the framework) and thus listens for changes in the
* data it is modeling and automatically updates the JTable and the
* model when a change occurs to the data.
*/
public void collectionChanged(CollectionEvent e)
{
initializeValues((Collection)e.getSource());
super.fireTableDataChanged();
} |
As you've seen, the BeanTableModel makes the entire TableModel generic enough for use in any table. It takes full advantage of introspection to save any bean-specific coding, the kind of coding that was absolutely necessary -- and completely redundant -- in classic TableModels. The BeanTableModel can be used outside of the TMF framework as well, although it loses some of its power and flexibility.
There are a couple of questions that you should have after looking at this code. First, where does the BeanTableModel get the information for the column name-field key-value pairing? And second, what the heck is an ObservableCollection? These questions will lead right into the next two parts of the framework. The answers, and more, will follow in the next few sections of this article.
Castor XML parser
The most logical place to store the necessary column name-field information is outside of the Java class, so that you can change this information without having to recompile your Java code. Because this information about the column name and field is the only information specifically about the table in the TMF framework, this means that the entire table is externally configurable.
Obviously, this solution screams out for XML as the language of choice for a configuration file. The configuration file must store information for multiple table models; you'll also need to be able to use the file to specify the data that goes with each column. The configuration file also ought to be as easy to read as possible, because people besides developers may be changing it.
The best solution to these issues is the Castor XML parser (see the sidebar for more information). The best way to see Castor in use is to look at how it's used in the framework.
Let's think about the goal of the configuration file: to store information about a table model and its columns. The XML file should display this information as simply as possible. The XML file in the TMF framework uses the form illustrated in Listing 3 to store table model information.
Listing 3. Sample TMF configuration file
<model>
<className>demo.hr.TableModelFreeExample</className>
<name>Hire</name>
<column>
<name>First Name</name>
<field>firstName</field>
</column>
<column>
<name>Last Name</name>
<field>lastName</field>
</column>
</model>
|
The converse to this goal is that the Java objects that developers have to deal with should be just as easy to understand as the XML file is. This can be seen in the three Java objects that are used by the Castor XML parser to store the column information: TableData (which stores all of the table models in a file), TableModelData (which stores the table model-specific information), and TableModelColumnData (which stores the column information). These three classes provide all the wrappers needed by a Java developer to get all the necessary information about a TableModel.
The missing link that wraps this all up is known as the mapping file; it's the XML file that Castor uses to map the simple XML to the simple Java objects. In a perfect world, this mapping file would be simple too, but it's a little more complicated than that. A good mapping file keeps everything else simple; so generally, the more complicated the mapping file, the easier the config file and Java objects are to deal with. The mapping file does exactly what its names implies: it maps the XML objects to Java objects. Listing 4 illustrates the mapping file used by the TMF framework.
Listing 4. The Castor mapping file for the TMF framework
<?xml version="1.0"?>
<mapping>
<description>A mapping file for externalized table models</description>
<class name="com.ibm.j2x.swing.table.TableData">
<map-to xml="data"/>
<field name="tableModelData" collection="arraylist" type=
"com.ibm.j2x.swing.table.TableModelData">
<bind-xml name="tableModelData"/>
</field>
</class>
<class name="com.ibm.j2x.swing.table.TableModelData">
<map-to xml="model"/>
<field name="className" type="string">
<bind-xml name="className"/>
</field>
<field name="name" type="string">
<bind-xml name="name"/>
</field>
<field name="columns" collection="arraylist" type=
"com.ibm.j2x.swing.table.TableModelColumnData">
<bind-xml name="columns"/>
</field>
</class>
<class name="com.ibm.j2x.swing.table.TableModelColumnData">
<map-to xml="column"/>
<field name="name" type="string">
<bind-xml name="name"/>
</field>
<field name="field" type="string">
<bind-xml name="field"/>
</field>
</class>
</mapping>
|
Just by looking at the code, you can see that the mapping file clearly outlines each class used to store table model information, defines its class type, and links a name in the XML file to a field in the Java object. Keeping these names identical keeps things easy and more manageable, but it's not a requirement. Get more information on Castor XML mapping from Resources.
So now that the column name and field information has been externalized and read into a Java object that contains the column information, it can easily be sent to the BeanTableModel and used to set up the columns.
ObservableCollection
The final key part of the TMF framework is known as the ObservableCollection. Some of you may already be familiar with the concept of an ObservableCollection, where a member of the Java Collections framework throws events when it is modified and allows its listeners to perform actions based on those events. Although this has never been introduced into a formal release of the Java language, there are some third-party implementations of this concept out on the Internet already. For the purpose of this article, I used my own ObservableCollection implementation, because the framework needed only the most basic functionality. My implementation uses a method called collectionChanged() that is called by the ObservableCollection on its listeners every time it is modified. This usage can be called a Decorator on the Collection class (see the Collections framework site for many more Decorators for Collections), and you can create an Observable instance of a Collection class from a normal Collection class by adding only a few lines of code. Listing 5 shows an example of the ObservableCollection in use. (This is an example only, and is not contained in the code in j2x.zip.)
Listing 5. Example of an ObservableCollection in use
// convert a normal list to an ObservableList
ObservableList oList = CollectionUtilities.observableList(list);
// A listener could then register for events from this list by calling
oList.addCollectionListener(this);
// trigger event
oList.add(new Integer(3));
// listener receives event
public void collectionChanged(CollectionEvent e)
{
// event received here
}
|
The ObservableCollection has many applications outside the scope of the TMF framework; if you decide to not use the TMF framework, you may find that the ObservableCollection framework has many other practical uses in your code development.
Its use in the TMF framework, however, is important in that it better defines the relationship between the view and the model by automatically updating the view when the data changes. If you recall, that was a great limitation of the classic TableModel, because every time the data changed, you had to use the reference of the table model to update the view. In its use in the TMF framework, when the data changes, the view is automatically updated without needing to maintain a reference to the model. You saw this in action in the BeanTableModel's implementation of the collectionChanged() method.
TableUtilities
The final step in this framework is to bring it all together in some utility functions that make it simple and straightforward to use the TMF framework. These utility methods are found in the com.ibm.j2x.swing.table.TableUtilities class, which provides all the helper functions you'll need:
-
getColumnInfo(): This utility method uses the Castor XML file to parse the specified file and returns all the column information for the specified table model in the LinkedMap form that the BeanTableModel needs. This method becomes important when the developer chooses to subclass the BeanTableModel.
-
getTableModel(): This utility method builds off the getColumnInfo() method above by getting the column information and then passing it to a BeanTableModel and returning the BeanTableModel with all the column information already set up.
-
setViewToModel(): This utility method is the most important function and main attraction of the TMF framework. This method builds off the getTableModel() method and also takes a reference to the JTable that will have this table model, as well as a reference to the data that will display in the table. It then sets the TableModel on the JTable and passes the data to the TableModel -- in effect, it completely sets up the TableModel for the JTable in only one line of code. The TMF framework is best exemplified by this function, as your TableModels will be forever replaced by the simple function shown below:
TableUtilities.setViewToModel("table_config.xml", "Table", myJTable, myList); |
 |
The TMF framework in action
Every article about GUI programming needs an example, and of course this article will not be any different. The goals of this example will be to point out the major advantages of working with the TMF framework in place of the classic TableModel design. The example will show an application that has more than one table on the screen, will both add and delete from the tables, will have tables that contain different types of information (Strings, ints, Booleans, BigDecimals), and, most importantly, will include configurable column information that must be changed regularly.
The example application code is separate from the J2X packages, and you can find the source code in the src directory under the HR folder. You can also run the application through the JRE by double-clicking on the compiled JAR file located in the build/lib folder.
In the example application, there are two classes that can be swapped for one another, one called TableModelFreeExample and the other called TableModelExample. Both classes do the same thing in the application, and make the application behave in the same way; however, they are designed differently, one using the TMF framework and one using classic TableModels. The first thing you'll notice about them is that the TMF class, TableModelFreeExample, is made up of 63 lines of code, while the classic TableModel version, TableModelExample, is 285 lines long.
The Evil HR Director app
The example application that I will use is the Evil HR Director application, which allows an HR director (possibly furry and wearing glasses) to see a pool of potential employees in a JTable, and then hire from this table. The new hire will then be transferred to the two JTables for current employees; one of these tables contains personal information, while the other contains financial information. From there, the director can choose to fire any employee at will. You can see the UI for the app in Figure 1.
Figure 1. The Evil HR Director application
To further prove the simplicity of the TMF framework, take a look at Listing 6. This listing contains the three lines of code that are needed to produce the models for the three tables in the Evil HR Director application. These lines of code can be found in the TableModelFreeExample.
Listing 6. Code needed to produce models in the Evil HR Director application
TableUtilities.setViewToModel("demo/hr/resources/evil_hr_table.xml",
"Hire", hireTable, candidates);
TableUtilities.setViewToModel("demo/hr/resources/evil_hr_table.xml",
"Personal", personalTable, employees);
TableUtilities.setViewToModel("demo/hr/resources/evil_hr_table.xml",
"Financial", financialTable, employees);
|
For comparison, the TableModelExample contains the code needed to produce the models for the three tables using the classic TableModel approach. Take a look at the code in the sample package. I'm not going to list it all here, though, because it's 205 lines long!
Demonstrating the TMF framework's flexibility
One of the big advantages of the TMF framework is that it makes it much easier to alter a JTable-based application after rollout. To demonstrate this, let's look at two potential scenarios that might arise in daily use of the Evil HR Director app. In each, you'll see how the framework makes it easier to adapt the application to changing user needs.
Scenario 1: The corporate policy changes and says that it is illegal to see someone's marital status in a company application.
-
TableModelFree: The end users need to remove
<name>Married?</name><field>married</field> from the XML configuration file.
-
Classic TableModel: The developer has to go into the Java code and change
getColumnName() to not return the column name "Married?", change getColumnCount() to return a result of one fewer columns than it originally returned, and change getValueAt() to not return isMarried(). Then the developer must recompile the Java code and redeploy the application.
Scenario 2: The corporate policy changes and the company feels it necessary to include the state of residence in the potential employees table.
-
TableModelFree: The end users need to add
<name>State</name><field>state</field> to the XML configuration file.
-
Classic TableModel: The developer has to go into the Java code and change
getColumnName() to add a new column called "State", change getColumnCount() to return a column count that is incremented by one, and change getValueAt() to return getState(). Then the developer must recompile the Java code and redeploy the application.
As you can see, when the tables in your applications will be changing (which may occur frequently at the whim of your pointy-haired bosses), editing an XML file is always going to be much easier than redeploying the entire application.
Using the code
Before you race off to delete all your TableModel code, I thought I'd take a minute to explain the contents of the j2x.zip file, and how you can use it in your own project. (Remember, the TMF-specific code can be found in the com.ibm.j2x.swing.table package; you'll also find additional code in the J2X package that I introduced in an earlier article, "Go state-of-the-art with IFrame." See Resources for a link to this article.)
The j2x.zip file contains two folders:
-
src -- Contains the source code used in this article. Underneath the src folder, there are two folders: HR, which contains the source code used to make the Evil HR Director application, and J2X, which contains all the source code used in the J2X project.
-
build -- Contains the compiled class files of both the Evil HR Director application and the J2X project. The lib folder inside this folder contains the JAR files for both the HR application and the J2X project.
The lib.zip file contains the following folder:
-
lib -- Contains all the third-party JAR files needed to run both the application and any project utilizing the J2X project. You can find the licenses for these third party projects in this folder as well.
The docs.zip file contains the following folder:
-
docs -- Contains all the JavaDoc information for the J2X project.
To use the J2X packages in your application, you will need to point your CLASSPATH to the j2x.jar in the build/lib folder as well as to all three of the third-party JAR files contained in the lib folder. The licensing terms of the 3rd party packages allow you to redistribute all packages included in this article, but please read the license terms if you are interested in modifying the packages in any way.
Conclusion
With the TableModel Free framework, you should never need to write a classic TableModel again. The TMF framework improves the MVC relationship between the JTable and the TableModel by more cleanly separating the parts. In future releases, you will even be able to hot swap components without changing any model code. The framework also allows you to automatically update the view when the model changes, eliminating the communication that was needed between view and model in the classic TableModel design.
The TMF framework will also drastically decrease the time needed for GUI development, especially work with JTables. As an example, a few years ago I worked on an application that had over 150 JTables in it, each with an original table model. With the TMF framework, we could have taken care of this in 150 lines of code; unfortunately, TMF was not yet built, so we ended up writing 15,000 extra lines of code to produce the necessary table models. That adds not only to development time, but testing and debugging time as well.
With the TMF framework, you'll have an easier time configuring all of your JTables than you would using the classic TableModel. Imagine a POS application that is sold to five different clients. Each client is concerned with a unique set of information, and so each client wants a unique set of columns displayed in the application's GUI. Without the TMF framework, a unique TableModel would have to be created for each client -- and thus, a unique application as well. Using configurable XML files, each client could use the same application and have a business analyst at the client site change the XML files as needed. Imagine the development and support cost savings!
The TableModel Free framework addresses a specific need in the Swing developer community: reducing the development time and maintenance overhead of working with JTables, and increasing their ease of use for end users. The Swing desktop is making a return, and with tools like the TMF framework, developers will find it easier to work with Swing and develop GUI applications. One of the first steps is replacing all your TableModels with the single line of code from the TMF framework and banishing those TableModels forever off to the black hole of cyberspace.
Downloads
Resources
- Click on the Code icon (or see the Download section) to download the source code, third party JAR files, and Javadocs discussed in this article.
-
The Jakarta Commons Collections provides additional functionality on top of the Java Collections.
- Interested in XML? Then be sure to visit the
developerWorks XML zone, which boasts a tremendous library of excellent content for beginners and experts alike.
- The IFrame, introduced in "Go state-of-the-art with IFrame," Michael Abernethy (developerWorks, March 2004) is another component in the J2X project. It allows you to create custom designed application windows.
- "Building a Customized Tree View," Andy Clark and Dave Smith (developerWorks, January 2001) offers tips on using the MVC in a Swing component.
- "Struts, an open-source MVC implementation," Malcolm Davis (developerWorks, February 2001) offers the MVC in use with a Web application.
- "Swing model filtering," Mitch Goldstein (developerWorks, February 2001) offers an alternative to the TMF framework for TableModel design.
- " Rendering cells in Swing's JTable component," Brett Spell (developerWorks, November 2000) adds to a JTable's functionality by offering tips on cell rendering.
- You'll find articles about every aspect of Java programming in the
developerWorks Java technology zone.
-
Browse for books on these and other technical topics.
About the author  | 
|  | Michael Abernethy currently works as a lead in the WebSphere System Management Functional Test Team and has worked previously in the WebSphere Services team for four years, writing and deploying enterprise applications on WebSphere. He dabbles in Swing and UI development in his free time. Contact Michael at mabernet@us.ibm.com. |
Rate this page
|  |