Schachtelung (Composite Pattern?) von komponenten in SWT

Hallo

ich würde gerne wissen, ob ich eine Liste von checkboxen in einer Zelle einer Table darstellen kann (Man soll natürlich die einzelnen checkboxen anklicken können)?

Desweiteren würde ich gerne wenn ich in eine Zelle klicke, genau an der Stelle (x, y koordinaten und höhe und Breite der Zelle) an der die Zelle ist eine Checkbox erscheinen lassen. Da kann man dann etwas auswählen und das wird dann zurück in die Zelle geschrieben...

Viele Dank für die hilfe
 
ich würde gerne wissen, ob ich eine Liste von checkboxen in einer Zelle einer Table darstellen kann (Man soll natürlich die einzelnen checkboxen anklicken können)?

Warum willst Du denn mehrere Boxen in eine Zelle schreiben. Mach doch einfach mehrere Zellen. Ansonsten musst Du Dir einen eigenen TableCellEditor programmieren. Geht auch, ist aber ungleich komplizierter.

Desweiteren würde ich gerne wenn ich in eine Zelle klicke, genau an der Stelle (x, y koordinaten und höhe und Breite der Zelle) an der die Zelle ist eine Checkbox erscheinen lassen. Da kann man dann etwas auswählen und das wird dann zurück in die Zelle geschrieben...

Das verstehe ich nicht. Eine Checkbox pro Zelle? Schau mal hier

http://www.eclipse.org/articles/Article-Table-viewer/table_viewer.html

und in die Zelle zurückschreiben geht, aber schreib doch lieber gleich in Dein Datenmodel zurück.

Vielleicht holst Du ein fach mal weiter aus und schreibst was Du vorhast.

Grüße
 
Zu zwei. Ich wollte nicht Checkbox sagen, sondern ComboBox :) Also hilft der Artikel schonmal :) Danke

Und zum ersten problem es soll ungefähr so aussehen wie auf dem Bild:
Und das ganze für beliebig viele Spalten und Zeilen. Wenn jemand eine andere Darstellung weiß, bitte bescheid sagen, aber im Grunde sollte das Konzeopt so aussehen
 

Anhänge

  • Beispiel.jpg
    Beispiel.jpg
    26,7 KB · Aufrufe: 117
Ich denke nicht, das es ein solches Control gibt. Du kannst es Dir aber selbst schreiben. Dazu musst Du Deine Tabelle mit einem JFace TableViewer umhüllen. Artikel siehe oben. Die Klassen CheckboxCellEditor und TextCellEditor etc. erben alle von CellEditor. Dies sind alles JFace-Klassen. Wenn Du einen eigenen Editor schreiben möchtest, musst die Klasse CellEditor erweitern. Da kannst Du reinbauen, was Du willst.Der Editor gilt dann immer für eine ganze Spalte.

Grüße
 
Vielen Dank. Einfacher wäre es natürlich wenn das schonmal jemand gemacht hat. Mir würde auch ne Liste reichen in der ich dann Elemente anklicken könnte und nen hacken setzen könnte. Also falls jemand sowas schon gemacht hat, wäre ich seh dankbar für den code :)

Schöne Abend und schönes Wochenende
 
Lol, klar wäre das einfacher. Aber hart ist das Programmiererleben ;-)

Hier mal ein schneller Hack dazu. Ich habe eine DatenKlasse geschrieben, die ein BitSet verwendet um die Werte für die Checkboxen zu speichern. Das passiert in Spalte eins. In dieser Spalte siehst Du immer die Zahl der gesetzen Bits. Wenn Du reinclickst, geht der CellEditor auf, den ich geschrieben habe. Eigentlich brauchst Du nur den. Der Rest ist zum Testen. Der Editor erwartet ein Bitset mit 4 Bit. Das kannst Du natürlich umschreiben. Das Programm ist kein Plugincode,sondern eine normale Anwendung, deshalb musst Du folgende JARS aus dem Eclipse Pluginverzeichnis einbinden:

org.eclipse.core.commands.jar
org.eclipse.core.resources.jar
org.eclipse.equinox.common.jar
org.eclipse.jface.jar
org.eclipse.jface.text.jar
org.eclipse.swt.jar
org.eclipse.swt.win32.jar

jeweils in der Versionsnummer Deiner Eclipseumgebung. Ich verwende Eclipse 3.3.

In Spalte zwei passiert nix ausser einem normalen TextCellEditor.


Java:
package de.tutorials;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.Observable;
import java.util.Observer;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;





public class Demo {

	private static final Display display = new Display();
	private Shell shell = null;
	private TableViewer tableViewer = null;
	private DatenModell model = new DatenModell();
	
	public Demo() {
		dispatch();
		
	}
	

	private void dispatch() {
		getShell().open();
		while(! getShell().isDisposed()) {
			if(!display.readAndDispatch()) display.sleep();
		}
		display.dispose();
		
	}


	private Shell getShell() {
		if(shell == null) {
			shell = new Shell(display);
			shell.setLayout(new FillLayout());
			getTableViewer();
			
		}
		return shell;
	}




	private TableViewer getTableViewer() {
		if (tableViewer == null) {
			tableViewer = new TableViewer(getShell(),SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
			tableViewer.setLabelProvider(new MyTableLabelProvider());
			tableViewer.setContentProvider(new MyContentProvider());
			tableViewer.setInput(model);
		}
		return tableViewer;
	}




	public static void main(String[] args) {

		new Demo();

	}
	
	class MultiCheckBoxCellEditor extends CellEditor {
		
		private Button bit0;
		private Button bit1;
		private Button bit2;
		private Button bit3;

		private BitSet bitFeld = null;

		public MultiCheckBoxCellEditor() {
			super();
			
		}

		public MultiCheckBoxCellEditor(Composite parent, int style) {
			super(parent, style);
			
		}

		public MultiCheckBoxCellEditor(Composite parent) {
			super(parent);
			
		}
		
		@Override
		protected Control createControl(Composite composite) {
			if(bitFeld ==null) bitFeld = new BitSet();
			Composite retval = new Composite(composite,SWT.NONE);
			retval.setLayout(new RowLayout());
			bit0 = new Button(retval,SWT.CHECK);
			bit0.setText("bit 0");
			bit0.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(0, bit0.getSelection());
				}
				
			});
			
			bit1 = new Button(retval,SWT.CHECK);
			bit1.setText("bit 1");
			bit1.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(1, bit1.getSelection());
				}
				
			});
			bit2 = new Button(retval,SWT.CHECK);
			bit2.setText("bit 2");
			bit2.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(2, bit2.getSelection());
				}
				
			});
			bit3 = new Button(retval,SWT.CHECK);
			bit3.setText("bit 3");
			bit3.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(3, bit3.getSelection());
				}
				
			});
			return retval;
		}

		@Override
		protected Object doGetValue() {
			
			return bitFeld;
		}

		@Override
		protected void doSetFocus() {
			
			
		}

		@Override
		protected void doSetValue(Object object) {
			this.bitFeld = (BitSet) object;
			bit0.setSelection(bitFeld.get(0));
			bit1.setSelection(bitFeld.get(1));
			bit2.setSelection(bitFeld.get(2));
			bit3.setSelection(bitFeld.get(3));
		
		}
		
	}
	
	class MyCellModifier implements ICellModifier {

		@Override
		public boolean canModify(Object arg0, String arg1) {
			return true;
		}

		@Override
		public Object getValue(Object element, String property) {
			DatenKlasse datenKlasse = (DatenKlasse) element;
			if(property .equalsIgnoreCase("BitFeld"))
				return datenKlasse.getFlags();
			else
				return datenKlasse.getLabel();
		}

		@Override
		public void modify(Object element, String property, Object value) {
			DatenKlasse datenKlasse = (DatenKlasse)((TableItem) element).getData();
			if(property .equalsIgnoreCase("BitFeld"))
				datenKlasse.setFlags((BitSet) value);
			else
				datenKlasse.setLabel((String) value);
			
			
		}
		
	}
	class MyTableLabelProvider extends LabelProvider implements ITableLabelProvider {

		private String [] columnNames = {"BitFeld","Label"};
		private int [] columnAligments = {SWT.CENTER, SWT.LEFT};
		private int [] columnWidth = {400,200};
		
		public MyTableLabelProvider() {
			// Tabelle formatieren und Editoren vorbereiten
			
			//Formatieren
			Table table = getTableViewer().getTable();
			

			table.setHeaderVisible(true);
			table.setLinesVisible(true);
			for(int i = 0; i < columnAligments.length; i++) {
				TableColumn column = new TableColumn(table,columnAligments[i]);
				column.setText(columnNames[i]);
				column.setWidth(columnWidth[i]);
			}
			
			table.addListener(SWT.MeasureItem, new Listener(){ 

		         public void handleEvent(Event event) { 
		                        event.height = event.gc.getFontMetrics().getHeight() *2; 
		         } 
		          
		      }); 
			
			// Editoren
			getTableViewer().setColumnProperties(columnNames);
			MultiCheckBoxCellEditor multiCheckBoxCellEditor = new MultiCheckBoxCellEditor(table);
			TextCellEditor textCellEditor = new TextCellEditor(table);
			getTableViewer().setCellEditors(new CellEditor[]{multiCheckBoxCellEditor,textCellEditor});
			getTableViewer().setCellModifier(new MyCellModifier());
			
		}
		@Override
		public Image getColumnImage(Object arg0, int arg1) {
			return null;
		}

		@Override
		public String getColumnText(Object datensatz, int spalte) {
			if(spalte == 0)
				return "" + ((DatenKlasse) datensatz).getFlags().cardinality();
			else 
				return ((DatenKlasse) datensatz).getLabel();
		}
		
	}
	
	//ContentProvider für TableViewer
	class MyContentProvider implements IStructuredContentProvider, Observer {

		private TableViewer tableViewer;
		@Override
		public Object[] getElements(Object arg0) {
			return model.toArray();
		}

		@Override
		public void dispose() {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void inputChanged(Viewer viewer, Object oldSource, Object newSource) {
			this.tableViewer = (TableViewer) viewer;
			if(oldSource != null){
				((DatenModell) oldSource).deleteObserver(this);
			}
			if(newSource != null){
				((DatenModell) newSource).addObserver(this);
			}
				
			
		}

		// Schutziger Trick zum einfachen neuzeichnen der Tabelle
		@Override
		public void update(Observable o, Object arg) {
			tableViewer.refresh();
			
		}
	}
	
	// Container für Zeilen, das Datenmodell eben ;-)
	class DatenModell extends Observable implements Observer{
		private ArrayList<DatenKlasse> daten = new ArrayList<DatenKlasse>();

		// Mit Spieldaten füllen
		public DatenModell() {
			
			add(new DatenKlasse(new BitSet(4), "test1"));
			add(new DatenKlasse(new BitSet(4), "test2"));
			add(new DatenKlasse(new BitSet(4), "test3"));
			add(new DatenKlasse(new BitSet(4), "test4"));
			add(new DatenKlasse(new BitSet(4),"test5"));
		}
		public void  add(DatenKlasse datenKlasse) {
			datenKlasse.addObserver(this);
			daten.add(datenKlasse);
			fireEvent();
		}

		public void  remove(DatenKlasse datenKlasse) {
			datenKlasse.deleteObserver(this);
			daten.remove(datenKlasse);
			fireEvent();
		}

		public Object[] toArray() {
			return daten.toArray();
		}

		public String toString() {
			return daten.toString();
		}

		@Override
		public void update(Observable arg0, Object arg1) {
			fireEvent();
			
		}
		private void fireEvent() {
			setChanged();
			notifyObservers();
		}
		
	}
	
	// Spielklasse mit Daten für eine einzelne Zeile in der Tabelle (zweispaltig mit bitfeld und String)
	class DatenKlasse extends Observable{
		private BitSet flags = new BitSet();
		private String label = "";
		
		public DatenKlasse() {
			this(new BitSet(4),"");
		}
		public DatenKlasse(BitSet flags, String label) {
			super();
			this.flags = flags;
			this.label = label;
		}
		public BitSet getFlags() {
			return flags;
		}
		public void setFlags(BitSet flags) {
			this.flags = flags;
			fireEvent();
		}
		public String getLabel() {
			return label;
		}
		public void setLabel(String label) {
			this.label = label;
			fireEvent();
		}
		
		private void fireEvent() {
			setChanged();
			notifyObservers();
		}
		
		
		
	}
}

Hoffe es hilft! Grüße aus Hessen.

EDIT: Wenn Du das Layout des Editors ändern willst, (z.B. die Checkboxen untereinander) musst Du nur das RowLayout in ein anders ändern. Im Code ist auch ein Trick um die Zeilenhöhe bei SWT-Tabelle zu ändern. ;-)

EDIT2: Und wenn Dir arg langweilig ist. Schau dir hier den Quellcode des orginalen Texteditors an.

http://www.google.de/codesearch?hl=...org/eclipse/jface/viewers/TextCellEditor.java
 
Zuletzt bearbeitet:
Vielen Dank, das hilft mir sehr weiter. Was ich allerdings noch brauche:
Nach dem makieren der Checkboxen soll in der Zelle nicht die Anzahl der selektierten Checkboxen stehen, sonder als Text die Bezeichnungen der selektierten Boxen. am besten mit komma getrennt.

Ich find es einfach nicht, wo ich das ändern kann... Oh man ist wohl schon ziemlich spät...
 
Wie der Herr wünschen.... ;-)

Java:
package de.tutorials;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.Observable;
import java.util.Observer;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;





public class Demo {

	private static final Display display = new Display();
	private Shell shell = null;
	private TableViewer tableViewer = null;
	private DatenModell model = new DatenModell();
	
	public Demo() {
		dispatch();
		
	}
	

	private void dispatch() {
		getShell().open();
		while(! getShell().isDisposed()) {
			if(!display.readAndDispatch()) display.sleep();
		}
		display.dispose();
		
	}


	private Shell getShell() {
		if(shell == null) {
			shell = new Shell(display);
			shell.setLayout(new FillLayout());
			getTableViewer();
			
		}
		return shell;
	}




	private TableViewer getTableViewer() {
		if (tableViewer == null) {
			tableViewer = new TableViewer(getShell(),SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
			tableViewer.setLabelProvider(new MyTableLabelProvider());
			tableViewer.setContentProvider(new MyContentProvider());
			tableViewer.setInput(model);
		}
		return tableViewer;
	}




	public static void main(String[] args) {

		new Demo();

	}
	
	class MultiCheckBoxCellEditor extends CellEditor {
		
		private Button bit0;
		private Button bit1;
		private Button bit2;
		private Button bit3;

		private BitSet bitFeld = null;

		public MultiCheckBoxCellEditor() {
			super();
			
		}

		public MultiCheckBoxCellEditor(Composite parent, int style) {
			super(parent, style);
			
		}

		public MultiCheckBoxCellEditor(Composite parent) {
			super(parent);
			
		}
		
		
		
		@Override
		protected Control createControl(Composite composite) {
			if(bitFeld ==null) bitFeld = new BitSet();
			Composite retval = new Composite(composite,SWT.NONE);
			retval.setLayout(new RowLayout());
			bit0 = new Button(retval,SWT.CHECK);
			bit0.setText("bit 0");
			bit0.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(0, bit0.getSelection());
				}
				
			});
			
			bit1 = new Button(retval,SWT.CHECK);
			bit1.setText("bit 1");
			bit1.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(1, bit1.getSelection());
				}
				
			});
			bit2 = new Button(retval,SWT.CHECK);
			bit2.setText("bit 2");
			bit2.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(2, bit2.getSelection());
				}
				
			});
			bit3 = new Button(retval,SWT.CHECK);
			bit3.setText("bit 3");
			bit3.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(3, bit3.getSelection());
				}
				
			});
			return retval;
		}

		@Override
		protected Object doGetValue() {
			
			return bitFeld;
		}

		@Override
		protected void doSetFocus() {
			
			
		}

		@Override
		protected void doSetValue(Object object) {
			this.bitFeld = (BitSet) object;
			bit0.setSelection(bitFeld.get(0));
			bit1.setSelection(bitFeld.get(1));
			bit2.setSelection(bitFeld.get(2));
			bit3.setSelection(bitFeld.get(3));
		
		}
		
	}
	
	class MyCellModifier implements ICellModifier {

		@Override
		public boolean canModify(Object arg0, String arg1) {
			return true;
		}

		@Override
		public Object getValue(Object element, String property) {
			DatenKlasse datenKlasse = (DatenKlasse) element;
			if(property .equalsIgnoreCase("BitFeld"))
				return datenKlasse.getFlags();
			else
				return datenKlasse.getLabel();
		}

		@Override
		public void modify(Object element, String property, Object value) {
			DatenKlasse datenKlasse = (DatenKlasse)((TableItem) element).getData();
			if(property .equalsIgnoreCase("BitFeld"))
				datenKlasse.setFlags((BitSet) value);
			else
				datenKlasse.setLabel((String) value);
			
			
		}
		
	}
	class MyTableLabelProvider extends LabelProvider implements ITableLabelProvider {

		private String [] columnNames = {"BitFeld","Label"};
		private int [] columnAligments = {SWT.CENTER, SWT.LEFT};
		private int [] columnWidth = {400,200};
		
		public MyTableLabelProvider() {
			// Tabelle formatieren und Editoren vorbereiten
			
			//Formatieren
			Table table = getTableViewer().getTable();
			

			table.setHeaderVisible(true);
			table.setLinesVisible(true);
			for(int i = 0; i < columnAligments.length; i++) {
				TableColumn column = new TableColumn(table,columnAligments[i]);
				column.setText(columnNames[i]);
				column.setWidth(columnWidth[i]);
			}
			
			table.addListener(SWT.MeasureItem, new Listener(){ 

		         public void handleEvent(Event event) { 
		                        event.height = event.gc.getFontMetrics().getHeight() *2; 
		         } 
		          
		      }); 
			
			// Editoren
			getTableViewer().setColumnProperties(columnNames);
			MultiCheckBoxCellEditor multiCheckBoxCellEditor = new MultiCheckBoxCellEditor(table);
			TextCellEditor textCellEditor = new TextCellEditor(table);
			getTableViewer().setCellEditors(new CellEditor[]{multiCheckBoxCellEditor,textCellEditor});
			getTableViewer().setCellModifier(new MyCellModifier());
			
		}
		@Override
		public Image getColumnImage(Object arg0, int arg1) {
			return null;
		}

		@Override
		public String getColumnText(Object datensatz, int spalte) {
			if(spalte == 0)
				return "" + ((DatenKlasse) datensatz).getFlagsToString();
			else 
				return ((DatenKlasse) datensatz).getLabel();
		}
		
	}
	
	//ContentProvider für TableViewer
	class MyContentProvider implements IStructuredContentProvider, Observer {

		private TableViewer tableViewer;
		@Override
		public Object[] getElements(Object arg0) {
			return model.toArray();
		}

		@Override
		public void dispose() {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void inputChanged(Viewer viewer, Object oldSource, Object newSource) {
			this.tableViewer = (TableViewer) viewer;
			if(oldSource != null){
				((DatenModell) oldSource).deleteObserver(this);
			}
			if(newSource != null){
				((DatenModell) newSource).addObserver(this);
			}
				
			
		}

		// Schutziger Trick zum einfachen neuzeichnen der Tabelle
		@Override
		public void update(Observable o, Object arg) {
			tableViewer.refresh();
			
		}
	}
	
	// Container für Zeilen, das Datenmodell eben ;-)
	class DatenModell extends Observable implements Observer{
		private ArrayList<DatenKlasse> daten = new ArrayList<DatenKlasse>();

		// Mit Spieldaten füllen
		public DatenModell() {
			
			add(new DatenKlasse(new BitSet(4), "test1"));
			add(new DatenKlasse(new BitSet(4), "test2"));
			add(new DatenKlasse(new BitSet(4), "test3"));
			add(new DatenKlasse(new BitSet(4), "test4"));
			add(new DatenKlasse(new BitSet(4),"test5"));
		}
		public void  add(DatenKlasse datenKlasse) {
			datenKlasse.addObserver(this);
			daten.add(datenKlasse);
			fireEvent();
		}

		public void  remove(DatenKlasse datenKlasse) {
			datenKlasse.deleteObserver(this);
			daten.remove(datenKlasse);
			fireEvent();
		}

		public Object[] toArray() {
			return daten.toArray();
		}

		public String toString() {
			return daten.toString();
		}

		@Override
		public void update(Observable arg0, Object arg1) {
			fireEvent();
			
		}
		private void fireEvent() {
			setChanged();
			notifyObservers();
		}
		
	}
	
	// Spielklasse mit Daten für eine einzelne Zeile in der Tabelle (zweispaltig mit bitfeld und String)
	class DatenKlasse extends Observable{
		private BitSet flags = new BitSet();
		private String label = "";
		
		public DatenKlasse() {
			this(new BitSet(4),"");
		}
		public DatenKlasse(BitSet flags, String label) {
			super();
			this.flags = flags;
			this.label = label;
		}
		public BitSet getFlags() {
			return flags;
		}
		public void setFlags(BitSet flags) {
			this.flags = flags;
			fireEvent();
		}
		public String getLabel() {
			return label;
		}
		public void setLabel(String label) {
			this.label = label;
			fireEvent();
		}
		
		public String getFlagsToString(){
			// Geht sicher besser, aber ich bin noch müde
			StringBuilder builder = new StringBuilder();
			boolean flag = false;
			if (flags.get(0)){
				builder.append("Bit 0");
				flag = true;
			}
			
			if (flags.get(1)){
				if(flag)
					builder.append(",");
				builder.append("Bit 1");
				flag = true;
			}
			
			if (flags.get(2)){
				if(flag)
					builder.append(",");
				builder.append("Bit 2");
				flag = true;
			}
			
			if (flags.get(3)){
				if(flag)
					builder.append(",");
				builder.append("Bit 3");
				flag = true;
			}
			
			
			if(builder.length() == 0)
				builder.append("Keine Bits gesetzt.");
			return builder.toString();
		}
		
		private void fireEvent() {
			setChanged();
			notifyObservers();
		}
		
		
		
	}
}
 
Hier das ganze nochmal mit ein paar Kommentaren. Mich würde der Hintergrund trotzdem mal interessieren. Warum macht Du Dir (bzw. mir ;-)) diese Mühe. Was spricht dagegen, einzelne Checkboxen in die Zeile zu packen? Das ist mit völlig unklar. (Mich hat nur das Problem mit dem eigenen CellEditor gereizt.)

Java:
package de.tutorials;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.Observable;
import java.util.Observer;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;





public class Demo {

	private static final Display display = new Display();
	private Shell shell = null;
	private TableViewer tableViewer = null;
	private DatenModell model = new DatenModell();
	
	public Demo() {
		dispatch();
		
	}
	

	private void dispatch() {
		getShell().open();
		while(! getShell().isDisposed()) {
			if(!display.readAndDispatch()) display.sleep();
		}
		display.dispose();
		
	}


	private Shell getShell() {
		if(shell == null) {
			shell = new Shell(display);
			shell.setLayout(new FillLayout());
			getTableViewer();
			
		}
		return shell;
	}




	private TableViewer getTableViewer() {
		if (tableViewer == null) {
			tableViewer = new TableViewer(getShell(),SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
			tableViewer.setLabelProvider(new MyTableLabelProvider());
			tableViewer.setContentProvider(new MyContentProvider());
			tableViewer.setInput(model);
		}
		return tableViewer;
	}




	public static void main(String[] args) {

		new Demo();

	}
	/*
	 * 
	 * Dies ist mein simpler MultiCheckBoxCellEditor. Der ist natürlich sehr statisch. Man könnte im  Konstruktor 
	 * ein StringArray mit Labels mitgeben, und er baut sich daraus die Checkboxen dynamisch auf.
	 * Aber ein bißchen Arbeit wollte ich Dir auch lassen ;-).
	 * 
	 * Durch dem CellModifier (siehe unten) werden die Methoden doGetValue aufgerufen, wenn der Editor den Focus verliert um die Daten 
	 * aus dem Editor zu lesen, bzw. umgekehrt die Daten  mit doSetValue zu übergeben, wenn der Editor den Focus erhält.
	 *
	 */
	class MultiCheckBoxCellEditor extends CellEditor {
		
		private Button bit0;
		private Button bit1;
		private Button bit2;
		private Button bit3;

		private BitSet bitFeld = null;

		public MultiCheckBoxCellEditor() {
			super();
			
		}

		public MultiCheckBoxCellEditor(Composite parent, int style) {
			super(parent, style);
			
		}

		public MultiCheckBoxCellEditor(Composite parent) {
			super(parent);
			
		}
		
		
		
		@Override
		protected Control createControl(Composite composite) {
			if(bitFeld ==null) bitFeld = new BitSet();
			Composite retval = new Composite(composite,SWT.NONE);
			retval.setLayout(new RowLayout());
			bit0 = new Button(retval,SWT.CHECK);
			bit0.setText("bit 0");
			bit0.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(0, bit0.getSelection());
				}
				
			});
			
			bit1 = new Button(retval,SWT.CHECK);
			bit1.setText("bit 1");
			bit1.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(1, bit1.getSelection());
				}
				
			});
			bit2 = new Button(retval,SWT.CHECK);
			bit2.setText("bit 2");
			bit2.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(2, bit2.getSelection());
				}
				
			});
			bit3 = new Button(retval,SWT.CHECK);
			bit3.setText("bit 3");
			bit3.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					
					bitFeld.set(3, bit3.getSelection());
				}
				
			});
			return retval;
		}

		@Override
		protected Object doGetValue() {
			
			return bitFeld;
		}

		@Override
		protected void doSetFocus() {
			
			
		}

		@Override
		protected void doSetValue(Object object) {
			this.bitFeld = (BitSet) object;
			bit0.setSelection(bitFeld.get(0));
			bit1.setSelection(bitFeld.get(1));
			bit2.setSelection(bitFeld.get(2));
			bit3.setSelection(bitFeld.get(3));
		
		}
		
	}
	
	/*
	 * Der CellModifier regelt den datenaustausch zwischen Editor und DatenKlasse. Beide haben ja keine Kenntnis
	 * voneinander. Deswegen wird dieser Adapter dazwischegeschaltet. In der Literatur lößt die "modify" Methode das
	 * neuzeichnen der Tabelle aus. Das hat aus meiner Sicht den Nachteil, dass sich die tabelle nur dann neuzeichnet, wenn die datenklasse
	 * sich via CellEditor ändert. Ich möchte aber, dass sich die Tabelle auch dann neuzeichnet, wenn der Datensatz direkt (durch eine andere Klasse)
	 * geändert wird. Deswegen habe ich den etwas abwendigeren Weg über den Observer gewählt. siehe unten.
	 * 
	 * 
	 * 
	 */
	class MyCellModifier implements ICellModifier {

		@Override
		public boolean canModify(Object arg0, String arg1) {
			return true;
		}

		/*
		 * 
		 * Diese Methode liefert den beiden Editoren die zu bearbeitenden Daten. In der Spalte "BitFeld" das BitSet Objekt
		 * in der anderen Spalte den String  
		 * 
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object, java.lang.String)
		 */
		@Override
		public Object getValue(Object element, String property) {
			DatenKlasse datenKlasse = (DatenKlasse) element;
			if(property .equalsIgnoreCase("BitFeld"))
				return datenKlasse.getFlags();
			else
				return datenKlasse.getLabel();
		}

		/*
		 * Wird durch den Editor aufgerufen, wenn er den Focus verliert bzw. nach validate und dient dazu die Daten aus dem Editor
		 * in die Datenklasse zurückzuschreiben.
		 * 
		 * (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object, java.lang.String, java.lang.Object)
		 */
		@Override
		public void modify(Object element, String property, Object value) {
			DatenKlasse datenKlasse = (DatenKlasse)((TableItem) element).getData();
			if(property .equalsIgnoreCase("BitFeld"))
				datenKlasse.setFlags((BitSet) value);
			else
				datenKlasse.setLabel((String) value);
			
			
		}
		
	}
	
	/*
	 * Die eigentliche Aufgabe des LabelProviders ist es, Strings für die einzelnen Spalten zur Verfügung zu stellen
	 * vom TableViewer werden die Datenobjekte mittels ContentProvider (siehe unten) gelesen und einzeln an den Labelprovider übergeben.
	 * Dann wird durch den TableViewer die Methode "getColumnText" aufgerufen, das Datenobjekt und der Spaltenindex übergegen. 
	 * diese Funktion muss dann den String für die Zelle liefern.
	 * 
	 * Ich nutze die Klasse auch um die Tabelle zu formatieren und die Editoren zu setzen, weil ich finde, dass dies 
	 * logisch hier reingehört. Damit sind alle Metainformationen zur Tabelle in einer Klasse. Dies geschieht im Konstruktor der Klasse
	 * Die Zeilenhöhe der Tabelle wird normalerweise über den Schriftgrad bestimmt. Deswegen ist ein Trick nötig um die Zeilenhöhe zu setzen.
	 * 
	 * Diese Klasse ist in jedem Buch über JFace beschrieben.
	 */
	class MyTableLabelProvider extends LabelProvider implements ITableLabelProvider {

		private String [] columnNames = {"BitFeld","Label"};
		private int [] columnAligments = {SWT.CENTER, SWT.LEFT};
		private int [] columnWidth = {400,200};
		
		public MyTableLabelProvider() {
			// Tabelle formatieren und Editoren vorbereiten
			
			//Formatieren
			Table table = getTableViewer().getTable();
			

			table.setHeaderVisible(true);
			table.setLinesVisible(true);
			for(int i = 0; i < columnAligments.length; i++) {
				TableColumn column = new TableColumn(table,columnAligments[i]);
				column.setText(columnNames[i]);
				column.setWidth(columnWidth[i]);
			}
			/*
			 * mit diesem Trick Zeilenhöhe festlegen 
			 */
			table.addListener(SWT.MeasureItem, new Listener(){ 

		         public void handleEvent(Event event) { 
		                        event.height = event.gc.getFontMetrics().getHeight() *2; 
		         } 
		          
		      }); 
			
			// Editoren
			getTableViewer().setColumnProperties(columnNames);
			MultiCheckBoxCellEditor multiCheckBoxCellEditor = new MultiCheckBoxCellEditor(table);
			TextCellEditor textCellEditor = new TextCellEditor(table);
			getTableViewer().setCellEditors(new CellEditor[]{multiCheckBoxCellEditor,textCellEditor});
			getTableViewer().setCellModifier(new MyCellModifier());
			
		}
		@Override
		public Image getColumnImage(Object arg0, int arg1) {
			return null;
		}

		@Override
		public String getColumnText(Object datensatz, int spalte) {
			if(spalte == 0)
				return "" + ((DatenKlasse) datensatz).getFlagsToString();
			else 
				return ((DatenKlasse) datensatz).getLabel();
		}
		
	}
	
	//ContentProvider für TableViewer
	/*
	 * Diese Klasse hat die Aufgabe die Zeilen für den TableViewer bereit zu stellen. Dies erledigt er mit der Methode 
	 * getElements, die immer vom TableViewer aufgerufen wird, wenn sich die Tabelle neuzeichnet
	 * 
	 * InputChanged verwende ich um mich beim Model als listener zu registrieren. Diese Methode feuert immer dann, wenn sich
	 * der Input des Viewers mit setInput ändert.
	 * 
	 * Diese Klasse ist in jedem Buch über JFace beschrieben.
	 * 
	 */
	class MyContentProvider implements IStructuredContentProvider, Observer {

		private TableViewer tableViewer;
		@Override
		public Object[] getElements(Object arg0) {
			return model.toArray();
		}

		@Override
		public void dispose() {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void inputChanged(Viewer viewer, Object oldSource, Object newSource) {
			this.tableViewer = (TableViewer) viewer;
			if(oldSource != null){
				((DatenModell) oldSource).deleteObserver(this);
			}
			if(newSource != null){
				((DatenModell) newSource).addObserver(this);
			}
				
			
		}

		// Schutziger Trick zum einfachen neuzeichnen der Tabelle
		@Override
		public void update(Observable o, Object arg) {
			tableViewer.refresh();
			
		}
	}
	
	// Container für Zeilen, das Datenmodell eben ;-)
	/*
	 * Dieses einfache Datenmodell nimmt alle Datenobjekte für die einzelnen Zeilen auf. Es wird benachrichtigt, wenn sich 
	 * irgendein gespeicherertes Objekt ändern und feuert selbst mit einem Ereignis, wenn ein Objekt hinzugefügt, geändert, oder entfernt wird.
	 * Damit weiss der ContentProvider, dass sich Daten geändert haben und er die Tabelle neuzeichnen muss.
	 * 
	 */
	class DatenModell extends Observable implements Observer{
		private ArrayList<DatenKlasse> daten = new ArrayList<DatenKlasse>();

		// Mit Spieldaten füllen
		public DatenModell() {
			
			add(new DatenKlasse(new BitSet(4), "test1"));
			add(new DatenKlasse(new BitSet(4), "test2"));
			add(new DatenKlasse(new BitSet(4), "test3"));
			add(new DatenKlasse(new BitSet(4), "test4"));
			add(new DatenKlasse(new BitSet(4),"test5"));
		}
		public void  add(DatenKlasse datenKlasse) {
			datenKlasse.addObserver(this);
			daten.add(datenKlasse);
			fireEvent();
		}

		public void  remove(DatenKlasse datenKlasse) {
			datenKlasse.deleteObserver(this);
			daten.remove(datenKlasse);
			fireEvent();
		}

		public Object[] toArray() {
			return daten.toArray();
		}

		public String toString() {
			return daten.toString();
		}

		/*
		 * Wird durch die einzelnen DatenObjekte ausgelöst, wenn sich darin etwas ändert.  
		 * (non-Javadoc)
		 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
		 */
		@Override
		public void update(Observable arg0, Object arg1) {
			fireEvent();
			
		}
		private void fireEvent() {
			setChanged();
			notifyObservers();
		}
		
	}
	
	// Spielklasse mit Daten für eine einzelne Zeile in der Tabelle (zweispaltig mit bitfeld und String)
	/* 
	 * Dies ist die eigentliche Datenklasse, die pro Zeile angezeigt wird. Im richtigen Leben repräsentiert
	 * die Klasse eine Person oder ein Auto oder ein anderes Geschäftsobjekt. Den Observer habe ich deswegen eingebaut, damit sich die Tabelle
	 * auch dann neuzeichnet, wenn jemand den Datensatz an der Tabelle vorbei ändert. 
	 * 
	 * In diesem Fall wird das Modell (siehe oben) benachrichtigt, welches wiederum dem ContentProvider eine Nachricht schickt. 
	 * Der ContentProvider veranlaßt dann das Neuzeichnen der Tabelle mit refresh.
	 * 
	 */
	class DatenKlasse extends Observable{
		private BitSet flags = new BitSet();
		private String label = "";
		
		public DatenKlasse() {
			this(new BitSet(4),"");
		}
		public DatenKlasse(BitSet flags, String label) {
			super();
			this.flags = flags;
			this.label = label;
		}
		public BitSet getFlags() {
			return flags;
		}
		public void setFlags(BitSet flags) {
			this.flags = flags;
			fireEvent();
		}
		public String getLabel() {
			return label;
		}
		public void setLabel(String label) {
			this.label = label;
			fireEvent();
		}
		
		public String getFlagsToString(){
			// Geht sicher besser, aber ich bin noch müde
			StringBuilder builder = new StringBuilder();
			boolean flag = false;
			
			for (int i = 0 ; i < 4; i++){
				if (flags.get(i)){
					if(flag)
						builder.append(",");
					builder.append("Bit " + i);
					flag = true;
				}
			}
			
			if(builder.length() == 0)
				builder.append("Keine Bits gesetzt.");
			return builder.toString();
		}
		
		private void fireEvent() {
			setChanged();
			notifyObservers();
		}
		
		
		
	}
}
 
Hallo Danke nochmal für die Mühe :) Naja wenn ich in jede Zelle eine Checkbox packe, schaut das glaub ich nicht so gut aus. (Zumindest bilde ich mir das ein :) ) So wie du es oben geschrieben hast, ist es super...Vor allem ist die Anzahl der checkboxen dynamisch, je nach vorheriger Konfiguration de benutzers... ich glaube das paßt schon :)
 
Zurück