Submitted On 15-APR-2002
krunkle
For JButton and JToggleButton:
These are the only 2 button types I used but this should work for other buttons too...For all JButtons, I did
a setUI(MyButtonUI) and for all JToggleButtons I did a setUI(MyToggleButtonUI). The code for those is:
public class MyToggleButtonUI extends MetalToggleButtonUI {
protected BasicButtonListener createButtonListener(AbstractButton b) {
return new MyButtonListener(b);
}
}
public class MyButtonUI extends MetalButtonUI {
protected BasicButtonListener createButtonListener(AbstractButton b) {
return new MyButtonListener(b);
}
}
The code for MyButtonListener is listed below. Again, I only had to change mousePressed to check for focus
before arming the Button
:
public class MyButtonListener extends BasicButtonListener {
public MyButtonListener(AbstractButton b) {
super(b);
}
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
AbstractButton b = (AbstractButton) e.getSource();
if (b.contains(e.getX(), e.getY())) {
ButtonModel model = b.getModel();
if (!model.isEnabled()) {
// Disabled buttons ignore all input...
return;
}
if (!b.hasFocus()) {
b.requestFocus();
}
//System.out.println("has focus" + b.hasFocus());
if (!b.hasFocus()) return;
if (!model.isArmed()) {
// button not armed, should be
model.setArmed(true);
}
model.setPressed(true);
}
}
}
}
Submitted On 15-APR-2002
krunkle
If you are still looking for a workaround in the meantime....see the comments of bug 4302322 or...
I had to work around this bug for a GUI I developed and here's what I did.
I had to subclass BasicMenuUI, MetalComboBoxUI and BasicButtonListenerUI (along with MetalButtonUI and
MetalToggleButtonUI)
For JMenu:
I had to setUI(MyMenuUI) for each JMenu I was using so that the menu would not popup if my input verifier
returned false. The only change I had to make to BasicMenuUI was to check for focus in the mousePressed
method before allowing the menu to popup. Here's the code I used for MyMenuUI...
public class MyMenuUI extends BasicMenuUI {
protected MouseInputListener createMouseInputListener(JComponent c) {
return new MouseInputHandler();
}
private class MouseInputHandler implements MouseInputListener {
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {
JMenu menu = (JMenu)menuItem;
if (!menu.isEnabled())
return;
if (!menu.hasFocus()) {
menu.requestFocus();
}
if (!menu.hasFocus()) return;
MenuSelectionManager manager =
MenuSelectionManager.defaultManager();
if(menu.isTopLevelMenu()) {
if(menu.isSelected()) {
manager.clearSelectedPath();
} else {
Container cnt = menu.getParent();
if(cnt != null && cnt instanceof JMenuBar) {
MenuElement me[] = new MenuElement[2];
me[0]=(MenuElement)cnt;
me[1]=menu;
manager.setSelectedPath(me);
}
}
}
MenuElement selectedPath[] = manager.getSelectedPath();
if(!(selectedPath.length > 0 &&
selectedPath[selectedPath.length-1] ==
menu.getPopupMenu())) {
if(menu.isTopLevelMenu() ||
menu.getDelay() == 0) {
MenuElement newPath[] = new MenuElement[selectedPath.length+1];
System.arraycopy(selectedPath,0,newPath,0,selectedPath.length);
newPath[selectedPath.length] = menu.getPopupMenu();
manager.setSelectedPath(newPath);
} else {
setupPostTimer(menu);
}
}
}
public void mouseReleased(MouseEvent e) {
JMenu menu = (JMenu)menuItem;
if (!menu.isEnabled())
return;
MenuSelectionManager manager =
MenuSelectionManager.defaultManager();
manager.processMouseEvent(e);
if (!e.isConsumed())
manager.clearSelectedPath();
}
public void mouseEntered(MouseEvent e) {
JMenu menu = (JMenu)menuItem;
if (!menu.isEnabled())
return;
MenuSelectionManager manager =
MenuSelectionManager.defaultManager();
MenuElement selectedPath[] = manager.getSelectedPath();
if (!menu.isTopLevelMenu()) {
if(!(selectedPath.length > 0 &&
selectedPath[selectedPath.length-1] ==
menu.getPopupMenu())) {
if(menu.getDelay() == 0) {
MenuElement newPath[] = new MenuElement[selectedPath.length+2];
System.arraycopy(selectedPath,0,newPath,0,selectedPath.length);
newPath[selectedPath.length] = menuItem;
newPath[selectedPath.length+1] = menu.getPopupMenu();
manager.setSelectedPath(newPath);
} else {
manager.setSelectedPath(getPath());
setupPostTimer(menu);
}
}
} else {
if(selectedPath.length > 0 &&
selectedPath[0] == menu.getParent()) {
MenuElement newPath[] = new MenuElement[3];
// A top level menu's parent is by definition
// a JMenuBar
newPath[0] = (MenuElement)menu.getParent();
newPath[1] = menu;
newPath[2] = menu.getPopupMenu();
manager.setSelectedPath(newPath);
}
}
}
public void mouseExited(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
JMenu menu = (JMenu)menuItem;
if (!menu.isEnabled())
return;
MenuSelectionManager.defaultManager().processMouseEvent(e);
}
public void mouseMoved(MouseEvent e) {
}
}
}
Submitted On 15-APR-2002
krunkle
For JComboBox:
For all JComboBoxes I did a setUI(MyComboBoxUI). You also need MyButtonListener for this one too (see
createArrowButton) and I also changed InvocationMouseHandler's mousePressed method. See code below:
public class MyComboBoxUI extends MetalComboBoxUI {
protected ComboPopup createPopup() {
return new MetalComboPopup( comboBox );
}
public JComboBox getcomboBox() {
return comboBox;
}
protected JButton createArrowButton() {
JButton button = new MetalComboBoxButton( comboBox,
new MetalComboBoxIcon(),
comboBox.isEditable() ? true : false,
currentValuePane,
listBox ) ;
button.setMargin( new Insets( 0, 1, 1, 3 ) );
button.setDefaultCapable(false);
button.setUI(new MetalButtonUI() {
protected BasicButtonListener createButtonListener(AbstractButton b) {
return new MyButtonListener(b);
}
});
return button;
}
public class MetalComboPopup extends BasicComboPopup {
public MetalComboPopup( JComboBox cBox ) {
super( cBox );
}
protected MouseListener createMouseListener() {
return new InvocationMouseHandler();
}
protected class InvocationMouseHandler extends MouseAdapter {
public void mousePressed( MouseEvent e ) {
Rectangle r;
if ( !SwingUtilities.isLeftMouseButton(e) )
return;
if ( !comboBox.isEnabled() )
return;
if (!arrowButton.hasFocus()) return;
togglePopup();
}
public void mouseReleased( MouseEvent e ) {
Component source = (Component)e.getSource();
Dimension size = source.getSize();
Rectangle bounds = new Rectangle( 0, 0, size.width - 1, size.height - 1 );
if ( !bounds.contains( e.getPoint() ) ) {
MouseEvent newEvent = convertMouseEvent( e );
Point location = newEvent.getPoint();
Rectangle r = new Rectangle();
list.computeVisibleRect( r );
if ( r.contains( location ) ) {
updateListBoxSelectionForEvent( newEvent, false );
comboBox.setSelectedIndex( list.getSelectedIndex() );
}
hide();
}
hasEntered = false;
stopAutoScrolling();
}
}
}
}
Hope these help for now......They worked for me.
Submitted On 08-SEP-2002
vesely99
Since work is in progress for enhancing it, might one ask for
- no InputVerifier class, since an interface is enough,
- one more parameter, to learn which component it was?
Submitted On 17-OCT-2002
markusmenner
Sun, please, please solve this problem, it's urgent ...
Submitted On 30-OCT-2002
DReese
How is this considered to be an enhancement, and not a bug?
The Swing documents describes the InputVerifier as follows:
The purpose of this class is to help clients support smooth
focus navigation through GUIs with text fields. Such GUIs
often need to ensure that the text entered by the user is
valid (for example, that it's in the proper format) before
allowing the user to navigate out of the text field. To do
this, clients create a subclass of InputVerifier and, using
JComponent's setInputVerifier method, attach an instance of
their subclass to the JComponent whose input they want to
validate. Before focus is transfered to another Swing
component that requests it, the input verifier's
shouldYieldFocus method is called. Focus is transfered only
if that method returns true.
This is not how the class behave. It's a bug.
Submitted On 21-NOV-2002
wille1234
I consider the current behaviour a bug, since it renders
InputVerifier useless.
Stefan
Submitted On 02-JAN-2003
ragnor
InputVerifier would be infinitely more useful if you could
determine the opposite component like you get in a
FocusEvent. For example, on a entry form, you might want to
allow a uset to hit a CANCEL button without validating the
input in the current field.
Using focus listeners to do this are messy, as your only
choice to bring focus back is requestFocus(), which brings up
problem cases like the validation failing on the component
that briefly recieves focus.
The event that caused the focus change would be extremely
useful as well. For example, mouse event, tab, shift tab, etc.
In our application, we would like to allow the user to back up
(shift tab) on a failed validation to correct a field you are
dependant upon, but not go forward.
As it stands, the only option to have a good, working
validation system is to write your own focus manager to do it.
Perhaps in the next JDK release this could be corrected.
Submitted On 08-MAR-2003
unipax
Any kind of input must be validated, not only that from a
text field, radio button and check box, combo box and list
field, and any other input from the user may be valid or not
for the particular application context.
To control all the user GUI interaction is a must.
If InputVerifiers is not the solution find one, but once for
all.
Submitted On 26-AUG-2003
sebastiankirsch
If I'm right, there' s really simple work-around for this bug.
For example, if you wan't to prevent executing ActionEvents,
just do the following:
public void actionPerformed(ActionEvent actionEvent) {
JComponent c = (JComponent) actionEvent.getSource();
if (c.getVerifyInputWhenFocusTarget())
if (!c.requestFocusInWindow())
return;
// your handling code
}
This should just work fine. If you use awt components (which
should occur seldom, as inputverifiers are for JComponents
only), just check if the source is an instance of
JComponent, too.
This is not the best solution, as the actions are fired
nethertheless. But yo don't need to replace the JDK-classes.
Sebastian Kirsch
Submitted On 26-AUG-2003
sebastiankirsch
What's more, with the c.getVerifyInputWhenFocusTarget() you
can have cancel buttons that are ignore the InputVerifiers.
- It seems like some didn't knew of this property.
Sebastian
Submitted On 26-AUG-2003
sebastiankirsch
It seems like >c.requestFocusInWindow()< returns false even
if the component already has the focus...
So it is better to use this code:
public void actionPerformed(ActionEvent actionEvent) {
JComponent c = (JComponent) actionEvent.getSource();
if (c.getVerifyInputWhenFocusTarget()) {
c.requestFocusInWindow();
if (!c.hasFocus())
return;
}
// handling code
}
Submitted On 09-SEP-2003
boldue
Of course this is a bug. The whole reason for using an
InputVerifier is to (bear with me here) verify input! This
means the user cannot leave the field until the input verify is
satisfied or they choose a field that does not cause the input
verifier to be fired. As it stands, clicking on any field that has
a popup window is a simple way for users to by-pass the
input verifier thus rendering it absolutely useless for its
intended purpose. This can be fixed with custom coding, but
what good is a feature if custom coding is needed to fix it.
Either fix this bug or get rid of input verifiers.
Submitted On 16-SEP-2003
hampton13
This is definately a bug. Both the focus and the selection
should be stalled when an InputVerifier fails The focus is
nothing more than the visualization of the selection.
Submitted On 30-AUG-2004
pcopeland
This is a serious high priority bug that should have been fixed a long time ago. Its very disapointing to see that this has now been open for 3 years without fixing. Data validation has always been a painful and time consuming exercise - without serious & fundemental problems in the base classes.
Submitted On 21-JAN-2005
rcclough
The InputVerifier class is a pile. It should be fixed NOW or taken out of the JDK. It has never worked, and it doesn't work yet, years later. To call this litany of problem reports a "request for enhancement" is absurd. It is as buggy as anything I've seen. Come on SUN. Stop jerking us around.
- Ray Clough
Submitted On 21-JAN-2005
kozchris
Just wasted a couple of errors to figure out this was a bug. I kept thinking that I was doing something wrong because the documentation clearly states how this is supposed to work. I jumped up to java 5 only to find out this still isn
Submitted On 21-JAN-2005
kozchris
How come this doesn't show up on the top 25 bugs list?
Submitted On 27-JAN-2005
carnoult
This definitly should be considered as a high priority bug.
Here is the "literature" i could collect on it on the internet. As far as combobox are concerned, remember to use a verifier on the editor, instead of the combo itself.
The "rootpane solution" (http://weblogs.java.net/blog/castelaz/archive/2004/08/the_best_laid_p.html) was promosing but then it's the menus that i couldn't handle.
http://java.sun.com/j2se/1.5.0/fixedbugs/fixedbugs.html
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4911422
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4533820
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4342333
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4302322
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4368790
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4490197
Sun's forum threads:
http://forum.java.sun.com/thread.jspa?threadID=177664&start=15&tstart=0
Misc:
http://weblogs.java.net/blog/castelaz/archive/2004/08/the_best_laid_p.html
http://www.mycgiserver.com/~Kleopatra/swing/button/buttonverify.html
http://weblogs.java.net/blog/joshy/archive/2003/10/swing_hack_4_th.html
http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html#glasspane
http://java.sun.com/docs/books/tutorial/uiswing/components/menu.html#popup
http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/FocusSpec.html#FocusAndVetoableChangeListener
Submitted On 25-OCT-2005
benarnold
I think this should be changed to a "bug", not because of the interaction with JButtons in general, but because of JComboBoxes.
Normal buttons can have logic attached to them that checks that the currently focused field is valid. It might make sense for some buttons (like "Cancel") to stay active when the user has entered invalid data.
JComboBoxes are different. All the event-handling for a JComboBox's pop-up button is done in the look and feel, which means that there is no way to intercept it and disable it without writing custom versions for each look and feel your customers are likely to use... or resorting to something drastic like a glass pane.
Most Swing forms have a combination of text fields and combo boxes. What sense is there in a verifier that prevents the user from changing text fields but lets them change combo boxes, which are just text fields with a pick-list. As others have said, it renders the whole InputValidator concept almost useless.
Submitted On 29-DEC-2005
jesse_barnum
Sun - what is the best way to solve this problem? I've read that the behavior is 'correct', but the problem remains. There is currently no good solution that I can see to ensure that a field is valid before the user can do other actions.
Submitted On 14-MAR-2007
We are now up to JDK 1.6 and this bug still hasn't been fixed.
I don't understand why Sun can't fix this bug in over 6 years and several JVM releases.
Swing won't go anywhere if bugs like these remain over a span of many years.
Submitted On 02-APR-2008
Please do something with this bug. It makes InputVerifier completly unusable. I can even create JTabbedPane and switch focus to different JTextField on different tab.
Marek Mosiewicz
http://www.jotel.com.pl
Submitted On 12-AUG-2008
Any status update on this bug? I am using a JComboBox in one of the projects I am doing and the InputVerifier is proving to be a pain. The JComboBox is embedded in a small JDialog which is hidden when the user clicks 'OK' or 'Cancel'. When the JDialog becomes active again, there is code to clear out the JComboBox and initialize it with different data. The InputVerifier also seems to be called when the removeAllItems() method of the box is called, even though I have attached the InputVerifier to the underlying textfield...this is really a painful process, maybe another JVM will do the trick.
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|