> When we use JList component as is, mouse hovering over a cell
> component doesn't change the cell color. Selection by clicking
[quoted text clipped - 17 lines]
> Is there a way to change cell color with focusing of MY
> definition, that is mouse entering into the cell?
You cannot just redefine what the "cellHasFocus" argument means.
Here is my attempt at a hover implementation:
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
public class Hover
{
private static class Listener
extends MouseInputAdapter
implements ListDataListener, PropertyChangeListener, ComponentListener, HierarchyListener, HierarchyBoundsListener, Runnable
{
private JList list;
private int hoverIndex;
private boolean enabled, running;
private Point lastLocation;
public Listener(JList l)
{
list = l;
hoverIndex = -1;
}
public void setEnabled(boolean value)
{
if (enabled == value)
return;
enabled = value;
if (enabled)
{
list.addMouseListener(this);
list.addMouseMotionListener(this);
list.addPropertyChangeListener(this);
list.getModel().addListDataListener(this);
list.addComponentListener(this);
list.addHierarchyListener(this);
list.addHierarchyBoundsListener(this);
list.putClientProperty(HOVER, this);
}
else
{
repaint(hoverIndex());
list.removeMouseListener(this);
list.removeMouseMotionListener(this);
list.removePropertyChangeListener(this);
list.getModel().removeListDataListener(this);
list.removeHierarchyBoundsListener(this);
list.removeHierarchyListener(this);
list.removeComponentListener(this);
list.putClientProperty(HOVER, null);
}
}
public int hoverIndex()
{
return hoverIndex;
}
private void setHoverIndex(int value)
{
hoverIndex = value;
}
private void repaint(int index)
{
if (index != -1)
list.repaint(list.getCellBounds(index, index));
}
private Point toScreen(Point p)
{
p = new Point(p);
SwingUtilities.convertPointToScreen(p, list);
return p;
}
private Point toList(Point p)
{
if (!list.isShowing())
return null;
Point s = list.getLocationOnScreen();
s.x = p.x - s.x;
s.y = p.y - s.y;
return s;
}
// p is in screen coordinate system (or zero, denoting not known or outside)
private void updateHover(Point p)
{
int h = hoverIndex();
Point q = p == null ? null : toList(p);
int newHoverIndex = p == null ? -1 : list.locationToIndex(q);
if (h != newHoverIndex)
{
repaint(h);
repaint(newHoverIndex);
setHoverIndex(newHoverIndex);
}
lastLocation = p;
}
// updateLater is used to make sure that the cell bounds are already updated.
// this may have problems if called initially not from the event-dispatch thread
private void updateLater()
{
if (!running)
{
running = true;
EventQueue.invokeLater(this);
}
}
public void run()
{
running = false;
updateHover(lastLocation);
}
public void propertyChange(PropertyChangeEvent e)
{
String name = e.getPropertyName();
if (name.equals("model"))
{
((ListModel)e.getOldValue()).removeListDataListener(this);
((ListModel)e.getNewValue()).addListDataListener(this);
setHoverIndex(-1);
updateLater();
}
else if (name.equals("font") || name.equals("cellRenderer") || name.equals("fixedRowWidth") || name.equals("fixedRowHeight") || name.equals("prototypeCellValue") || name.equals("layoutOrientation"))
{
// very unspecific
list.repaint();
updateLater();
}
}
public void hierarchyChanged(HierarchyEvent e)
{
if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0)
{
if (!list.isShowing())
{
lastLocation = null;
setHoverIndex(-1);
}
// else: nothing to be done as mouse location is not known (only 1.5)
}
}
public void componentShown(ComponentEvent e)
{
}
public void componentHidden(ComponentEvent e)
{
// handled by hierarchyChanged
}
public void componentMoved(ComponentEvent e)
{
updateHover(lastLocation);
}
public void ancestorMoved(HierarchyEvent e)
{
updateHover(lastLocation);
}
public void componentResized(ComponentEvent e)
{
updateLater();
}
public void ancestorResized(HierarchyEvent e)
{
updateLater();
}
public void mouseMoved(MouseEvent e)
{
updateHover(toScreen(e.getPoint()));
}
public void mouseEntered(MouseEvent e)
{
updateHover(toScreen(e.getPoint()));
}
public void mouseExited(MouseEvent e)
{
updateHover(null);
}
// These implementations are quite unspecific.
public void intervalAdded(ListDataEvent e)
{
if (hoverIndex() >= e.getIndex0())
setHoverIndex(-1);
updateLater();
}
public void intervalRemoved(ListDataEvent e)
{
if (hoverIndex() >= e.getIndex0())
setHoverIndex(-1);
updateLater();
}
public void contentsChanged(ListDataEvent e)
{
updateLater();
}
}
private static Object HOVER = "xxx.Hover";
public static int index(JList l)
{
Listener h = (Listener)l.getClientProperty(HOVER);
return h == null
? -1 : h.hoverIndex();
}
public static void install(JList l)
{
if (l.getClientProperty(HOVER) == null)
{
Listener h = new Listener(l);
h.setEnabled(true);
}
}
public static void uninstall(JList l)
{
Listener h = (Listener)l.getClientProperty(HOVER);
if (l != null)
h.setEnabled(false);
}
public static void main(String[] args)
{
final DefaultListModel data = new DefaultListModel();
Object[] o = new java.io.File(System.getProperty("user.home")).list();
for (int i = 0; i < o.length; i++)
data.addElement(o[i]);
final JList l = new JList(data);
Hover.install(l);
l.setCellRenderer(new DefaultListCellRenderer()
{
private Color hoverBackground = new Color(150, 255, 200);
public Component getListCellRendererComponent
(JList l, Object value, int index, boolean selected, boolean focused)
{
super.getListCellRendererComponent(l, value, index, selected, focused);
if (Hover.index(l) == index)
setBackground(hoverBackground);
return this;
}
});
l.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
final JFrame f = new JFrame();
f.getContentPane().add(new JScrollPane(l));
f.pack(); f.show();
Timer t = new Timer(5000, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//data.insertElementAt(e.toString().substring(0, 10), 0);
f.setLocation(f.getX(), f.getY() + 30);
}
});
t.start();
}
}
Christian
hiwa - 12 Jan 2005 01:33 GMT
Thanks Christian for your wonderful code.
But ...
Should it be that complex?!
Sigh ...
I shall struggle for a simpler one.