December 22, 2014
Hot Topics:

MVC in a Java/Swing Application

  • May 21, 2007
  • By Rob Lybarger
  • Send Email »
  • More Articles »

Using the controller

When working with the class that the text component resides in—most appropriately during initialization and layout—make a call to pass a reference to the text component to the controller:

...
JTextArea textArea = new JTextArea(rows,cols);
AppController.getInstance().setTextComponent(textArea);
...

When setting up the event listener for the button, feel free to make an anonymous class implementation:

...
JButton escapeButton = new JButton("Escape XML");
escapeButton.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
      AppController.getInstance().handleEscapeAction();
   }
});
...

Aside from the actual code for the handleEscapeAction method, that is pretty much it. Note how adding a menu item to a menu bar can be just as simple. More importantly, note how the controller neither knows nor cares how its handleEscapeAction method is called, nor exactly where the text component itself lives in the overall design of the application (nor does the button really know what happens when its event fires, if anything.) Also note how much simpler it would be to redesign the user interface components: the interactions between components are stored in a separate controller class that need not change. (Just be sure to properly initialize the controller's component references in the redesigned code user interface code. See the 'Careful Initialization' section below.)

Business Logic

So where is the business logic in all this? After all, you might have taken inter-component control code out of the UI, but the controller class still needs to track reference to a few UI component references (plus know how to interact with them). In the case of the demo app, one last class is used to contain the details of the "business logic," which for you is the actual escaping of characters in some String object. If you download the source code file attachment for this article, note that the Escaper class contains one method that takes one String argument and returns another String argument. This represents the actual workhorse code for the application. In your real-world application, this would do something far more interesting: load or save files, talk to a database, perform some interesting calculation, or whatever.

The net effect for the demo app is that the controller class shown here represents a sort of "bridge" between the Swing-specific code to talk to the JTextComponent instance and the purely business-oriented code in the Escaper class. One immediate implication of this is that you could provide a separate controller class entirely that works completely off of a command line (by prompting for a string as input via System.in and displaying the result via System.out) but still uses the exact same business logic in the Escaper class.

Other Thoughts

Other issues you should not forget are threaded tasks, IDEs, careful initialization, and multiple controllers.

Threaded Tasks

One area of development that always tends to cause grief is threading your long-running business tasks. On one hand, if you don't, the user interface goes into an unresponsive limbo state until the task finishes. On the other hand, if you aren't extremely careful, bad things happen. One major sticking point in a Swing app is this: The user interface elements should really only be updated from the "event dispatching thread," not from your own worker threads. The Swing library provides the static method SwingUtilities.invokeLater(...) to give your worker thread the ability to affect the user interface in a safe manner. However, even knowing you need to do this, it still can be troublesome to put this code in the right place. After all, when a lot of code and a lot of classes are flying around in your editor, your brain easily tends to associate methods in your JFrame class as all running in the event dispatch thread—this isn't true. Offloading the overhead into a controller class helps emphasize the separation, in my opinion (as does carefully documenting that some method is called from a worker thread.)

IDEs

I admit I would still rather hand-code a user interface (after sketching it on paper) than use any of the GUI builders I have tried to date, but those I have tried show common traits that makes a controller class design rather viable: Interface components have post-initialization hooks you can use to pass their reference to the controller class, and event handlers let you either directly connect with arbitrary methods or let you write a quick line of code to do the same. This being the case, once you create a minimal skeleton controller class (with empty methods), the IDE can help you even more rapidly connect user interface elements with those methods. Your UI and business logic can safely coexist with the autogenerated code.

Careful initialization

Take some care in your controller's action methods to check whether the user interface component references are null before you try to access them. If they are null, you either aren't setting them when the components were initialized, or the action methods are being called earlier than you think. This is, of course, a risk regardless of how your application is designed, but it bears noting here.

Multiple Controllers

Larger applications might benefit from the presence of more than one controller. You might have the main frame components managed by a separate controller from a dialog's controller, for example. In situations like these, any common behavior you might have between controller classes can be in a parent class. (Here is where use of factory and singleton patterns provide value over the more simple all-static patterns.)

Closing Remarks

I hope to have demonstrated another tool you can put in your application design toolbox while simultaneously touching on why the MVC approach is worth embracing. Feel free to download the files for this article to see the source code for yourself. Remember: This was a simple demonstration—a "hello world," if you will. However, if you have followed all the way to the end, surely you can already see how applicable it might be in the real world. Although I feel this technique provides a certain amount of architectural flexibility, I also know there is also no such thing as "one solution fits all." I leave it to the interested reader to judge the merits of this approach in their own projects.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel