The Source for Java Technology Collaboration
User: Password:



Scott Violet

Scott Violet's Blog

Changes to Actions in 1.6

Posted by zixle on November 21, 2005 at 08:16 AM | Comments (15)

In my last two blogs I've covered various aspects of Actions. I had originally wanted to write about the changes to Actions in 1.6 but felt the background would make interesting blogs. I promise this is the last blog on Actions for a while;)

In 1.6 we've overhauled Actions adding new features and fixing a handful of annoying bugs. For this blog I'm going to cover the new features and when you might use them.

Action.SELECTED_KEY

The single biggest request for Actions was to add support for Actions to represent selected state. In particular when an Action is attached to a JRadioButton, JCheckBox, JToggleButton and the like there was no way to change the selected state of the component from the Action and have it reflected in the component. The new key Action.SELECTED_KEY takes care of that. All components that visually represent a selection will now listen for changes to the SELECTED_KEY and reflect that in the component.

The following code creates a JRadioButton from an Action that is initially selected:

  Action action = new MyAction();
  // Make the action selected. 
  action.putValue(Action.SELECTED_KEY, Boolean.TRUE);
  JRadioButton selectedRadioButton = new JRadioButton(action);
The SELECTED_KEY property is a bit different than other Action properties. In particular the SELECTED_KEY property is both read and set from the component; none of the other Action properties have this characteristic. For example, if the user clicks on the radio button to make it selected, the SELECTED_KEY property is set on the Action from the component.

The following example shows how an Action could customize it's behavior based on the selected state:

  class BoldAction implements Action {
    public void actionPerformed(ActionEvent e) {
      toggleBold((Boolean)getValue(Action.SELECTED_KEY));
    }
  }

Action.LARGE_ICON_KEY

All buttons and menu items have the ability to show an Icon. When a button or menu item is associated with an Action the button or menu item uses the Icon from the Action. This is problematic because typically you want two different icons for these two components. To address this in 1.6 we added LARGE_ICON_KEY. Menu items will only use the Icon from the SMALL_ICON property. Buttons will first look for the LARGE_ICON_KEY property, if it's value is non-null it will be used, otherwise the value from SMALL_ICON is used. This enables you to customize the Icon for the two different components.

The following example creates an Action with two different icons. The menu item will use smallIcon and the button largeIcon:

  Action action = new MyAction();
  action.putValue(Action.SMALL_ICON, smallIcon);
  action.putValue(Action.LARGE_ICON_KEY, largeIcon);
  // menu item will use smallIcon
  new JMenuItem(action);
  // button will use largeIcon
  new JButton(action);
Note: the term button is a bit overloaded. AbstractButton is the superclass of both menu items and classes such as JButton, JToggleButton, JRadioButton ... In this context when referring to button I mean all non JMenuItem subclasses that extend AbstractButton.

Action.DISPLAYED_MNEMONIC_INDEX_KEY

This is useful for the rare cases where you don't want the first occurence of a character in the text to be underlined. For example, a menu item with the text 'Save As' typically has the second 'a' underlined. The following code shows how to do this:

  Action action = new MyAction();
  action.putValue(Action.NAME, "Save As");
  // Notice the autoboxing here.
  action.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
  action.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY, 5);
  new JMenuItem(action);
Be careful when using DISPLAYED_MNEMONIC_INDEX_KEY. In particular if you change the mnemonic you should be sure you change the DISPLAYED_MNEMONIC_INDEX_KEY as well.

AbstractButton.setHideActionText

This property allows you to specify whether or not AbstractButton should show the NAME property from the Action as the buttons text. Consider if you have a menu item and toolbar button attached to the same Action. To have non-empty text on the menu item the Action will have a non-null value for it's NAME property. If you don't want the toolbar button to show the text you would invoke setHideActionText(true). The following code illustates this:
  Action action = new MyAction();
  action.putValue(Action.NAME, "Save As");
  new JMenuItem(action);
  JButton toolbarButton = new JButton(action);
  // We don't want the button to mirror the text from the Action.
  toolbarButton.setHideActionText(true);

System property swing.actions.reconfigureOnNull

The beans specification indicates that a null property name can be used to indicate multiple values have changed. By default Swing components that take an Action do not handle such a change. To indicate that Swing should treat null according to the beans specification set the system property swing.actions.reconfigureOnNull to the String value true.

This property is useful for cases where you want to do a bunch of changes to an Action without sending individual property changes, and then have all listeners refetch properties when done. I honestly can't say I have ever had a need for this functionality, but it's now there.

The javadoc for Action now details all this information as well as how the various components support the different Action properties.

As usual, if you want to try out these changes (and the rest of the goodness in 1.6) download the source and binaries from mustang snapshot release.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Very nice additions to the API,I must say.
    Having said that, I must add thataction.put(Action.SELECTED_KEY,Boolean.TRUE); is rather unnecessary.The other Action properties you have added, either change the aesthetics or provide a hint to the JComponent using this Action, about how it should render this Action.That is fine.In fact it's perfect and more elegant than the SWT initialization APIs,that have pipes all over the place. However the propertyselected conveys a state, and state IMHO is best manipulated via setter/getter methods.

    Posted by: swapnonil on November 21, 2005 at 11:10 AM

  • swapnonil,
    I agree that a setter/getter would be preferable for selected. The downside is that as Action is an interface it can't be changed. The other option of adding an entirely new interface just for selected seemed like overkill. Hence the property.

       -Scott

    Posted by: zixle on November 21, 2005 at 11:19 AM

  • Will there be any issue using DISPLAYED_MNEMONIC_INDEX_KEY with localized application?

    Posted by: woongiap on November 21, 2005 at 07:24 PM

  • woongiap,
    No more than usual. By default the DISPLAYED_MNEMONIC_INDEX_KEY is set for you when you change the title/mnemonic. If you want to change the DISPLAYED_MNEMONIC_INDEX_KEY independently you could always localize it.

       -Scott

    Posted by: zixle on November 22, 2005 at 05:53 AM

  • Would Action.SELECTED_KEY allow for actions with more than two states? I have always felt the need to have three-state components (radiobuttons and checkboxes with undefined --gray, or intermediate-- states), and in fact I have implemented some of them, unfortunately without support for actions.

    Posted by: irivera on November 22, 2005 at 06:20 AM

  • irivera,
    As Swing doesn't support tri-state buttons yet, Action doesn't either. When we enable tri-state buttons we'll update actions appropriately.

        -Scott

    Posted by: zixle on November 22, 2005 at 08:52 AM

  • Hi Scott, these look like a lot of good changes.

    One question I had was on setHideActionText -- since the property hidden is "NAME", shouldn't the method on AbstractButton be setHideActonName? To me, it'd be easier to make the connection.

    Posted by: erickson on November 22, 2005 at 11:20 AM

  • erickson,
    It turns out AbstractButton has always supported a client property with the name 'hideActionText' to give this effect. When I added the property I figured it's best to keep it consistant with the name of the client property.

       -Scott

    Posted by: zixle on November 22, 2005 at 01:33 PM

  • Hi Scott.

    Glad to see Actions getting some attention. I recently contributed a java.net project called SAM - the Swing Action Manager that has some of these features (and more), including the Action.SELECTED_KEY and the hideActionText. It's great to see these in the JDK, I just want to let people know they can have something like them in 1.4 using SAM.


    On the interface question, SAM uses properties for every feature too, so it works for any Action, but it also includes a BasicAction that wraps the properties with methods for convenience.


    Aren't tri-state buttons just enabled+selected?


    I'll update SAM "real soon" to make it consistent with these changes.

    Posted by: michaelbushe on November 22, 2005 at 03:19 PM

  • I am curious why the Action interface doesn't conform to the JavaBeans model in the accessor/mutator portion of the interface. Why use getValue(key) and putValue(key, value) rather than getText()/setText(String), getSelected(), setSelected(boolean).

    Aren't you exposing an implementation detail that these attributes and their values are probably implemented in a hash table/dictionary?

    Why is the attribute "enabled" different (e.g it has the normal get/set methods)?

    Posted by: libra67 on December 03, 2005 at 10:44 AM

  • libra67,

    Excellent questions. I am not the original author of Action, so I can only speculate on some of these. Here's my best guesses:

    The disadvantage of having specific setters/getters for an interface like this is that we would not have been able to compatibility rev it. For example, if there were no getValue(key) we could not add LARGE_ICON_KEY. Instead we would have to add a new interface for the new methods. This is obviously painful and does not scale well.

    Enabled is a bit odd. I suspect the rationale for making it a real property is that all places that use an Action need the enabled state. That is not true of the other properties.

       -Scott

    Posted by: zixle on December 05, 2005 at 01:16 PM

  • Scott,

    you described the mnemonic stuff like this

    For example, a menu item with the text 'Save As' typically has the second 'a' underlined.

    but then the code does it like this


    action.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY, 5);


    then you offer the warning
    Be careful when using DISPLAYED_MNEMONIC_INDEX_KEY. In particular if you change the mnemonic you should be sure you change the DISPLAYED_MNEMONIC_INDEX_KEY as well.

    Is it just me, or do others notice a cognitive dissonance here?

    If you want the second 'a' to be the underlined letter, why not pass 2 as the argument rather than 5 (or 1 if you want it zero based)?
    The default is to underline the first occurance of the mnemonic, not the first letter, so why does the explicit method take a string index rather than an occurance of the letter?

    It looks like the implementation is defining the form of the API, rather than the other way around.

    Posted by: brucechapman on December 11, 2005 at 08:02 PM

  • brucechapman,

    If you want the second 'a' to be the underlined letter, why not pass 2 as the argument rather than 5 (or 1 if you want it zero based)?
    The value for DISPLAYED_MNEMONIC_INDEX_KEY indicates the index of the character to underline in the text, not the index of that occurence of the character. This means you could do something completely odd like specifying a mnemonic of 'a', but underlining 'o'.

    It looks like the implementation is defining the form of the API, rather than the other way around.

    I agree this seems a bit odd, but this is the way JLabel and AbstractButton have dealt with underlining different characters and I would not want Action to be different.

       -Scott

    Posted by: zixle on December 12, 2005 at 02:06 PM

  • Scott,

    just for selected seemed like overkill

    I disagree with the "just" :-) It has considerable conceptual weight by mixing in a property that's often bound to a domain model, so I started/jumped into discussion

    http://forums.java.net/jive/thread.jspa?threadID=12734&tstart=0
    http://forums.java.net/jive/thread.jspa?threadID=2450&tstart=0

    Cheers, Jeanette

    Posted by: kleopatra on February 03, 2006 at 05:05 AM

  • Scot,
    If my Action has mnemonic key, and I don't wan't to change the action, but I wan't that my button's mnemonic will be disable.
    How can I do that?

    -Amir

    Posted by: amirlevy on March 08, 2007 at 01:54 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds