Problem mit eigenem CellEditor

TimoTH

Mitglied
Hi zusammen!
Ich habe mir für eine JTable einen eigenen Editor geschrieben, welcher eine JComboBox nutzt.
Leider funktioniert das mit der Werteübergabe von Editor an Tabellenmodel nicht so wirklich.
Denn nicht nur die eigene Zelle wird auf den selektierten Wert gesetzt, sondern die ganze Reihe..
Habe nur leider keine Idee, woran das liegen könnte...


Editor
Code:
/*
 * CustomEditor.java
 *
 * Created on 9. Juli 2007, 09:45
 */
import javax.swing.AbstractCellEditor;

import java.util.ArrayList;
import javax.swing.event.CellEditorListener;

import javax.swing.table.TableCellEditor;

import javax.swing.JComboBox;

import java.awt.event.MouseListener;

import javax.swing.event.ChangeEvent;

import java.util.EventObject;

import java.awt.event.KeyListener;

import javax.swing.JTextField;

import javax.swing.JLabel;

public class CustomEditor implements TableCellEditor,KeyListener{
    private ArrayList cellListener = new ArrayList();
    JComboBox box  = null;
    boolean started = false;
    String ident;
    /** Creates a new instance of CustomEditor */
    public CustomEditor(JComboBox box, String ident) {
        this.box = box;
        this.box.addKeyListener(this);
        this.ident = ident;
        
    }
    
    public void addCellEditorListener(CellEditorListener l){
        cellListener.add(l);
    }
    public void removeCellEditorListener(CellEditorListener l){
        cellListener.remove(l);
    }
    public CellEditorListener[] getCellEditorListeners(){
        return (CellEditorListener[])cellListener.toArray();
    }
    public Object getCellEditorValue() {
        System.out.println("Liefere Selektiertes Object = "+box.getSelectedItem()+" fuer "+ident);
        return box.getSelectedItem();
    }
    
    public java.awt.Component getTableCellEditorComponent(javax.swing.JTable table, Object value, boolean isSelected, int row, int column) {
        if(value!= null){
              box.setSelectedItem(value);
                
            
        }
        return box;
    }
    
   
    public void cancelCellEditing(){
        System.out.println("cancel edititing");
        
    }
    public boolean stopCellEditing(){
        System.out.println("stop edititing");
        return true;
    }
    public void fireEditingStopped(){
        for(int i=0; i < cellListener.size(); i++){
            CellEditorListener list = (CellEditorListener)cellListener.get(i);
            System.out.println("fire edititing stopped");
            list.editingStopped(new ChangeEvent(this));
        }
    }
    public void fireEditingCanceled(){
        for(int i=0; i < cellListener.size(); i++){
            CellEditorListener list = (CellEditorListener)cellListener.get(i);
            System.out.println("fire edititing cancel");
            list.editingCanceled(new ChangeEvent(this));
        }
    }
    public boolean isCellEditable(EventObject evt){
        return true;
    }
    public boolean shouldSelectCell(EventObject evt){
        return true;
    }
    
    public void keyPressed(java.awt.event.KeyEvent e) {
        if(e.getKeyCode()==10)
            fireEditingStopped();
        
       
    }
    
    public void keyReleased(java.awt.event.KeyEvent e) {
    }
    
    public void keyTyped(java.awt.event.KeyEvent e) {
    }
    
}

Anzeige
Code:
/*
 * TestFrame.java
 *
 * Created on 6. Juli 2007, 14:00
 */


import javax.swing.*;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;


public class TestFrame extends JFrame{
    private JTable table = null;
    private DefaultTableColumnModel colModel = null;
    private TableColumn col = null;
    private CustomEditor editor = null;
    private DefaultTableModel tabModel = null;
    
    /** Creates new form TestFrame */
    public TestFrame() {
        initComponents();
        setSize(400,400);
        initFrame();
        
    }
    
    public void initFrame(){
        String[] content1 = {"A","AB","BA","BB","C"};
        String[] content2 = {"A","AB","BA","BB","CC"};
        
        JComboBox box1 = new JComboBox(content1);
        editor = new CustomEditor(box1,"Spalte 1");
        colModel = new DefaultTableColumnModel();
        col = new TableColumn();
        col.setHeaderValue("Spalte 1");
        col.setCellEditor(editor);
        colModel.addColumn(col);
        col = new TableColumn();
        col.setHeaderValue("Spalte 2");
        JComboBox box2 = new JComboBox(content2);
        editor = new CustomEditor(box2,"spalte 2");
        col.setCellEditor(editor);
        colModel.addColumn(col);
        tabModel = new DefaultTableModel(3,2);
        table = new JTable(tabModel,colModel);
        //table.setDefaultEditor(Object.class,editor);
        this.getContentPane().add(table);
        
    }
    
    
    
    
    
    public static void main(String args[]) {
        new TestFrame().show();
    }
    
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {

        getContentPane().setLayout(new java.awt.FlowLayout());

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        pack();
    }
    
    /** Exit the Application */
    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }

*gruß*
Timo
 
Hi Timo!


Ich hab dir mal was Vorbereitet:

TestFrame.java
Java:
package de.tutorials.cellRenderDemo;

/*
 * TestFrame.java
 *
 * Created on 6. Juli 2007, 14:00
 */


import javax.swing.*;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;



public class TestFrame extends JFrame{
    private JTable table = null;
    private DefaultTableColumnModel colModel = null;
    private TableColumn col = null;
    private CustomEditor editor = null;
    private DefaultTableModel tabModel = null;
    private CellRenderModel model = null;
    
    /** Creates new form TestFrame */
    public TestFrame() {
    	this.model = CellRenderModel.getInstance();
        initComponents();
        setSize(400,400);
        initFrame();
        
    }
    
    public void initFrame(){
        table = new JTable(model.getTableModel());
        table.getColumnModel().getColumn(0).setCellEditor(new CustomEditor());
        table.getColumnModel().getColumn(1).setCellEditor(new CustomEditor());
        this.getContentPane().add(table);
        
    }
    
    
    
    
    
    public static void main(String args[]) {
        new TestFrame().setVisible(true);
    }
    
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {

        getContentPane().setLayout(new java.awt.FlowLayout());

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        pack();
    }
    
    /** Exit the Application */
    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }
}

CustomEditor .java
Java:
package de.tutorials.cellRenderDemo;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;

public class CustomEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {

	private String value = ""; 
	private JComboBox box = null;
	
	public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
		
		String[] content1 = {"A","AB","BA","BB","C"};
        String[] content2 = {"A","AB","BA","BB","CC"};
		if (column == 0) {
			box = new JComboBox(content1);
			box.addActionListener(this);
			
		} else if (column == 1) {
			box = new JComboBox(content2);
			box.addActionListener(this);	
		}
        
        return box;
	}

	public Object getCellEditorValue() {
		// TODO Auto-generated method stub
		return value;
	}

	public void actionPerformed(ActionEvent e) {
		this.value = box.getSelectedItem().toString();
		
	}
      
}


CellRendererDemoDataSet .java
Java:
package de.tutorials.cellRenderDemo;

public class CellRendererDemoDataSet {
	
	private String val1 = "";
	private String val2 = "";
	
	public CellRendererDemoDataSet() {
		
	}

	public CellRendererDemoDataSet(String val1, String val2) {
		super();
		this.val1 = val1;
		this.val2 = val2;
	}

	public String getVal1() {
		return val1;
	}

	public void setVal1(String val1) {
		this.val1 = val1;
	}

	public String getVal2() {
		return val2;
	}

	public void setVal2(String val2) {
		this.val2 = val2;
	}
	
	

}


CellRenderModel.java
Java:
package de.tutorials.cellRenderDemo;

import java.util.Vector;

import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;

/**
 * @author MKI
 * Modelklasse für das CellRendererDemo
 */
public class CellRenderModel {
	
	private static CellRenderModel crm = null;
	private Vector<CellRendererDemoDataSet> data = null;
	
	/**
	 * Kunstruktor, private wg. Singleton
	 */
	private CellRenderModel() {
		this.data = new Vector<CellRendererDemoDataSet>();
		//Demo-Datensätze erzeugen
		CellRendererDemoDataSet ds1 = new CellRendererDemoDataSet("A", "A");
		CellRendererDemoDataSet ds2 = new CellRendererDemoDataSet("A", "A");
		CellRendererDemoDataSet ds3 = new CellRendererDemoDataSet("A", "A");
		data.add(ds1);
		data.add(ds2);
		data.add(ds3);
	}
	
	/**
	 * Singleton-Pattern, gibt eine unique Instanz zurück
	 * @return {@link CellRenderModel}
	 */
	public static CellRenderModel getInstance() {
		if (CellRenderModel.crm == null) {
			CellRenderModel.crm = new CellRenderModel();
		}
		return CellRenderModel.crm;
	}
	
	
	
	/**
	 * @return the data
	 */
	public Vector<CellRendererDemoDataSet> getData() {
		return data;
	}

	public TableModel getTableModel() {
		return new CellRendererDemoTableModel();
	}
	
	private class CellRendererDemoTableModel extends AbstractTableModel {

		private String[] columnNames = new String[] {"Wert 1", "Wert 2"};
		
		/**
		 * @see javax.swing.table.TableModel#getColumnCount()
		 */
		public int getColumnCount() {
			return columnNames.length;
		}

		/**
		 * @see javax.swing.table.TableModel#getRowCount()
		 */
		public int getRowCount() {
			return data.size();
		}

		/**
		 * @see javax.swing.table.TableModel#getValueAt(int, int)
		 */
		public Object getValueAt(int row, int col) {
			CellRendererDemoDataSet dataSet = data.get(row);
			if (col == 0) {
				return dataSet.getVal1();
			} else if (col == 1) {
				return dataSet.getVal2();
			}
			return "";	
		}

		/**
		 * @see javax.swing.table.AbstractTableModel#getColumnName(int)
		 */
		@Override
		public String getColumnName(int col) {
			return columnNames[col];
		}

		/**
		 * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
		 */
		@Override
		public boolean isCellEditable(int arg0, int arg1) {
			return true;
		}

		/**
		 * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int)
		 */
		@Override
		public void setValueAt(Object value, int row, int col) {
			CellRendererDemoDataSet dataSet = data.get(row);
			if (col == 0) {
				dataSet.setVal1(value.toString());
			} else if (col == 1) {
				dataSet.setVal2(value.toString());
			}
		}
		
		
		
	}
	
	

}

So, was machen die Klassen jetzt?
Zuerst einmal habe ich den DefaultColumnModel und das DefaultTableModel rausgeschmissen und durch ein eigenes TableModel ersetzt. Dieses ist als innere Klasse in der Klasse CellRenderModel implementiert und erbt von AbstractTableModel. Das CellRenderModel enthält dabei deine Tabellendaten.
Dadurch hast du vor allem zwei Vorteile:

1. Datenhaltung und GUI sind von einander getrennt. Dadurch ist dein Code besser strukturiert.
2. Das TableModel steuert alle Parameter deiner JTable (Spalte editierbar, Spaltennamen...)

Die Tabellendaten selber habe ich zwecks der Übersicht in eine eigene Klasse (CellRendererDemoDataSet) verfrachtet - prinzipiell kannst du deine Daten jedoch auch in anderer Form ablegen.
In deiner View habe ich dann das Model an die JTable geknüpft. Dies geschieht entweder direkt im Konstruktor oder über die Methode setModel.
Den einzelnen Spalten der JTable habe ich dann jeweils einen CustomEditor zugewiesen.

Ich hoffe mal, das hilft dir weiter.

Gruss, Manuel
 
Zurück