I am working on one of my first bigger Swing applications and encounter an unexpected but nasty problem. My application consist of several panels which all of them contain some controls, among them buttons. Most of the simple learning-book examples use anonymous listener classes to add some functionality to a button:
For a panel with many buttons, the code becomes large and messy, besides it is not possible to attach an action to several components. Here the Action interface comes in:
For each action I have created such a CustomAction class. This works fine as long as the business method called in actionPerformed does not need any state data from the various GUI components. But if it does, a problem arises because no information can be passed to the actionPerformed method (except for the ActionEvent, but this event object does not give me any way to access the GUI components except for the event source).
I see the following 2 solutions to this problem:
1. Make all CustomAction classes private inner classes of the panel class, so having access to all its GUI components. 2. Use a PanelCallback interface defining getter methods for all data I want to retrieve from my panel. This interface can be passed to the CustomAction contstructor together with the BusinessController object.
Option 1 will definitely work but still makes the main class very large. Option 2 gives smaller Panel classes but requires a separate Guicallback interface for each Panel
An additional issue is that I want to be able to enable/disable actions from within the GUI or from within other actions. This means that I must have access to all actions. FOr this purpose, I use an ActionFactory class holding a Map with the CustomAction class as a key and the action CustomAction object as a value:
Though this appears to work, it all seems over-complicated to me ! Do I overlook someting ? I would like to get some feedback to my solutions... TIA, Klaas
[ August 12, 2005: Message edited by: Klaas van Gelder ] [ August 12, 2005: Message edited by: Klaas van Gelder ]
"What you don't know, can't help you"
SCJP (81%), SCWCD (81%), SCJD (354/400), SCBCD (85%)
Klaas van Gelder
Joined: Jul 08, 2004
Uhhh.. no reactions yet :-( I choosed to use named inner classes only for the Swing actions. This saves a lot of the overhead needed for using outer classes for the Actions.
Actions and dependencies are a core issues that developers run into. There isn't a perfect/easy answer to this. It really depends on your app. You seem to be going down the right road with an action factory. I would extend that concept further by having an action registry with one instance of each action. The various buttons you have should all be able to share once instance of an action in the majority of your cases. Getting back to dependencies ... as you mentioned you can use private inner classes. However, this will cause things to get messy quite quickly. I'll admit the other option of passing in a callback interface can get overwhelming as well. At this point your are getting into a core dependencies issue not just a UI issue. There are a number of ways to help reduce this dependency burden. I would recommend looking at Martin Fowler's dependency injection article for ideas:
Dependency injection might be overkill for your project. However, a service locator might help separate out your dependencies better. Another option is to make your application more message based. You can use a JMS implementation like Somnifugi or Werx2 to make a message bus. Then your components can send an event throught the bus which the actions can respond to. The actions can then perform some work and respond on the bus. The components can listen to this message and act accordingly. So you can have the two working together without tight coupling. Finally you should take a look at the following Java.net actions project.