O'Reilly logo

Swing Hacks by Chris Adamson, Joshua Marinacci

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

490
|
Chapter 12, Miscellany
#97 Mirror an Application
HACK
Put all of this together, with the following main( ) method, and then fire up
two copies of your program. The first one will wait for a connection. When
the second one starts, it will send every mouse event over the network to the
first copy, which will then reuse it. If you click on the button in the second
window, you will see the button depress in the first.
public static void main(String[] args) throws Exception {
ApplicationMirrorTest mirror = new ApplicationMirrorTest( );
mirror.start( );
}
Component Problems
Wait...did this work? No, it didn’t. The events still don’t work after being
sent over the network. A little debugging will show that every part of the
reconstituted event works properly except for the
getComponent( ) method,
which returns
null. Why?
The reference to the component doesn’t get sent over the wire because that
would require sending the component itself. That component, of course, is
part of your entire Swing tree, which would also have to be sent over. Pretty
soon you’d be sending a few megabytes through the network for every event.
To avoid this, the developers of Java made the component reference tran-
sient, which means the object will be skipped during serialization. That
makes the component fast, but it presents a problem: how do you know
which component the event goes with?
When you think about it, you wouldn’t really want the actual component in
the other program anyway. You already have a component on the receiving
instance that’s showing on screen. You just need to associate the event with
the correct component from the sending instance, and match that with the
correct component in the receiving instance. Fortunately, every Swing com-
ponent can have a name attached to it. If both programs use the same names
(which they will since they are just different instances of the same code),
then you can build a
HashMap to keep track of them all. Example 12-19 takes
care of these details.
Example 12-19. Associating events with components via the component name
public class ComponentMap extends HashMap implements AWTEventListener {
public ComponentMap( ) {
Toolkit tk = Toolkit.getDefaultToolkit( );
tk.addAWTEventListener(this,
AWTEvent.COMPONENT_EVENT_MASK);
}
Mirror an Application #97
Chapter 12, Miscellany
|
491
HACK
ComponentMap is a subclass of HashMap, and it adds one key feature. It listens
for component events system-wide and stores the components in its
HashTable with the component name as the key. Now, instances can look up
components using
ComponentMap. Of course, this means you need to name all
of your components. By default, subclasses of
JComponent will have a null
value for getName( ), so you need to set these names explicitly:
Map component_map;
public ApplicationMirrorTest( ) {
component_map = new ComponentMap( );
JFrame frame = new JFrame( );
frame.getContentPane().setLayout(new FlowLayout( ));
final JButton button = new JButton("action generator");
button.setName("button");
frame.getContentPane( ).add(button);
JTextField tf = new JTextField("text field");
tf.setName("textfield");
frame.getContentPane( ).add(tf);
frame.pack( );
frame.show( );
}
The new version of the ApplicationMirrorTest, which uses all of this new
code, creates a
ComponentMap to track names, and then sets a name for each
component as it’s created. Once you have the lookup map, you can modify
the sending loop in
openSender( ) to send the component’s name before it
sends the event:
if(evt instanceof MouseEvent) {
MouseEvent me = (MouseEvent)evt;
public void eventDispatched(AWTEvent evt) {
try {
// p("evt = " + evt);
ComponentEvent ce = (ComponentEvent)evt;
// p("storing component: " + ce.getComponent().getName( ));
this.put(
ce.getComponent().getName( ),
ce.getComponent( )
);
} catch (Exception ex) {
// p("ex: " + ex);
}
}
}
Example 12-19. Associating events with components via the component name (continued)

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required