redcarton.com

Java Bugs and Quirks...

Here are some Java bugs, annoyances and workarounds that I have found.

  1. Components with ItemListener return wrong deselect value
  2. JTable erases selections when switching selection model
  3. Cannot compile inner class of ItemListener
  4. JPasswordField size wrong with Windows Look and Feel
  5. JTabbedPane selected tab overlap with Windows Look and Feel

1. Components with ItemListener return wrong deselect value

JVM: 1.1.8, 1.2.2, 1.3.1

Problem: Component selection is wrong during deselection.

Example: If you call getState() on a CheckBox or isSelected() on a JRadioButton during the first itemStateChanged() event, they will return the newly selected component as being selected, and not the previously selected component.

Solution: Restrict your code to the appropriate itemStateChanged(ItemEvent e) call. Use:

if (e.getStateChange() == ItemEvent.DESELECTED) { }

for deselection calls, and:

if (e.getStateChange() == ItemEvent.SELECTED) { }

for selection calls.

To get the appropriate radio button selection (or other), only check for its selection during the ItemEvent.SELECTED call.


2. JTable erases selections when switching selection model

JVM: 1.3.1

Problem: Chaging selection model clears current selection(s).

Example: If you select a row in a JTable with ListSelectionModel.SINGLE_SELECTION and then change to ListSelectionModel.MULTIPLE_INTERVAL_SELECTION, your selection will be lost.

Solution: Store the current selection, change the selection model, and then restore the selection. This can be done in two ways.

1. Store the first selection:

int index = table.getSelectedRow(); table.setSelectionModel(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.getSelectionModel().addSelectionInterval(index, index);

2. Store the last chosen selection:
Continuously keep track of the last selected row. Add a ListSelectionListener to the table and use this valueChanged() method:

public void valueChanged(ListSelectionEvent e) { lastRow = e.getLastIndex(); }

Then do like method 1:

table.setSelectionModel(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.getSelectionModel().addSelectionInterval(lastRow, lastRow);


3. Cannot compile inner class of ItemListener

JVM: 1.1.8

Problem: ItemListner inner class causes compile issues.

Example: If you have an ItemListener inner class, your class file will not compile. (Note: The code will run, but it will note compile.)

Sample Problem Code:

import java.awt.*; public class ItemListenerTest { public ItemListenerTest() { Frame frame = new Frame("ItemListner Test"); Container contentPane = frame.getContentPane(); new ListBox(new ItemListener( public void ItemStateChanged(ItemEvent e) { //do something } )); contentPane.add(panel); frame.pack(); frame.show(); } public static void main(String[] args) { new ItemListenerTest(); } }

Solution: Have the class containing the inner class implement the ItemListener instead.

Sample Solution Code:

public class ItemListenerTest { public ItemListenerTest() implements ItemListener { Frame frame = new Frame("ItemListner Test"); Container contentPane = frame.getContentPane(); new ListBox(new ItemListener(this)); contentPane.add(panel); frame.pack(); frame.show(); } public void ItemStateChanged(ItemEvent e) { //do something } public static void main(String[] args) { new ItemListenerTest(); } }


4. JPasswordField size wrong with Windows Look and Feel

JVM: 1.2.2, 1.3.1, 1.4.0

Problem: JPasswordField and JTextField fields are not the same size with Win L&F.

Example: If you create a JPasswordField above a JTextField with the same size arguments, they will not be the same size with the Windows Look and Feel.

Sample Problem Code:

import java.awt.*; import javax.swing.*; public class JPasswordFieldTest { public JPasswordFieldTest() { JFrame frame = new JFrame("JPasswordField Test"); Container contentPane = frame.getContentPane(); JPanel panel = new JPanel(); panel.add(new JTextField()); panel.add(new JPasswordField()); contentPane.add(panel); frame.pack(); frame.show(); } public static void main(String[] args) { try { UIManager.setLookAndFeel( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception e) { System.out.println("Error"); } new JPasswordFieldTest(); } }

Solution: Use a layout manager to streach the fields. This way they will both be the same lenght. See the Java Tutorial for details on which layout managers resize the components.

Sample Solution Code:

public class JPasswordFieldTest { public JPasswordFieldTest() { JFrame frame = new JFrame("JPasswordField Test"); Container contentPane = frame.getContentPane(); JPanel panel = new JPanel(new GridLayout(1,2)); panel.add(new JTextField()); panel.add(new JPasswordField()); contentPane.add(panel); frame.pack(); frame.show(); } public static void main(String[] args) { try { UIManager.setLookAndFeel( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception e) { System.out.println("Error"); } new JPasswordFieldTest(); } }

Additional Notes: The Windows Look and Feel should only be used on machines running MS Windows.


5. JTabbedPane selected tab overlap with Windows Look and Feel

JVM: 1.2.2, 1.3.1, 1.4.0

Problem: The selected tab hides part of the tab above it with Win L&F.

Example: If your JtabbedPane has multiple rows of tabs, the selected tab will hide a portion of the text in the tab above it.

Sample Problem Code:

import java.awt.*; import javax.swing.*; public class JTabbedPaneTest { public JTabbedPaneTest() { JFrame frame = new JFrame("JTabbedPane Test"); Container contentPane = frame.getContentPane(); JTabbedPane tp = new JTabbedPane(); tp.addTab("Panel 1 - p", null, new JPanel(), "This is panel 1"); tp.addTab("Panel 2 - p", null, new JPanel(), "This is panel 2"); tp.addTab("Panel 3 - p", null, new JPanel(), "This is panel 3"); tp.addTab("Panel 4 - p", null, new JPanel(), "This is panel 4"); tp.addTab("Panel 5 - p", null, new JPanel(), "This is panel 5"); tp.addTab("Panel 6 - p", null, new JPanel(), "This is panel 6"); contentPane.add(tp); frame.pack(); frame.show(); } public static void main(String[] args) { try { UIManager.setLookAndFeel( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception e) { System.out.println("Error"); } new JTabbedPaneTest(); } }

Solution: Extend BasicTabbedPaneUI and override the calculateMaxTabHeight() method and add 2 to the returned value. This will add 2 pixels to the tab height, enough to clear the selected tab.

Sample Solution Code:

import java.awt.*; import javax.swing.*; public class JTabbedPaneTest { public JTabbedPaneTest() { JFrame frame = new JFrame("JTabbedPane Test"); Container contentPane = frame.getContentPane(); JTabbedPane tp = new JTabbedPane(); tp.addTab("Panel 1 - p", null, new JPanel(), "This is panel 1"); tp.addTab("Panel 2 - p", null, new JPanel(), "This is panel 2"); tp.addTab("Panel 3 - p", null, new JPanel(), "This is panel 3"); tp.addTab("Panel 4 - p", null, new JPanel(), "This is panel 4"); tp.addTab("Panel 5 - p", null, new JPanel(), "This is panel 5"); tp.addTab("Panel 6 - p", null, new JPanel(), "This is panel 6"); contentPane.add(tp); /* Tip: Only add set the UI if using the Windows Look and Feel. */ tp.setUI(new myBasicTabbedPaneUI()); frame.pack(); frame.show(); } public static void main(String[] args) { try { UIManager.setLookAndFeel( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception e) { System.out.println("Error"); } new JTabbedPaneTest(); } } import javax.swing.plaf.basic.BasicTabbedPaneUI; public class MyBasicTabbedPaneUI extends BasicTabbedPaneUI { protected int calculateMaxTabHeight(int tabPlacement) { return super.calculateMaxTabHeight(tabPlacement) + 2; } }

Additional Notes: The Windows Look and Feel should only be used on machines running MS Windows.