JDK-4146858 : Wrong DefaultButton behavior in Windows & Motif L&Fs
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.1.6,1.1.7,1.2.0,1.2.2,1.3.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,windows_95,windows_nt
  • CPU: generic,x86
  • Submitted: 1998-06-08
  • Updated: 2001-02-14
  • Resolved: 2001-02-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
Other
1.4.0 betaFixed
Related Reports
Duplicate :  
Duplicate :  
Description

Name: el35337			Date: 06/08/98


Swing 1.0.2 - JDK 1.1.6 - Win 95/NT - Windows L&F

Try the following example programm.
The first button is the default button. You
can select it with enter.
- press TAB: the default button has the focus. OK
- press TAB again: now the second button has the
  focus and is the default button. OK
- press TAB again: the CheckBox has the focus.
  The second button is the default (see black
  border or try with ENTER). I think this is
  WRONG. The "DefaultButton" should be the
  default Button, again. This is the behaviour
  I see in Windows.

If a component that is not a button is selected
the button set as default button should own the
status "default button". Not the last button which
owned the focus.

import com.sun.java.swing.*;
import java.awt.*;

public class DefaultButton extends JFrame
{
	JButton db = new JButton("DefaultButton");
	JButton ab = new JButton("Button 2");
	JCheckBox cb = new JCheckBox("A Component");
	
	public DefaultButton()
	{
		setTitle("Strange DefaultButton");
		getContentPane().setLayout(new FlowLayout());
		getContentPane().add(db);
		getContentPane().add(ab);
		getContentPane().add(cb);
		getRootPane().setDefaultButton(db);
		pack();
	}

    public static void main(String[] args)
    {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch(Exception ex) {System.out.println(ex);}

		JFrame my = new DefaultButton();
        my.setVisible(true);
    }
}
(Review ID: 33248)
======================================================================

Name: skT88420			Date: 08/06/99


Default Pushbutton behaviour in windows look and feel is much different from the normal windows apps.
Generally , if there is a default pushbutton and some other pushbuttons in a windows app, when focus is on an editfield, the default button will become  the one set initially , and once the focus goes to another pushbutton, it becomes default pushbutton. This is right in the java app too.
But in native windows applications,  when focus goes back to another editfield or some other control other than pushbutton, the default button reverts back to the one which was assigned default initially.
But in JDK1.2 with swing, pushbutton which had last focus still remains default pushbutton even when focus goes to some other edit field.
Steps to reproduce :
1.Cut and Paste the app given to MyDialog.java and compile and run it.
2.Initially focus is on 'First' text area. We can see that the button with text 'Default' is painted as default, Press Enter key , we can see Default button gets activated.
3.Tab to Test1. Default button becomes 'Test 1' which is right behaviour.
4.Tab until Close and then tab again to 'Second' Text area.
See that default button still remains 'Close'
Press Enter key, we can see that the Close button is activated, and makes the window invisible.
Actually, Default button should have got activated instead.
See any of the windows native app and you can see the explained behaviour.
-----------------------------------------------------------------
//Source code

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.border.*;

public class MyDialog extends JDialog implements ActionListener
{
static JFrame parentFrame;
static MyDialog errDialog;

public MyDialog(JFrame parent,
String title,
boolean modal) {
super(parent,title,modal);
setSize(400, 200);

JPanel ButtonArea = new JPanel();

JButton tst1 = new JButton("Test 1");
JButton tst2 = new JButton("Test 2");

JButton def = new JButton("Default");
JButton closeButton = new JButton("Close");

closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) 
	{
		setVisible(false);
	}
});

def.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("Default Button");
}
});


ButtonArea.add(tst1);
ButtonArea.add(tst2);
ButtonArea.add(def);
ButtonArea.add(closeButton);

JTextField first = new JTextField("First", 20); 
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
Keymap map1 = first.getKeymap();
map1.removeKeyStrokeBinding(enter);

JTextField tf = new JTextField("Second", 20); 
Keymap map2 = tf.getKeymap();
map2.removeKeyStrokeBinding(enter);

getContentPane().setLayout(new FlowLayout());

getContentPane().add(first);
getContentPane().add(ButtonArea);
getContentPane().add(tf);
getRootPane().setDefaultButton(def);

}
	public void actionPerformed(ActionEvent ae) 
	{
		System.out.println("The action command is :"+ae.getActionCommand());
		if(ae.getActionCommand() == "Close")
		{
			setVisible(false);
			dispose();
		}

	}
	public static void main(String[] args) {

		try
		 {
		 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		 }
		 catch (Exception e)//UnsupportedLookAndFeelException e)
		 {}
		parentFrame = new JFrame();
		parentFrame.setSize(400, 200);
		parentFrame.addWindowListener(new WindowAdapter() { 
		public void windowClosing(WindowEvent e) {
		System.exit(0);
		} // windowClosing
		} ); 

  String title = " My Dislog ";

 MyDialog myDialog = new MyDialog(parentFrame, title, true);
 myDialog.setVisible(true);
}

}
(Review ID: 93605)
======================================================================

Name: skT88420			Date: 08/25/99


JOptionPane.showConfirmDialog(parent,
			msg, title, JOptionPane.YES_NO_OPTION, 
			JOptionPane.QUESTION_MESSAGE);

1.  In WINDOWS Look and feel show the dialog
2.  change the focus to the "No" option.
3.  Press Enter.
4.  'No' option activates which is correct behavior.

5.  In SWING Look and feel show the dialog
6.  change the focus to the "No" option.
7.  Press Enter.
8.  'Yes' option activates even though 'No' has focus.

I believe item 8 is incorrect behavior.
(Review ID: 94376)
======================================================================

Name: skT88420			Date: 02/08/2000


java version "1.3.0rc1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc1-T)
Java HotSpot(TM) Client VM (build 1.3.0rc1-S, mixed mode)

Setting the default button on a JRootPane doesn't work when there are multiple
JInternalFrames visible.  When there is only one internal frame, setting
frame.getRootPane().setDefaultButton(button) works as expected.  Attached is
code to demonstrate.  After running the demo, do the following:

1) There are two internal frames stacked on top of each other.  Move the top
one so that you can see the bottom frame.
2) Notice that the bottom frame button has the dark default button border, but
the top frame does not.
3) Pressing enter show trigger the button and change its label to "clicked".
Press enter and notice the top frame does nothing.
4) Now activate the bottom frame and notice the default border around button
goes away.  Press enter to show it does nothing also.

Now recompile the program after commenting out one of the two lines "AddFrame
()" so that only one JInternalFrame is created.  Run it and notice that the
default button works correctly and will change its text when enter is pressed.

Here is the code to demonstrate the problem:

package test;

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

public class DefaultButtonTest extends JFrame implements ActionListener {
	
	JDesktopPane desktop = new JDesktopPane();
	
	public static void main(String[] args) {
		new DefaultButtonTest();
	}
	
	public DefaultButtonTest() {
		getContentPane().add(desktop);
		setSize(500, 300);
		show();

		AddFrame();
		AddFrame();
	}
	
	private void AddFrame() {
		JInternalFrame frame = new JInternalFrame();
		desktop.add(frame);
		JButton button = new JButton("test");
		button.addActionListener(this);
		frame.getRootPane().setDefaultButton(button);
		frame.getContentPane().setLayout(new FlowLayout());
		frame.getContentPane().add(button);
		frame.setSize(300, 200);
		frame.show();
	}
	
	public void actionPerformed(ActionEvent e) {
		((JButton)e.getSource()).setText("clicked");
	}
}
(Review ID: 100980)
======================================================================

Name: jk109818			Date: 06/21/2000


java -version
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

Activating and disactivating internal frames removes the default button:

1. Activate top left internal frame by clicking on the title bar
2. Press Enter --> Button is pressed as it should
3. Activate bottom right internal frame by clicking on the title bar
4. Press Enter --> Default button is NOT activated as it should
5. Click again in the title bar of the top left internal frame
6. Press Enter --> Default button is NOT activated as it should

Code that demonstrates the problem:

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

public class DefaultButtonBug
{
	static void addInternalFrame(JDesktopPane desktop, int x, int y)
    {
        final JButton btn = new JButton("Button");
		final JInternalFrame iframe = new JInternalFrame();

        iframe.getContentPane().add(new JTextField(), BorderLayout.NORTH);
        iframe.getContentPane().add(btn, BorderLayout.SOUTH);

		iframe.pack();
        iframe.setLocation(x, y);
		iframe.setSize(100,100);
        iframe.setVisible(true);
		desktop.add(iframe);

        iframe.getRootPane().setDefaultButton(btn);

        // This is the workaround code:
/*		iframe.addInternalFrameListener(new InternalFrameAdapter() {
			public void internalFrameActivated(InternalFrameEvent e)
            {
                iframe.getRootPane().setDefaultButton(btn);
            }
         });
*/
    }

	static public void main(String[] args)
	{
		JFrame frame = new JFrame();
		JDesktopPane desktop = new JDesktopPane();

		frame.setContentPane(desktop);
		frame.pack();
		frame.setSize(400,400);
		frame.setVisible(true);

		addInternalFrame(desktop, 0, 0);
		addInternalFrame(desktop, 200, 200);
	}
}
(Review ID: 105892)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin merlin-beta FIXED IN: merlin-beta INTEGRATED IN: merlin-beta
2004-06-14

WORK AROUND Name: skT88420 Date: 08/25/99 None (Review ID: 94376) ====================================================================== Name: skT88420 Date: 02/08/2000 None. (As usual, don't use Java2) (Review ID: 100980) ======================================================================
2004-06-11

EVALUATION This is true. HOwever, it's going to be difficult to fix, given the current organization of the focus/default-handling code. Currently the defaultbutton- setting code is contained in the button UI implementation, and from there it has no way of telling what type of component a button is losing focus to. I suppose the logic for this handling should really be in the focus manager. amy.fowler@Eng 1998-09-30 Turns out this is also a problem in the Motif LAF. I've almost got a fix working, however I really need a reliable way of detecting generic focus changes that isn't currently possible with the existing api. Specifically, the case I need to be able to detect is when focus leaves a JButton and moves into a non-JButton. (there are hacks I could use, but cleaning up the api would be preferable) amy.fowler@Eng 1998-09-30 amy.fowler@Eng 1998-12-11 Still don't have appropriate FocusManager api to fix this in a reasonable way. moving the committment to merlin. amy.fowler@Eng 1999-10-12 I have now fixed this problem by modifying BasicRootPaneUI to store the original "default" setting and then BasicButtonListener will reset the default to this value when focus leaves the button. amy.fowler@Eng 2001-02-07
2001-02-07