JDK-4654916 : JList and JTree should scroll automatically with first-letter navigation
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0,1.4.1
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_nt,windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2002-03-19
  • Updated: 2003-03-12
  • Resolved: 2003-03-12
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 Availability Release.

To download the current JDK release, click here.
Other
5.0 tigerFixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description

Name: jk109818			Date: 03/19/2002


FULL PRODUCT VERSION :
java version "1.4.0-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-rc-b91)
Java HotSpot(TM) Client VM (build 1.4.0-rc-b91, mixed mode)


FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]



A DESCRIPTION OF THE PROBLEM :
According to the article:
http://java.sun.com/products/jfc/tsc/articles/merlin/index.h
tml#JList

"JList should support first letter key navigation-#4284709"

This is implemented in Merlin, but incomplete, however.
Although the selection does happen by typing the key, the
scrolling to the related item is missing, what makes it
pointless.

The method:
getNextMatch(prefix, startIndex, Position.Bias.Forward);

has been added to JList;
BasicListUI.KeyHandler.keyTyped() contains the line:

src.setSelectedIndex(index);, but
src.ensureIndexIsVisible(index); is missing.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Please run the attached program
2.Type the first letter of the last list item (W)
3.

EXPECTED VERSUS ACTUAL BEHAVIOR :
The selection of the item does happen correctly but the
scrolling to it is missing by JList.

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.*;

import java.awt.*;

import javax.swing.*;
import javax.swing.border.*;


public class TestList extends JPanel {

    private JList    list;
    private Vector   listvector;
    DefaultListModel listmodel = new DefaultListModel();

    TestList() {

        createDataModel();
        createList();
        createGUI();
        setBorder();
    }

    void createDataModel() {

        listvector = new Vector();

        listvector.addElement("Penrose");
        listvector.addElement("Hawking");
        listvector.addElement("Green");
        listvector.addElement("Heisenberg ");
        listvector.addElement("Feynman");
        listvector.addElement("Curie");
        listvector.addElement("Newton");
        listvector.addElement("Prigogine");
        listvector.addElement("Planck");
        listvector.addElement("Witten");
        listvector.addElement("Asimov");
        listvector.addElement("Bruno");
        System.out.println("Before sorting:\n ");

        Iterator it = listvector.iterator();

        while (it.hasNext()) {
            System.out.println(it.next());
        }

        Collections.sort(listvector);
    }

    void createList() {

        for (int i = 0; i < listvector.size(); i++) {
            listmodel.addElement(listvector.elementAt(i));
        }

        list = new JList(listmodel);
    }

    void createGUI() {
        setBackground(Color.white);
        add(new JScrollPane(list));
    }

    void setBorder() {

        Border       line  = BorderFactory.createLineBorder(Color.lightGray);
        TitledBorder title = BorderFactory.createTitledBorder(line,
                                 "TestList");

        title.setTitleFont(list.getFont().deriveFont(Font.PLAIN, 16));
        title.setTitleColor((Color) UIManager.get("ScrollBar.thumb"));
        setBorder(title);
    }

    public static void main(String[] args) {

        JFrame    f    = new JFrame("Test");
        Container cont = f.getContentPane();

        cont.add(new TestList(), "Center");
        cont.add(new JLabel("Please type W"), "South");
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
I wrote my own ListUI to overcome this. To support the
scrolling correctly please add the missing lines to
BasicListUI (marked by // line added ):

int index = src.getNextMatch(prefix, startIndex,
                           Position.Bias.Forward);

if (index >= 0) {
    src.setSelectedIndex(index);
    src.ensureIndexIsVisible(index);  // line added
} else if (startingFromSelection) {
    index = src.getNextMatch(prefix, 0,
Position.Bias.Forward);

    if (index >= 0) {
        src.setSelectedIndex(index);
        src.ensureIndexIsVisible(index);    // line added
    }
}



Thank you
(Review ID: 138838) 
======================================================================

Name: jk109818			Date: 07/11/2002


FULL PRODUCT VERSION :
java version "1.4.1-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-beta-b14)
Java HotSpot(TM) Client VM (build 1.4.1-beta-b14, mixed mode)


FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]
Service pack 2

A DESCRIPTION OF THE PROBLEM :
This bug would only take a few lines of code to fix, and it
would make this new feature much more usable.  In other
words, lots of bang for not much buck.

In the JTree KeyListener for first-letter navigation, when
it changes the selected path, it should also call
scrollPathToVisible.  Likewise, in the JList KeyListener,
when it changes the selected index, it should call
ensureIndexIsVisible.  This way users are not surprised
when they press a key and the selection appears to vanish.
This improvement would mirror how native Windows controls
work.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile and execute the included code.
2. With the window open and keyboard focus on the list (as
should happen by default), type single letters and watch
what happens to the selection.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected result: the list automatically scrolls so that the
newly-selected row is fully visible.

Actual result: the list does not scroll, even if the newly-
selected row is not visible at all.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;

public class JListTest
{
  public static void main (String[] args)
  {
    JFrame frame = new JFrame("Frame");

    Container conPane = frame.getContentPane();
    conPane.setLayout(new BorderLayout());

    String strings[] = new String[26];
    int i;
    char c = 'A';
    for (i = 0; i < 26; ++i, ++c) {
        strings[i] = String.valueOf(c);
    }

    JList list = new JList(strings);
    list.setSelectedIndex(0);
    JScrollPane scroll = new JScrollPane(list);

    conPane.add(scroll, BorderLayout.CENTER);

    frame.pack();
    frame.show();
  }
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
It's a big hack, but here it is.  Copy Sun's KeyListener
code for first-letter navigation and add the lines to
scroll to the selected index/row, then subclass the JList
to prevent Sun's KeyListener from being added:

public void addKeyListener(KeyListener l) {
    if (l == null ||
        !l.getClass().getName().startsWith(
            "javax.swing.plaf")) {
        super.addKeyListener(l);
    }
}

This is because BasicListUI.createKeyListener is private,
rather than protected like its cousin in BasicTreeUI or the
other BasicListUI.createXxxListener methods.  I'll write up
another bug report for that inconvenience.

JTree is easier to work around because its UI's inner
KeyListener class is public and the method to create it is
protected.
(Review ID: 159233)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b03
24-08-2004

EVALUATION Name: apR10133 Date: 08/07/2002 The description of this bug contains the evaluation and fix for JList. BasicListUI.KeyHandler.keyTyped() should call ensureIndexIsVisible(index) for list. BasicTreeUI needs similar changes. ###@###.### ======================================================================
24-08-2004

SUGGESTED FIX Name: apR10133 Date: 08/07/2002 ------- BasicListUI.java ------- *** /tmp/sccs.0DaOqA Wed Aug 7 13:56:30 2002 --- BasicListUI.java Wed Aug 7 13:55:48 2002 *************** *** 1802,1812 **** --- 1802,1814 ---- Position.Bias.Forward); if (index >= 0) { src.setSelectedIndex(index); + src.ensureIndexIsVisible(index); } else if (startingFromSelection) { // wrap index = src.getNextMatch(prefix, 0, Position.Bias.Forward); if (index >= 0) { src.setSelectedIndex(index); + src.ensureIndexIsVisible(index); } } } ------- BasicTreeUI.java ------- *** /tmp/sccs.CNaiJD Wed Aug 7 14:11:07 2002 --- BasicTreeUI.java Wed Aug 7 14:08:25 2002 *************** *** 2625,2635 **** --- 2625,2639 ---- Position.Bias.Forward); if (path != null) { tree.setSelectionPath(path); + int row = getRowForPath(tree, path); + ensureRowsAreVisible(row, row); } else if (startingFromSelection) { path = tree.getNextMatch(prefix, 0, Position.Bias.Forward); if (path != null) { tree.setSelectionPath(path); + int row = getRowForPath(tree, path); + ensureRowsAreVisible(row, row); } } } ###@###.### ======================================================================
24-08-2004