Product \ Actions

API Code Example

The Action framework is meant to make Swing programming a lot easier and more responsive at the same time. Any programming book for Swing will tell you that you need to do long running actions in a seperate thread since those calculations would otherwise mean nothing is being redrawn on screen, creating an application that responds too slow to user action.
This created the problem that thread programming is hard to do correctly and you can use your time doing better things then trying to debug threading problems.

Using the Actions framework described bere will solve that problem for you, and at the same time solve a lot of problems that Swings event based system currently has.

Features include:

 

The Action framework really exists of several different technologies you can use seperately from each other for an easy learning curve. The framework, and the rest of the UICollection parts work together fluently so you may find yourself being an expert before you know it.

Old style events, whats wrong with them?

Programming for Swing means you will have to handle button presses and selection changes in lists etc. Using the basic Swing API you have to create a new class, called an Event Listener which you then add to the widget you want to listen to. Here is an example for a way to update a label with a new value as the user drags a slider.

  public class Example extends JPanel {
    protected JSlider slider;
    protected JLabel textLabel;
    public Example() {
        super( new VerticalLayout(11, 6) );
        textLabel = new JLabel();
        slider = new JSlider(SwingConstants.HORIZONTAL, 0, 100, 0);
        add(textLabel);
        add(slider);

        // *** actions ***
        slider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                int value = ((JSlider) e.getSource()).getValue();
                if(value < 25)
                    textLabel.setText("Small");
                else if(value < 75)
                    textLabel.setText("Medium");
                else
                    textLabel.setText("Large");
            }
        });
    }
  }

The example adds an inner class using the code new ChangeListener() { ... } and overrides the method stateChanged following the API doc of the ChangeListener interface. The effect is that the method will be called with a new Event object every time the user drags the slider a little.

This framework, but also the SwingWorker and various other tools solve at least the first problem to do with slow repaints by creating a new thread for the handler and make sure your code is called in that other thread. Earlier solutions just created one thread for each action that came in and let that thread die as soon as its action was completed. This creates some problems since the order in which threads are executed is quite random and you might up saving your document before that last change in he document has been processed.

The newer solutions all create a queue, to execute each action in the order of which the user executed the action. So the user changing the slider and just a bit later pressing a save button is guarenteed that the actions based on the slider change is executed before the save action is being executed.

What would be the perfect solution is a methodology to place the user event in a queue and then when its turn comes to call a handler I programmed, and do that in a different thread to allow repaints while I calculate. The handler can be a method in my class since that would be usefull to do the initialisation or unit-testing of that handler. To top it off; I'd like to have the method be called with the integer 'value' instead of the event so I don't have to cast the event source to a JSlider.
Good times; This framework allows all of these.

Other queued threading options, whats wrong with them

Having a queue of actions can have some unexpected effects. The simplest to imagine is that when a slow action is being handled it will then take a while to start handling actions that have been added later, since they are executed in order. Imagine a user pressing a button and then starting to play with the slider from our Example. The button takes 3 seconds to finish its work and in that time the user has dragged and created some 50 events with changes.

The Action framework solves all of these, and plenty more; see the links at the top for more. Here is what the updated example would look like using actions:

  public class Example extends JPanel {
    protected JSpnner spinner;
    protected JLabel textLabel;
    public Example() {
        super( new VerticalLayout(11, 6) );
        textLabel = new JLabel();
        spinner = new JSpnner();
        add(textLabel);
        add(spinner);

        // *** actions ***
        new JSpinnerChangeAction(this, "spinnerUpdateSlot").add(spinner);
    }
    private void spinnerUpdateSlot(int value) {
        if(value < 25)
            textLabel.setText("Small");
        else if(value < 75)
            textLabel.setText("Medium");
        else
            textLabel.setText("Large");
    }
  }