Nice TWiki > Doc > CodeExamples > SwingLibraryExample TWiki webs:
Dev | Doc | Main | TWiki | Sandbox
Doc . { Changes | Index | Search | Go }
This example shows the way one can add and remove event listeners using the swing library. It uses new classes not present in cvs yet (See NiceGuiControlClasses? for more info on that). I'm at the moment adding a new layer to the swing library that consists of the following: For every Swing and AWT control (and some classes in java.beans) there is a class that inherits from it and has all possible actions as fields. This makes it possible to initialize the new class with all its actions using the (absolutely great) automatically generated constructor. Of course it is still also possible (in most cases) to provide the constructor with initialization values known from the according java class constructor. This is not alway possible (yet) since I don't know how to call a superclass's contructor with several arguments ????

The example also nicely shows how to use the Mediator pattern with Nice, which is (of course :-) in Nice easier to apply ! In Java what you normally do when you use this pattern is, that for every gui control in your program you must inherit a new class (e.g class QuitButton? extends JButton { ... } that instructs the mediator to execute its quit action. In Nice you don't need to specify this new class as shown in this example. All you do is define all eventhandling methods in the Mediator class and also store fields that keep references to those methods. Now whenever you want to add an action to a Gui Control, all you have to do is specify its name (e.g. mediator.blueColor) as a value for the named action parameter in the constructor call (or in one of the addXXXListener methods). Also you have to store references to all components needed by your eventhandling methods in order to do their work. This is normally done via a registerXXX method in the Mediator class. Typically the eventhandling methods inside the Mediator don't take any arguments, since they have all they need as fields in their enclosing class. Still it's sometimes useful to pass them arguments (although these should only be values that don't depend on a class, meaning they can easily be provided at call site (e.g. user input).

Working with a Mediator in the described way, also easily solves the problem where to store the function pointers to the eventhandling methods. They are needed when one wants to remove an eventhandling method from a Gui Component (e.g. button.removeActionsListener(actionPerformed: mediator.offGrayColor)) later on.

A boring fact is that the Mediator itself cannot easily be reused, since registered components (much more than eventhandling methods I guess ???) have to be specialized for every application (any improvement idea ? ideal would be a Mediator class inheriting from some base Mediator where it would be sufficient to just define all eventhandling methods and fields that reference them, but the problem arises with registered application components that are needed by the eventhandling methods). I thought about this for a long time already, but didn't come to a reasonable conclusion. My thoughts where leading to establishing a collection where the registered components are stored in, but then certain keys would have to be specified in order to get them out again. This would always lead to more complication when using those references inside the eventhandling methods. Anybody have other ideas ??? Writing Mediator code can become somewhat tedious (actually only the field declaration and registerXXX part) so it would be nice if we could improve here !!!

Here is general MediatorExplanation? (taken from the book "The Design Patterns Companion", by James W. Cooper, 1998).

package examples.buttons;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import nice.swing;


// --------------------------------------------------------------------------------------------

// Indications to the compiler about the precise types of some Swing features.
// The colors are not null:
Color blue() = native Color.blue;
Color gray() = native Color.gray;

var Mediator mediator = new Mediator(); 
  
class TestFrame extends NFrame
{
  init()
  {
    super;
          
    // switches background to blue
    NButton blueButton = new NButton
      (text: "BLUE",
       actionPerformed: mediator.blueColor
       );
    blueButton.init();
    
    // switches background to gray
    NButton grayButton = new NButton
      (text: "GRAY",
       actionPerformed: mediator.grayColor
       );
    grayButton.init();
    mediator.registerGrayButton(grayButton);    
    
    // switches off grayButtons action
    NButton offGrayButton = new NButton
      (text: "Switch off GRAY",
       actionPerformed: mediator.offGrayColor
       );
    offGrayButton.init(); 
    
    // create a new Panel and add the 2 buttons
    NPanel panel = new NPanel();
    panel.add(blueButton);
    panel.add(grayButton);
    panel.add(offGrayButton);
    mediator.registerPanel(panel);
    
    // add the panel to the contentPane of this frame
    ?java.awt.Container contentPane = this.getContentPane();
    if(contentPane != null) contentPane.add(BorderLayout.CENTER,panel);
     
    // set dimensions and show
    this.setSize(300,100);
    this.setLocation(100,100);
    this.show();
  }
}

class Mediator
{
  // fields to store references needed
  // by actions from other gui components
  private ?NPanel panel = null;
  private ?NButton grayButton = null;
  
  // fields to store references to eventhandling methods 
  // (for later removal and easier access)
  ActionEvent ?-> void blueColor = null;
  ActionEvent ?-> void grayColor = null;
  ActionEvent ?-> void offGrayColor = null;
    
  // methods to register needed gui components 
  void registerPanel(NPanel p) { this.panel = p; } 
  void registerGrayButton(NButton b) { this.grayButton = b; }  

  // eventhandling methods  
  
  void changeColor(Color c) 
  {
    ?NPanel panel = this.panel;
    if(panel != null) panel.setBackground(c);
  }
  
  void offButton(NButton button, ActionEvent ?-> void action) 
    = button.removeActionListener(actionPerformed: action);
    
  void init()
  {
    // initialize fields to store the eventhandling functions (for later removal)
    this.blueColor = (ActionEvent e) => mediator.changeColor(Color.blue);
    this.grayColor = (ActionEvent e) => mediator.changeColor(Color.gray);
    this.offGrayColor = (ActionEvent e) => mediator.offButton(notNull(this.grayButton), this.grayColor);

    // create and initialize the example frame  
    TestFrame frame = new TestFrame
      (title: "MyFrame",
       windowClosing: (WindowEvent e) => System.exit(0)
      );
    frame.init();
  }
} 

main(args)
{
  mediator.init();
}
-- GamsL - 20 Jul 2002 Martin, you should really put all the native color declarations in a file in the library, so they would not be needed in the programs (i.e. the begining of this example). Otherwise, this looks interesting. It seems I will have to learn more about design patterns, like your Mediator :-) -- DanielBonniot

Ok, I will do that ! (Actually I wanted to so before but forgot about it :-) Shall I follow your convention and make a java.nice in every package for this purpose ? or is it enough to make one for the whole lib ? -- GamsL - 23 Jul 2002

I made separate java.nice files for every package now. -- GamsL - 01 Aug 2002

I think one per package is good (if necessary), since it allows one to use for instance nice.awt only if you don't want Swing. A java.nice file has the advantage of keeping all these definitions in a single file, so one knows where to find them or to ignore them.

BTW, I also advise you to comment the Java 1.4 features (mouse wheels) with //JDK1.4 instead of just //. This will allow in the future to handle them automatically, for instance to generate a version of the lib for 1.4.

About the Mediator: I wonder if this is still needed in Nice. Some of the arguments (from the book) seem to apply to Java but not Nice. For instance that the mediator allows to add behaviour with changing the class. In Nice you could use multi-methods, and store the references in package variables instead of the Mediator. This is just my first thoughts, I would have to look more closely at the example and try to write it differently, but I lack the time badly... Comments?

-- DanielBonniot

Topic SwingLibraryExample . { Edit | Attach | Ref-By | Printable | Diffs | r1.1 | More }
Revision r1.1 - 30 Jan 2003 - 01:38 GMT - TWikiGuest
Parents: WebHome > CodeExamples
Copyright © 1999-2003 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback.