Seltsames Verhalten meiner CheckBoxen

darkmoon221

Mitglied
Guten Morgen zusammen,

ich habe es nun geschafft, CheckBoxen in meiner JTable darzustellen und sieht eigentlich sehr gut aus.
Jetzt hab ich nur noch das Problem dass diese ein sehr seltsames Verhalten aufweisen.

Es ist etwas schwer, das Problem richtig zu beschreiben, jetzt hab ich mal ein kleines Video angefertigt:

Ich hoffe es ist erlaubt auf ein Video zu verweisen 🙂

ImageShack® - Online Photo and Video Hosting
 
Hast du das mit dem JTable umgesetzt? Dann tippe ich mal auf den CellEditor. Hast du dafür eine eigenen Implementation geschrieben? Falls ja, poste diese mal.
 
Hier ist mal meine Methode aus meinem TableModel

Java:
@Override
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {		
		ScribeApplication myScribe = OverviewGui.getScribe();
		String topicName = (String) getValueAt(rowIndex, columnIndex+1);
		System.out.println("MyTableModel: "+topicName);
		if(columnIndex == 0){
			if(aValue == (Object)true){
				aValue = false;
				myScribe.unsubscribe(topicName);
			}else{
				aValue = true;
				myScribe.subscribe(topicName);
			}
		}
		
		
	}



Und mein CellEditor

Java:
public class MyCellEditor extends AbstractCellEditor implements TableCellEditor {

	private static Logger logger = Logger.getLogger(MyCellEditor.class);

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	final JCheckBox check = new JCheckBox();

	@Override
	public Object getCellEditorValue() {
		return check.isSelected();
	}

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

		if (isSelected && column == 0) {
			check.setSelected(false);
			logger.info("CheckBox was selected and is now deselected");

		} else if (!isSelected && column == 0) {
			check.setSelected(true);
			logger.info("CheckBox was deselected and is now selected");
		}

		check.setBackground(new Color(51, 51, 51));

		return check;
	}

}


Sollte ich den Code der setValueAt eher in die CellEditor packen ?
 
Hier mal was auf die schnelle:
Java:
import java.awt.Component;

import javax.swing.AbstractCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;

public class TableDemo 
{
	public static void main(String[] args) 
	{
		final JFrame frame=new JFrame("Sample");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JTable table=new JTable(new Object[][] {{true},{false}},new Object[] {"A"});

		table.getColumn("A").setCellRenderer(new TableRenderer());
		table.getColumn("A").setCellEditor(new TableEditor());
		
		frame.add(new JScrollPane(table));
		
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				frame.setVisible(true);
			}
		});		
	}
	
	static class TableEditor extends AbstractCellEditor implements TableCellEditor
	{
		private JCheckBox checkBox=new JCheckBox();
		
		
		@Override
		public Object getCellEditorValue() {
			return checkBox.isSelected();
		}

		@Override
		public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) 
		{
			checkBox.setSelected((Boolean) value);
			return checkBox;
		}
	}
	
	static class TableRenderer extends DefaultTableCellRenderer
	{
		private JCheckBox checkBox=new JCheckBox();
		
		@Override
		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int column) {
			
			checkBox.setSelected((Boolean)value);
			
			return checkBox;
		}
	}
}

Habe schon lange nix mehr mit Editoren gemacht. Aber ich denke, das setValue da irgendwie einzubauen ist sicherlich nicht verkehrt. Ansonsten steht es afaik nicht im Model. Musst du mal ausprobieren.
 
So ich muss jetzt mal einfach alle Klassen posten die was mit meiner JTable zu tun haben.
Wahrscheinlich hab ich irgendwo nen Fehler drin und kommme nicht drauf.

Als zuerst die Klasse die eine TableRow darstellt:

Java:
ublic class TopicRow {

	// a checkbox is represented by a boolean value here
	private Boolean checkbox;
	private String label;
	private ImageIcon icon;

	/**
	 * Constructor
	 * 
	 * @param checkbox
	 *            the initial checkbox value
	 * @param label
	 *            label which schould be displayed
	 * @param icon
	 *            shown if new messages are available in a topic
	 */
	public TopicRow(Boolean checkbox, String label, ImageIcon icon) {
		this.checkbox = checkbox;
		this.label = label;
		this.icon = icon;

	}

	/**
	 * Getter for checkbox
	 * 
	 * @return checkbox
	 */
	public Boolean getCheckBox() {
		return checkbox;
	}

	/**
	 * Getter for label
	 * 
	 * @return label
	 */
	public String getLabel() {
		return label;
	}

	/**
	 * Getter for icon
	 * 
	 * @return icon
	 */
	public ImageIcon getIcon() {
		return icon;
	}
	
	public void setCheckBox(boolean value){
		checkbox = value;
	}

}

dann mein model für die Tabelle:

Java:
package de.peerstream.gui;

import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;

import org.apache.log4j.Logger;

import de.peerstream.scribe.ScribeApplication;


/**
 * This class manages the insertion of data into the table
 * 
 * @author
 *
 */
public class MyTableModel implements TableModel{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;



	private static Logger logger = Logger.getLogger(MyTableModel.class);
	
	
	
	private Vector<TopicRow> topicRows = new Vector<TopicRow>();
	private Vector<TableModelListener> listeners = new Vector<TableModelListener>();
	
	public void addTableRow(TopicRow topicRow){
		// Index of topicRow
        int index = topicRows.size();
        topicRows.add(topicRow);
        
        // create event "insert new row"
        TableModelEvent e = new TableModelEvent( this, index, index, 
                TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT );
        
        // send the event
        for( int i = 0, n = listeners.size(); i<n; i++ ){
            ((TableModelListener)listeners.get( i )).tableChanged( e );
        }
		
		logger.info("Added a new row to the table model");
	}
	@Override
	public void addTableModelListener(TableModelListener l) {
		listeners.add(l);
		
	}
	@Override
	public Class<?> getColumnClass(int columnIndex) {
        switch( columnIndex ){
            case 0: return Boolean.class;
            case 1: return String.class;
            case 2: return ImageIcon.class;
            default: return null;
        }   
    }
	@Override
	public int getColumnCount() {
		return 3;
	}
	@Override
	public String getColumnName(int columnIndex) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public int getRowCount() {
		return topicRows.size();
	}
	
	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
        TopicRow topicRow = (TopicRow)topicRows.get( rowIndex );
        
        switch( columnIndex ){
            case 0: return topicRow.getCheckBox() ? Boolean.TRUE : Boolean.FALSE;
            case 1: return topicRow.getLabel();
            case 2: return topicRow.getIcon();
            default: return null;
        }
    }
	@Override
	public boolean isCellEditable(int rowIndex, int columnIndex) {
		if(columnIndex == 0){
			return true;
		}else{
			return false;
		}
	}
	@Override
	public void removeTableModelListener(TableModelListener l) {
		listeners.remove(l);		
	}
	
	@Override
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {		
		ScribeApplication myScribe = OverviewGui.getScribe();
		
		String topicName = (String) getValueAt(rowIndex, columnIndex+1);
		System.out.println("MyTableModel: "+topicName);
		
		if(columnIndex == 0){
			if(aValue == (Object)true){
				aValue = false;
				
				myScribe.unsubscribe(topicName);
				System.out.println(aValue);
			}else{
				aValue = true;
				myScribe.subscribe(topicName);
				System.out.println(aValue);
			}
		}
		
		
	}
}

Der TableCellRenderer

Java:
package de.peerstream.gui;

import java.awt.Color;
import java.awt.Component;

import javax.swing.JCheckBox;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

public class MyTableRenderer extends DefaultTableCellRenderer {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	 private JCheckBox checkBox=new JCheckBox();
     
     @Override
     public Component getTableCellRendererComponent(JTable table,
             Object value, boolean isSelected, boolean hasFocus, int row,
             int column) {
         
         checkBox.setSelected((Boolean)value);
         checkBox.setBackground(new Color(51, 51, 51));
         return checkBox;
     }

}


der TableCellEditor

Java:
public class MyCellEditor extends AbstractCellEditor implements TableCellEditor {

	private static Logger logger = Logger.getLogger(MyCellEditor.class);

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	final JCheckBox check = new JCheckBox();

	@Override
	public Object getCellEditorValue() {
		return check.isSelected();
	}

	@Override
	public Component getTableCellEditorComponent(JTable table, Object value,
			boolean isSelected, int row, int column) {
		
		check.setSelected((Boolean) value);
		check.setBackground(new Color(51, 51, 51));
        return check;

und zum Schluss noch die Methode in der ich die Tabelle befülle:

Java:
MyTableModel model = new MyTableModel();
		
		table = new JTable(model) {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			// add specific tooltip to each topic
			public String getToolTipText(MouseEvent e) {
				String tip = null;
				java.awt.Point point = e.getPoint();
				int rowIndex = rowAtPoint(point);
				int colIndex = columnAtPoint(point);
				int realColumnIndex = convertColumnIndexToModel(colIndex);

				if (realColumnIndex == 1) { // Text column
					String topicName = (String) getValueAt(rowIndex, colIndex);

					tip = pastActions.getTopicDescription(topicName);

				} else {
					// You can omit this part if you know you don't
					// have any renderers that supply their own tool
					// tips.
					tip = super.getToolTipText(e);
				}
				return tip;
			}
		};

		// table color and additional settings
		table.setForeground(Color.WHITE);
		table.setBackground(new Color(51, 51, 51));
		table.setSelectionBackground(new Color(51, 51, 51));
		table.setSelectionForeground(Color.WHITE);
		table.setShowHorizontalLines(false);
		table.setShowVerticalLines(false);
		table.setColumnSelectionAllowed(true);
		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		table.updateUI();

		// set width of checkbox column and icon column
		TableColumnModel columnModel = table.getColumnModel();
		columnModel.getColumn(0).setMaxWidth(20);
		columnModel.getColumn(2).setMaxWidth(25);
		table.setRowHeight(25);

		// add cell editor and renderer to checkbox column
		TableColumn checkBoxColumn = table.getColumnModel().getColumn(0);
		MyCellEditor editor = new MyCellEditor();
		MyTableRenderer renderer = new MyTableRenderer();
		checkBoxColumn.setCellEditor(editor);
		checkBoxColumn.setCellRenderer(renderer);

		// for testing set the icon to each row
		for (String top : topics) {
			URL img = OverviewGui.class.getResource("notification.png");
			ImageIcon imgIcon = new ImageIcon(img);

			TopicRow row = new TopicRow(new Boolean(true), top, imgIcon);
			model.addTableRow(row);
			logger.info("Added new row to the table model");

		}	
		checkBox.add(table);
		parent.repaint();
		parent.validate();
	}
 
Zuletzt bearbeitet:
Das stimmt so nicht:
Java:
public Component getTableCellRendererComponent(JTable table,
             Object value, boolean isSelected, boolean hasFocus, int row,
             int column) {
         
         checkBox.setSelected((Boolean)value);
         checkBox.setBackground(new Color(51, 51, 51));
         return checkBox;
     }
Selected im Table != angehakte Checkbox. Wenn getTableCellRendererComponent dir als isSelected true übergibt heisst das, dass die Zelle markiert ist.
Edit: checkBox.setBackground(new Color(51, 51, 51)); musst du eigentlich auch nicht jedes mal neu machen oder? Das könntest du in den Konstruktor packen.
 
Zuletzt bearbeitet:
Hab vergessen den true oder false Wert auch in meiner TopicRow-Klasse zu ändern.

Jetzt funktionierts.

Jetzt muss ich nur noch kurz nachfragen, wo ich meine Logik implementieren soll, wenn eine checkbox angehackt wird. Muss ich das in meiner Model-Klasse machen oder eher in der TableCellEditor-Klasse?

Danke im Voraus
 

Zurück
Oben