# JButton in JList - MouseEvent-Problem



## Rock Lobster (17. Jul 2008)

Servus,

ich habe eine JList, welche JPanels als Listenelemente enthält, die wiederum einige Unter-Elemente enthalten, unter anderem auch JButtons.

Das Problem ist nur, daß die MouseEvents auf dem Button nun nicht mehr funktionieren, weil die JList diese wohl nicht weiterleitet. Ich habe schon einige Dinge ausprobiert (z.B. direkt auf AWT-Events hören, oder die MouseEvents von der JList abfangen und per processMouseEvent() an das enthaltene Panel weitergeben), aber leider alles ohne Erfolg.

Wie kann ich dafür sorgen, daß der Button ordnungsgemäß funktioniert, obwohl er in einer Liste drinsteht?
Ich hoffe, ihr könnt mir helfen.

Schöne Grüße
Rock Lobster


----------



## kleiner_held (17. Jul 2008)

Meine erste Frage ist ob du die JPanels wirklich als Elemente in der JList hast  oder nur einen entsprechenden ListCellRenderer verwendest.

Das von dir beschriebene Verhalten ist mit JList nicht moeglich, da diese Klasse nur CellRenderer aber keine CellEditoren verwendet - dazu muesste man dann auf JTable umsteigen.
Falls du aber eh schon fuer jeden Eintrag ein JPanel erstellt verstehe ich nicht wozu du noch eine JList brauchst.


----------



## Rock Lobster (17. Jul 2008)

Nein also das macht der ListCellRenderer. Der gibt einfach ein Panel zurück.

Aber wenn es nicht geht, dann werde ich wohl auf die Liste verzichten müssen und stattdessen die Panels einfach so untereinander anordnen. Dann muß ich halt auch das Selektieren usw. selbst programmieren.


EDIT: Okay, JTable wäre evtl. auch noch eine Möglichkeit... werd ich mir mal anschauen. Danke schonmal für den Tip!


----------



## kleiner_held (17. Jul 2008)

Die Komponenten die der CellRenderer zurueckgibt werden wirklich nur zum Rendern genommen, die sind also nicht in den ComponentTree eingebunden und erhalten deswegen auch keine Events.
In dem Fall hilft nur eine JTable mit TableCellEditor, denn solange eine Zelle editiert wird ist der Editor (die Component) auch wirklich eigebunden, und erhaelt alle Events.


----------



## Rock Lobster (17. Jul 2008)

Ahh okay, d.h. der CellRenderer gibt - vereinfacht gesagt - nur das eigentliche Bild zurück, damit die GUI halt gezeichnet werden kann? Dann ist das Problem klar. Okay dann werde ich mir wirklich mal die JTable anschauen...


----------



## Rock Lobster (18. Jul 2008)

Also ich bin nun auf JTable umgestiegen und hab meinen eigenen TableCellEditor eingebaut, aber die Events gehen immer noch nicht durch 

Habe auch schon ein bißchen mit den Rückgabewerten rumgespielt, z.B. bei isCellEditable() usw., aber es funktioniert leider nicht.


----------



## Michael... (18. Jul 2008)

zeig doch mal ein bisschen Code, vor allem den des Editors, dann kann man mehr dazu sagen


----------



## Rock Lobster (18. Jul 2008)

```
@Override
	public Component getTableCellEditorComponent(JTable table, Object value,
			boolean isSelected, int row, int column)
	{
		if (value instanceof ContactPanel)
		{
			ContactPanel panel = (ContactPanel)value;
			panel.setToolTipText(panel.getName());
			
			if (isSelected)
			{
				panel.setBackground(table.getSelectionBackground());
				panel.setForeground(table.getSelectionForeground());
			}
			
			return panel;
		}
		
		if (value instanceof Component)
			return (Component)value;
		
		return null;
	}


	@Override
	public void addCellEditorListener(CellEditorListener l)
	{
	}


	@Override
	public void cancelCellEditing()
	{
	}


	@Override
	public Object getCellEditorValue()
	{
		return null;
	}


	@Override
	public boolean isCellEditable(EventObject anEvent)
	{
		return true;
	}


	@Override
	public void removeCellEditorListener(CellEditorListener l)
	{
	}


	@Override
	public boolean shouldSelectCell(EventObject anEvent)
	{
		return true;
	}


	@Override
	public boolean stopCellEditing()
	{
		return false;
	}
```


----------



## Michael... (18. Jul 2008)

Rock Lobster hat gesagt.:
			
		

> ```
> @Override
> public Component getTableCellEditorComponent(JTable table, Object value,
> boolean isSelected, int row, int column)
> ...



Das wird Dir als Editor vermutlich immer null zurückliefern, da die Variable value den Dateninhalt repräsentiert und spätestens nach dem ersten Aufruf des Editors auf null gesetzt wird siehe Deinen Code Zeile 41.

Kleiner Tip leite nach Möglichkeit den Editor von AbstractCellEditor ab, dann musst nicht alle Methoden von TableCellEditor überschreiben.


----------



## Rock Lobster (18. Jul 2008)

Also angezeigt werden die Einträge schon, von daher liefert er wohl nicht null zurück. Ich kann bloß den darin enthaltenen Button nicht anklicken, sprich, die Events werden wieder nicht an die inneren Components weitergeleitet.


----------



## kleiner_held (18. Jul 2008)

Beispiel siehe unten. Ist nicht unbedingt eine Augenweide, sollte aber das Prinzip verdeutlichen. Allgemein wuerde ich aber ueberlegen ob es wirklich noetig ist JPanels als model values zu verwenden.


```
public class TableCellEditorSample
{
	public static void main(String[] args)
	{
		JFrame frame = new JFrame();
		DefaultTableModel defaultTableModel = new DefaultTableModel(new Object[][]{{"Line 1", new MyPanel("ABC", "ABC")}, {"Line 2", new MyPanel("DEF", "DEF")}}, new String[] {"Header", "Header"})
		{
			@Override
			public Class<?> getColumnClass(int columnIndex)
			{
				if (columnIndex == 1)
				{
					return MyPanel.class;
				}
				return super.getColumnClass(columnIndex);
			}
		};
		JTable table = new JTable(defaultTableModel);
		table.getColumnModel().getColumn(0).setPreferredWidth(40);
		table.getColumnModel().getColumn(1).setPreferredWidth(200);
		table.doLayout();
		MyTableCellEditorAndRenderer editorAndRenderer = new MyTableCellEditorAndRenderer();
		table.setDefaultRenderer(MyPanel.class, editorAndRenderer);
		table.setDefaultEditor(MyPanel.class, editorAndRenderer);
		table.setRowHeight(25);
		frame.add(table);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(400, 300);
		frame.setVisible(true);
	}
	
	/**
	 * Editor und renderer fuer die Tabelle
	 */
	private static class MyTableCellEditorAndRenderer extends AbstractCellEditor implements TableCellEditor, TableCellRenderer
	{
		MyPanel panel;
		
		public Object getCellEditorValue()
		{
			return panel;
		}
		
		public boolean isCellEditable(EventObject anEvent) 
		{
			if (anEvent instanceof MouseEvent) 
			{ 
				return ((MouseEvent)anEvent).getClickCount() >= 2;
			}
			return true;
		}
		
		public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
		{ 
			panel = (MyPanel) value;
			setColor(panel,table, isSelected);
			return panel;
		}	

		public boolean stopCellEditing()
		{
			panel.getLabel().setText(panel.getTextField().getText());
			return super.stopCellEditing();
		}
		
		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
				boolean hasFocus, int row, int column)
		{	
			MyPanel panel = (MyPanel) value;
			setColor(panel,table, isSelected);
			return panel;	
		}
		
		private void setColor(MyPanel panel, JTable table, boolean isSelected)
		{
			if (isSelected)
			{
				panel.setBackground(table.getSelectionBackground());
			} 
			else
			{
				panel.setBackground(table.getBackground());
			}
		}
	}
	
	/**
	 * Panel zum Anzeigen und editieren.
	 */
	private static class MyPanel extends JPanel
	{
		JTextField textField;
		JLabel label;
		
		private MyPanel(String text, String text2)
		{
			setLayout(new BorderLayout());
			setBorder(new EmptyBorder(3,3,3,3));
			label = new JLabel(text);
			textField = new JTextField(text2, 20);
			add(label, BorderLayout.WEST);
			add(textField, BorderLayout.CENTER);
			add(new JButton(new AbstractAction("Klick") {
				public void actionPerformed(ActionEvent e)
				{
					JOptionPane.showMessageDialog(null, "Test");
				}
			}), BorderLayout.EAST);
		}

		private JTextField getTextField()
		{
			return textField;
		}

		private JLabel getLabel()
		{
			return label;
		}
	}
}
```


----------



## Rock Lobster (18. Jul 2008)

Danke für das Beispiel, aber irgendwie will das immer noch nicht so recht. Manche Tabelleneinträge kann ich per Maus gar nicht auswählen (nur per Tastatur), und der Button funktioniert meist auch nur in einem einzigen Feld (und dann nur nach mehrmaligem Klicken).

Ich glaube mir bleibt wohl nichts anderes übrig als einfach ein ganz normales Panel mit FlowLayout oder sonstwas zu nehmen und das Handling mit dem Selektieren usw. selbst zu programmieren.

Trotzdem danke für die Hilfe!


----------



## kleiner_held (18. Jul 2008)

In dem Beispiel wird Editieren erst mit einem Doppelklick gestartet.

```
public boolean isCellEditable(EventObject anEvent)
{
   if (anEvent instanceof MouseEvent)
   {
       return ((MouseEvent)anEvent).getClickCount() >= 2;
   }
   return true;
}
```
Ansonsten scheint aber trotzdem eine JTable fuer deine Anwandung unpassend zu sein, deswegen glaube ich auch dass du mit einem einfachen Panel besser faehrst.


----------

