Submitted On 18-NOV-1998
rmaddy
We are currently working on a solution to this issue since we need Action based
Toggle buttons, radio button menus, and checkbox menus too. Our solution is in
design but includes a new interface deriving Action. This adds some new
constants like SELECTED and GROUP. We dervived a new class from AbstractAction
that implements our new interface. All our actions derive from our new
abstract action class. We are extending JButton, JToggleButton, JMenu,
JToolBar, JCheckBoxMenuItem, and JRadioButtonMenuItem to take our action
interface. our JMenu, JToolBar and JRadioButtonMenuItem will check for the
GROUP value. If found it will create a JRadioButtonMenuItem or JToggleButton
as appropriate and associate it with the ButtonGroup. If no GROUP it will look
for SELECT. If found it will create a JCheckBoxMenuItem or JToggleButton as
appropriate. All these will have proper property change listeners and state
change listeners to react to Action changes and state changes.
Submitted On 16-FEB-2000
bodnej
I just tried to make the changes suggested by Raviola in the duplicate of this
bug and they are impossible, due to Sun declaring the method
registerMenuItemForAction in JMenu private. If it was protected, there would
be no problem, but the private method isn't visible to any subclass, and it's
that private method which connects the internally created JMenuCheckboxItem
with the Action. The field which registerMenuItemForAction modifies
(listenerRegistry) is also declared private, so you can't modify it from the
subclass.
It's a shame, because the solution would have been so easy, but Sun made a
mistake in the OO design for the JMenu.
Submitted On 22-FEB-2000
dougbell
It would be fairly easy to implement this myself and add
support to JToolbar EXCEPT that the
JToolbar.ActionChangedListener class is private and can't be
extended to handle other properties, such as a toggle state.
Further, JToolbar allows for overriding the
createActionChangeListener() method to instantiate a
different PropertyChangeListener, but the JToolbar.remove()
method is hard-coded to expect a
JToolbar.ActionChangedListener. Since you can't extend the
private JToolbar.ActionChangedListener, you can only extend
the property handling if you also override remove() to
remove the dependence on JToolbar.ActionChangedListener.
But you can't override remove() to remove the dependency,
because the static listenerRegistry Hashtable is also
private.
Really, JToolbar needs to be fixed. The minimum change
would be to make JToolbar.ActionChangedListener a protected
class.
Submitted On 19-MAY-2000
ralkire
protected JMenu.createActionComponent assumes that the component must be a JMenuItem, which precludes
the use of all other components. Also the Action class has no built in support for providing information to the
method which type of component is desired. Please fix this problem by creating a new pair of fields for the Action
class that specify the class to instanciate for toolbar buttons, and menu items. In this way, classes created
outside the JDK can also be created. This enables XML specified menu and toolbar items to be created supporting
generic actions that are not possible otherwise.
Submitted On 11-APR-2001
dstuart
When I first saw Actions, I was pleased and thought "oh
cool, now I don't have to do manual synchronization".. but
unfortunately this is useless to me without the
togglebutton and radio button behaviors as described. We
have lots of things that could benefit from it, but we
won't move until this is addressed..
Submitted On 11-APR-2001
dstuart
I've actually patched swing in our development environment
to achieve this for (at least) JToggleButtons and
JCheckboxMenuItems.
Feel free to contact me via e-mail if you want the patch..
(limit 1 per customer!)
Submitted On 02-NOV-2001
gfaron
It seems to me that the private inner-class
AbstractButton.ButtonActionPropertyChangeListener could
have the following "else if" clause inserted into its
propertyChange(PropertyChangeEvent) method and the issue
would be fixed (together with the code that the orignal
poster provided above).
// This clause is already present in the method.
else if (propertyName.equals("enabled"))
{
Boolean enabledState = (Boolean) e.getNewValue();
button.setEnabled(enabledState.booleanValue());
button.repaint();
} // ends else if
// Add this clause here.
else if (propertyName.equals("selected"))
{
Boolean selectedState = (Boolean) e.getNewValue();
button.setSelected(selectedState.booleanValue());
button.repaint();
} // ends else if
Submitted On 07-DEC-2001
gfaron
I have a fix for this one, but the CGI page is not
allowing me to post it. Please e-mail for the fix (mention
4133141 in the subject as well).
Submitted On 24-OCT-2002
joneshJ
gfaron seems to have the simplest fix for the problem (as
described).
I worked around the problem by creating an Action subclass
with isSelected/setSelected methods and firing a "selected"
PropertyChangeEvent.
Then you have to override JCheckBoxMenuItem and
JToggleButton to implement the method
createActionPropertyChangeListener which handles
the "selected" property properly.
Submitted On 20-MAR-2003
risadinha
My Workaround:
Use one ButtonModel for all Buttons with the same Action.
The reference of the ButtonModel can be stored in the action
such that when creating a button the button model can be set
in a second step:
ButtonModelAction action = new ButtonModelAction();
AbstractButton b = new WhateverAbstractButton(action);
b.setModel(action.getButtonModel());
The adventage is, that disabling, arming etc. can be done
through the model, as well. If the state of the buttons
depends on a table or tree selection, the model can change
state according to this selection and all buttons will adopt
apropriately.
Submitted On 11-DEC-2003
christopher_j_nielsen
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
///////////////////////////////////////////////////////////////////////////
// Simple extension to AbstractAction, to
support "togglable" actions
// (JCheckBoxMenuItem, JRadioButtonMenuItem, etc.)
///////////////////////////////////////////////////////////////////////////
public abstract class MyAbstractAction
extends AbstractAction
{
// Called when it is time for us to update
our enabled state
// (we should also obtain any state
necessary for toggle state,
// obtained via 'isSelected()' method).
//
// NOTE: this code should run as quickly as
possible, otherwise
// user will notice a delay before menu is
displayed!
public void update()
{
}
// For check box and radio button menu
items -- return TRUE if
// item should be toggled 'ON', FALSE
otherwise. For
// non-togglable items, there is no need to
override this method.
public boolean isSelected()
{
return(false);
}
abstract public void actionPerformed
(ActionEvent evt);
}
///////////////////////////////////////////////////////////////////////////
// Class to dynamically update menu items at popup
time (similar to MFC)
// via an extended AbstractAction.
///////////////////////////////////////////////////////////////////////////
public class MyAbstractActionUpdater
implements PopupMenuListener
{
// Recursively attach ourselves as a
PopupMenuListener, to the passed-
// in element and all popup submenus.
public void attach( MenuElement
menuElement )
{
if ( menuElement instanceof
JMenu )
{
JPopupMenu
popupMenu = ((JMenu) menuElement).getPopupMenu
();
popupMenu.addPopupMenuListener(this);
}
attach(
menuElement.getSubElements() );
}
public void attach( MenuElement
menuElementArray[] )
{
int nCount =
menuElementArray.length;
for ( int i = 0 ; i < nCount ; i++ )
attach(
menuElementArray[i] );
}
// Update the state of all items in a given
popup menu, just before
// the menu is displayed.
//
// Note that we are only concerned with top-
level items in this
// popup menu -- submenu popups are
handled only when they are
// ready to become visible.
public void popupMenuWillBecomeVisible
(PopupMenuEvent evt)
{
JPopupMenu popupMenu =
(JPopupMenu) evt.getSource();
MenuElement itemArray[] =
popupMenu.getSubElements();
int nCount = itemArray.length;
MenuElement genericItem;
JMenuItem item;
Action genericAction;
MyAbstractAction action;
for ( int i = 0 ; i < nCount ; i++ )
{
genericItem =
itemArray[i];
if ( genericItem
instanceof JMenuItem )
{
item =
(JMenuItem) genericItem;
genericAction = item.getAction();
if (
genericAction != null
&& (genericAction instanceof
MyAbstractAction) )
{
action = (MyAbstractAction) genericAction;
// First update the action state, then set the
// 'selected' status of menu item based on
action.
action.update();
item.setSelected( action.isSelected() );
}
}
}
}
public void popupMenuWillBecomeInvisible
(PopupMenuEvent evt)
{
}
public void popupMenuCanceled
(PopupMenuEvent evt)
{
}
}
Submitted On 11-DEC-2003
christopher_j_nielsen
I agree with this request -- I too have had to come up
with a workaround to ensure that all Action-related
code remains clean, when dealing with 'togglable'
actions.
My solution entails dynamically updating menu state
on-the-fly, just before a menu popup is shown. I will
post the code in short order.
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|