JList navigation (Selection & Focus)

Hi All,

I'm quite new with Swing.

I have a JList that I can navigate down through with the <Up> and <Down> keys.

I want to change the default behaviour so that the arrowkeys does'nt select the element but only highlights it (i.e. painting the element's border).

So in order to select an element, the element has to be highlighted and then <Space> or <Enter> will select the element.

Any help is appreciated

I't has to be compatible with JDK 1.4.x

[517 byte] By [JakeBarona] at [2007-9-23]
# 1
I'm guessing that this is controled in code in JList itself, and that you can look at the source, figure out how it works and override JList to make it do what you want.
bsampieria at 2007-7-10 > top of java,Desktop,Core GUI APIs...
# 2

The JList API gives an example of using a MouseListener to handle double clicks.

The Swing tutorial on "How to Use Key Bindings" shows how to invoke an Action when a given KeyStroke is pressed.

http://java.sun.com/docs/books/tutorial/uiswing/misc/keybinding.html

Putting the two together, you get something like this:

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class ListUtility

{

private static final KeyStroke ENTER = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);

public static void addAction(JList source, Action action)

{

// Handle enter key

InputMap im = source.getInputMap();

im.put(ENTER, ENTER);

source.getActionMap().put(ENTER, action);

// Handle mouse double click

source.addMouseListener( new ActionMouseListener() );

}

// Implement Mouse Listener

static class ActionMouseListener extends MouseAdapter

{

public void mouseClicked(MouseEvent e)

{

if (e.getClickCount() == 2)

{

JList list = (JList)e.getSource();

Action action = list.getActionMap().get(ENTER);

if (action != null)

{

ActionEvent event = new ActionEvent(

list,

ActionEvent.ACTION_PERFORMED,

"");

action.actionPerformed(event);

}

}

}

}

public static void main(String[] args)

{

Action displayAction = new AbstractAction()

{

public void actionPerformed(ActionEvent e)

{

JList list = (JList)e.getSource();

System.out.println(list.getSelectedValue());

}

};

String[] data = { "zero", "one", "two", "three", "four", "five" };

JList list = new JList( data );

ListUtility.addAction(list, displayAction);

JFrame frame = new JFrame();

frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

frame.getContentPane().add( new JScrollPane(list) );

frame.setSize(400, 100);

frame.setLocationRelativeTo( null );

frame.setVisible( true );

}

}

camickra at 2007-7-10 > top of java,Desktop,Core GUI APIs...
# 3

Thanks for your response, it's been very helpful.

How would change the way focus is displayed.

By default JList, shows a light-purple where in the JList you are and also on your selections.

How would you change it so only the selected elements have a bar and the element that has focus have a border around it.

This way the user is can use the arrow keys to navigate through the list (with a border showing what element has focus) and hit enter when they want to make a selection (the element gets a bar).

Thanks in advance

JakeBarona at 2007-7-10 > top of java,Desktop,Core GUI APIs...
# 4
list.setSelectionBackground(null);
pravintha at 2007-7-10 > top of java,Desktop,Core GUI APIs...
# 5

Thanks for your response. It helped with the border. Though still no solving my problem with the selection of mulitple values works and displayes.

However I found an example in the Swing 2nd Edition by Matthew Robbinson and Pavel Vorobiev, that covers JList very well and covers much of what I want to achieve. I don't thing Iegal for me to put their source code here. But I'll post a sample here when I'm after i've finished my small project.

JakeBarona at 2007-7-10 > top of java,Desktop,Core GUI APIs...
# 6

Hi JakeBaron ,

Try the following code , I hope it will solve your problem

It is a sample and you can enhance the code for ur requirement.

I hope it will helps to you.

import java.awt.* ;

import java.awt.event.* ;

import javax.swing.* ;

import javax.swing.plaf.ListUI;

import javax.swing.plaf.basic.BasicListUI;

public class LstTest extends JFrame {

public LstTest() {

super( "List Test" ) ;

setDefaultCloseOperation( EXIT_ON_CLOSE ) ;

init() ;

setSize( 350 , 300 ) ;

setVisible( true ) ;

}

private JList lst ;

private void init() {

Object[] o = new Object[] { "a" , "b" , "c" , "d" , "e" , "f" } ;

lst = new JList( o ) ;

initAction() ;

lst.registerKeyboardAction( new SpAct() , KeyStroke.getKeyStroke( KeyEvent.VK_SPACE , 0 , true ) , JList.WHEN_FOCUSED ) ;

getContentPane().add( new JScrollPane( lst ) , BorderLayout.CENTER ) ;

}

private void initAction() {

ActionMap map = (ActionMap)UIManager.get("List.actionMap");

map.put( "selectPreviousRow" , new MyIncrementLeadSelectionAction("selectPreviousRow",

MyIncrementLeadSelectionAction.CHANGE_SELECTION, -1) ) ;

map.put("selectPreviousRowExtendSelection",

new MyIncrementLeadSelectionAction

("selectPreviousRowExtendSelection",MyIncrementLeadSelectionAction.EXTEND_SELECTION, -1));

map.put("selectNextRow",

new MyIncrementLeadSelectionAction("selectNextRow",

MyIncrementLeadSelectionAction.CHANGE_SELECTION, 1));

map.put("selectNextRowExtendSelection",

new MyIncrementLeadSelectionAction

("selectNextRowExtendSelection", MyIncrementLeadSelectionAction.EXTEND_SELECTION, 1));

}

public class SpAct extends AbstractAction {

public SpAct() {

super() ;

}

public void actionPerformed( ActionEvent actEvt ) {

JList list = ( JList ) actEvt.getSource() ;

int lsi = list.getLeadSelectionIndex() ;

if( lsi == -1 ) {

return ;

}

ListSelectionModel lsm = list.getSelectionModel() ;

if( list.isSelectedIndex( lsi ) ) {

lsm.removeSelectionInterval( lsi , lsi ) ;

} else {

lsm.addSelectionInterval( lsi , lsi ) ;

}

}

}

public class MyIncrementLeadSelectionAction extends AbstractAction {

public static final int CHANGE_LEAD = 0;

public static final int CHANGE_SELECTION = 1;

public static final int EXTEND_SELECTION = 2;

protected int amount;

protected int selectionType;

protected MyIncrementLeadSelectionAction(String name, int type) {

this(name, type, -1);

}

protected MyIncrementLeadSelectionAction(String name, int type, int amount) {

super(name);

this.amount = amount;

this.selectionType = type;

}

protected int getNextIndex(JList list) {

int index = list.getLeadSelectionIndex();

int size = list.getModel().getSize();

if (index == -1) {

if (size > 0) {

if (amount > 0) {

index = 0;

} else {

index = size - 1;

}

}

} else {

index += getAmount(list);

}

return index;

}

protected int getAmount(JList list) {

if (list.getLayoutOrientation() == JList.HORIZONTAL_WRAP) {

ListUI ui = list.getUI();

if (ui instanceof BasicListUI ) {

int cc = Math.max(1, list.getModel().getSize()

/ list.getVisibleRowCount());

return cc * amount;

}

}

return amount;

}

protected void ensureIndexIsVisible(JList list, int index) {

list.ensureIndexIsVisible(index);

}

public void actionPerformed(ActionEvent e) {

JList list = (JList) e.getSource();

int index = getNextIndex(list);

if (index >= 0 && index < list.getModel().getSize()) {

if( list.isSelectedIndex( index ) )

list.addSelectionInterval( index , index ) ;

else

list.removeSelectionInterval(index, index);

ensureIndexIsVisible(list, index);

}

}

}

public static void main(String[] args) {

new LstTest() ;

}

}

Acknowledge me

LittleDanya at 2007-7-10 > top of java,Desktop,Core GUI APIs...
# 7

hi,

you can try this code also, just navigate throug the arrow and press space bar the selected row chages its background color

import java.awt.Color;

import java.awt.Component;

import java.awt.event.ActionEvent;

import java.awt.event.KeyEvent;

import java.util.ArrayList;

import javax.swing.AbstractAction;

import javax.swing.AbstractListModel;

import javax.swing.Action;

import javax.swing.DefaultListCellRenderer;

import javax.swing.JComponent;

import javax.swing.JFrame;

import javax.swing.JList;

import javax.swing.KeyStroke;

public class ListTest extends JFrame

{

JListlist = new JList();

ListModel lm= new ListModel();

public ListTest()

{

list.setModel(lm);

final DefaultListCellRenderer dfc = lm.getRenderer();

list.setCellRenderer(dfc);

getContentPane().add(list);

setVisible(true);

pack();

setDefaultCloseOperation(EXIT_ON_CLOSE);

KeyStroke keyKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false);

Action spaceKeyAction = new AbstractAction()

{

public void actionPerformed(ActionEvent actionEvent)

{

int iRow = list.getSelectedIndex();

if (iRow >= 0)

{

lm.setColorRender(iRow);

list.repaint();

}

}

};

this.list.getInputMap(JComponent.WHEN_FOCUSED).put(keyKeyStroke, "Space");

this.list.getActionMap().put("Space", spaceKeyAction);

}

class ListModel extends AbstractListModel

{

String[] listData = { "a", "b", "c", "x", "z" };

ArrayList<listcolor> al= new ArrayList<listcolor>();

class listcolor

{

boolean isSelected = false;

String data= new String();

}

ListModel()

{

for (int i = 0; i < listData.length; i++)

{

listcolor lc = new listcolor();

lc.data = listData[i];

lc.isSelected = false;

al.add(lc);

}

}

public int getSize()

{

return listData.length;

}

public void setColorRender(int row)

{

listcolor lc = al.get(row);

if (lc.isSelected)

lc.isSelected = false;

else

lc.isSelected = true;

}

public Object getElementAt(int index)

{

listcolor lc = al.get(index);

return lc.data;

}

ListCellRender lcr = new ListCellRender();

public DefaultListCellRenderer getRenderer()

{

return lcr;

}

class ListCellRender extends DefaultListCellRenderer

{

public Component getListCellRendererComponent(JList list, Object value, int index,

boolean isSelected, boolean cellHasFocus)

{

Component comp = super.getListCellRendererComponent(list, value, index,

isSelected, cellHasFocus);

listcolor lc = al.get(index);

if (lc.isSelected)

{

comp.setBackground(Color.MAGENTA);

}

else

{

comp.setBackground(Color.WHITE);

}

return comp;

}

}

}

public static void main(String[] args)

{

new ListTest();

}

}

dayanandabva at 2007-7-10 > top of java,Desktop,Core GUI APIs...