ListCellRenderer mit JLabel und MouseListener

FelixBaum

Mitglied
Hallo,

da ich bei meiner Suche nicht fündig wurde, wende ich mich mal an euch:

Ich habe einen ListCellRenderer geschrieben, der mir Text und zwei Labels in einer Liste anzeigt. Die Labels sind jeweils mit ImageIcons gefüllt. Jetzt versuche ich, Ereignisse der Maus abzufangen, indem ich einen MouseListener auf das jeweilige Label setze. Komischerweise passiert dabei nichts. Hier mein Code:

Java:
public class VorräteListCellRenderer extends JPanel implements ListCellRenderer {

    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
	
	this.removeAll();
	VorräteItem item = (VorräteItem) value;
	
	JLabel text = new JLabel(item.getName() + " - " + item.getAnzahl());
	text.setFont(new Font(text.getFont().getName(), Font.BOLD, 24));
	this.add(text);
	
	ImageIcon icon1 = new ImageIcon("./res/add.png");
	JLabel iconPlus = new JLabel();
	iconPlus.addMouseListener(new MouseAdapter() {
	    public void mouseClicked(MouseEvent e) {
		System.out.println("Hallo");
	    }
	});
	iconPlus.setIcon(icon1);
	iconPlus.setVisible(true);
	this.add(iconPlus);
	
	ImageIcon icon2 = new ImageIcon("./res/bin.png");
	JLabel iconMinus = new JLabel();
	iconMinus.setIcon(icon2);
	this.add(iconMinus);
	
	this.setOpaque(true);
	
	if (isSelected) {
	    text.setForeground(Color.RED);
	    this.setBackground(Color.GRAY);
	} else {
	    text.setForeground(Color.BLACK);
	    this.setBackground(Color.WHITE);
	}
	
	return this;
    }

}


Habt ihr vielleicht Ideen, warum dieses nicht funktioniert?
 
Das liegt daran, dass der Renderer die Komponenten nur in die JList zeichnet, und nicht wirklich Komponenten in die JList einfügt. Wenn dein Renderer z.B. einen JButton zurückliefert wird der zwar in der JList angezeigt, ist aber nicht klickbar.

Du könntest einen MouseListener zur JList hinzufügen. Über das MouseEvent kannst du dann herausbekommen welches Element geklickt wurde. Das wäre ein normaler Ansatz um das zu erreichen was du willst:
Java:
        final JList list = new JList<>();
        list.addMouseListener( new MouseAdapter() {

            @Override
            public void mouseClicked( MouseEvent me ) {
                final int index = list.locationToIndex( me.getPoint() );
                System.out.println( index );
            }
        } );
 
Danke für deine Antwort!

Das klappt wunderbar, wenn ich wissen will, welcher Index geklickt wurde. Doch möchte ich wissen, welches JLabel in dem Index geklickt wurde. Gibt es da auch Möglichkeiten?
 
Du müsstest mit den Koordinaten weiter rechnen um drauf zu kommen. Ich hab mal eine Beispiel-Lösung implementiert bei dem zwei Labels gerendert werden und das eine auf einen Mausklick reagieren soll. Aber wirklich schön ist die Lösung nicht:
Java:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;

public class ListRendererExample extends JFrame {

    public ListRendererExample() {
        super();
        setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

        final JList<String> list = new JList<String>( new String[] { "List", "Cell", "Renderer", "Example" } );

        final Map<Integer, Rectangle> labelLocations = new HashMap<Integer, Rectangle>();

        list.setCellRenderer( new ListCellRenderer<String>() {

            @Override
            public Component getListCellRendererComponent( JList<? extends String> list, String value, final int index,
                    boolean isSelected, boolean cellHasFocus ) {
                final JPanel panel = new JPanel();
                final JLabel mouseSensitiveLabel = new JLabel( value ) {

                    protected void paintComponent( java.awt.Graphics g ) {
                        super.paintComponent( g );
                        final Rectangle bounds = getBounds();
                        labelLocations.put( index, bounds );
                    };
                };
                mouseSensitiveLabel.setBorder( BorderFactory.createLineBorder( Color.BLACK ) );
                panel.add( new JLabel( index + ": " ) );
                panel.add( mouseSensitiveLabel );
                return panel;
            }
        } );

        list.addMouseListener( new MouseAdapter() {
            public void mouseClicked( java.awt.event.MouseEvent e ) {
                final int index = list.locationToIndex( e.getPoint() );
                final Rectangle cellBounds = list.getCellBounds( index, index );
                final Point point = new Point( e.getPoint().x - cellBounds.x, e.getPoint().y - cellBounds.y );
                if ( labelLocations.get( index ).contains( point ) ) {
                    System.out.println( "Label bei Index " + index + " wurde geklickt" );
                }
            };
        } );

        getContentPane().add( list );
        pack();
    }

    public static void main( String[] args ) {
        new ListRendererExample().setVisible( true );
    }

}

Das Problem ist, dass JList nicht so richtig für deine Zwecke geeignet ist, da das was du vorhast schon deutlich mehr als eine einfache Liste ist. Daher solltest du dir vielleicht überlegen ob es Sinn machen würde eine eigene Liste zu implementieren. Also z.B. eine JScrollPane mit einem Panel welches die Komponenten untereinander einfügt.
 
Du hast Recht, die Lösung ist nicht grade schön, aber trotzdem danke!

Ich werde es mal mit der JScrollPane ausprobieren und melde mich danach, wenn es nicht klappt!
 

Neue Themen


Zurück
Oben