SWT Popupmenu auf der Überschrift eines swt.widgets.Table verhindern?

Enternix

Mitglied
Ich versuche gerade etwas SWT/JFace mit den Snippets auf eclipse.org zu lernen. Dabei bin ich auf das JFace-Snippet-018 gestoßen: JFaceSnippets - Eclipsepedia

Hier wird demonstriert, wie man in einem org.eclipse.jface.viewers.TableViewer Zellen editieren kann und wie man mit einem Popup-Menü eine Spalte hinzufügen und auch wieder entfernen kann.

Das Snippet läuft nicht ganz fehlerfrei, da eine Exception ausgelöst wird, wenn man nach dem Programmstart des Snippets mit der rechten Maustaste auf die Tabellenüberschrift klickt und "Insert e-mail before" auswählt.

Das liegt daran, dass in der Methode triggerColumnSelectedColumn die Stelle des Mausklicks lokalisiert werden soll, um an dieser Stelle die Spalte hinzuzufügen. Klickt man jedoch mit rechts auf die Tabellenüberschrift, wird zwar das Popup-Menü aufgerufen, der MouseListener innerhalb der Methode triggerColumnSelectedColumn empfängt aber kein mouseDown, so dass die Stelle des Mausklicks nicht lokalisiert werden kann.

Daher würde ich gerne verhindern, dass das Popup-Menü der Tabelle aufgerufen wird, wenn nur auf die Tabellenüberschrift geklickt wird.
 
Zuletzt bearbeitet:
Bei mir funktioniert das Beispiel einwandfrei...

EDIT: Ahhh sorry gleich nach dem Start gibts Probleme, sonst passt es immer...
 
Ich habe mal die Editierfunktion des Snippets gelöscht, da sie nichts mit dem Problem zu tun hat:
Java:
package org.eclipse.jface.snippets.viewers;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableColumn;

public class Snippet018TableViewerSimplified {

	public class Person {
		public String givenname;

		public String surname;

		public String email;

		public Person(String givenname, String surname, String email) {
			this.givenname = givenname;
			this.surname = surname;
			this.email = email;
		}

		public String getValue(String name) {
			Field field;
			try {
				field = getClass().getDeclaredField(name);
				return (String) field.get(this);
			} catch (Exception e) {
				e.printStackTrace();
			}

			return "ERROR";
		}

	}

	public class MyLabelProvider extends LabelProvider implements
			ITableLabelProvider {
		private TableViewer viewer;

		public MyLabelProvider(TableViewer viewer) {
			this.viewer = viewer;
		}

		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		public String getColumnText(Object element, int columnIndex) {
			return ((Person) element)
					.getValue(viewer.getColumnProperties()[columnIndex]
							.toString());
		}
	}

	private int activeColumn = -1;

	public Snippet018TableViewerSimplified(Shell shell) {
		final TableViewer v = new TableViewer(shell, SWT.BORDER);
		v.setLabelProvider(new MyLabelProvider(v));
		v.setContentProvider(ArrayContentProvider.getInstance());

		v.setColumnProperties(new String[] { "givenname", "surname" });

		TableColumn column = new TableColumn(v.getTable(), SWT.NONE);
		column.setWidth(200);
		column.setText("Givenname");

		column = new TableColumn(v.getTable(), SWT.NONE);
		column.setWidth(200);
		column.setText("Surname");

		Person[] model = createModel();

		v.setInput(model);
		v.getTable().setLinesVisible(true);
		v.getTable().setHeaderVisible(true);

		addMenu(v);
		triggerColumnSelectedColumn(v);
	}

	private void triggerColumnSelectedColumn(final TableViewer v) {
		v.getTable().addMouseListener(new MouseAdapter() {

			public void mouseDown(MouseEvent e) {
				System.out.println("mouseDown");
				int x = 0;
				for (int i = 0; i < v.getTable().getColumnCount(); i++) {
					x += v.getTable().getColumn(i).getWidth();
					if (e.x <= x) {
						activeColumn = i;
						break;
					}
				}
			}

		});
	}

	private void addMenu(final TableViewer v) {
		final MenuManager mgr = new MenuManager();

		final Action insertEmailBefore = new Action("Insert E-Mail before") {
			public void run() {
				addEmailColumn(v, activeColumn);
			}
		};

		final Action insertEmailAfter = new Action("Insert E-Mail after") {
			public void run() {
				addEmailColumn(v, activeColumn + 1);
			}
		};

		final Action removeEmail = new Action("Remove E-Mail") {
			public void run() {
				removeEmailColumn(v);
			}
		};

		mgr.setRemoveAllWhenShown(true);
		mgr.addMenuListener(new IMenuListener() {

			public void menuAboutToShow(IMenuManager manager) {
				if (v.getTable().getColumnCount() == 2) {
					manager.add(insertEmailBefore);
					manager.add(insertEmailAfter);
				} else {
					manager.add(removeEmail);
				}
			}

		});

		v.getControl().setMenu(mgr.createContextMenu(v.getControl()));
	}

	private void removeEmailColumn(TableViewer v) {
		int emailIndex = -1;
		for (int i = 0; i < v.getColumnProperties().length; i++) {
			if (v.getColumnProperties()[i].toString().equals("email")) {
				emailIndex = i;
				break;
			}
		}

		ArrayList<Object> list = new ArrayList<Object>(Arrays.asList(v.getColumnProperties()));
		list.remove(emailIndex);
		String[] columnProperties = new String[list.size()];
		list.toArray(columnProperties);
		v.setColumnProperties(columnProperties);

		v.getTable().getColumn(emailIndex).dispose();

		v.refresh();
	}

	private void addEmailColumn(TableViewer v, int columnIndex) {

		ArrayList<Object> list = new ArrayList<Object>(Arrays.asList(v.getColumnProperties()));
		list.add(columnIndex, "email");
		String[] columnProperties = new String[list.size()];
		list.toArray(columnProperties);
		v.setColumnProperties(columnProperties);

		// 1. Add new column
		TableColumn column = new TableColumn(v.getTable(), SWT.NONE,
				columnIndex);
		column.setText("E-Mail");

		// 2. Update the viewer
		v.refresh();

		// 3. Make the column visible
		column.setWidth(200);
	}

	private Person[] createModel() {
		Person[] persons = new Person[3];
		persons[0] = new Person("Tom", "Schindl", "tom.schindl@bestsolution.at");
		persons[1] = new Person("Boris", "Bokowski",
				"boris_bokowski@ca.ibm.com");
		persons[2] = new Person("Tod", "Creasey", "tod_creasey@ca.ibm.com");

		return persons;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Display display = new Display();

		Shell shell = new Shell(display);
		shell.setLayout(new FillLayout());
		new Snippet018TableViewerSimplified(shell);
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}

		display.dispose();

	}

}
Somit zeigt das Beispiel-Programm nun eine Tabelle an, in die man mit Hilfe eines Rechtsklicks eine Spalte für die E-mail-Adresse ein- und ausblenden kann. Dabei wird die E-mail-Spalte an der Stelle eingefügt, wo geklickt wurde.

In Zeile 99 wird dem TableViewer ein MouseAdapter zum Empfangen von Mouse-Events übergeben. Leider bleibt ein Klick auf die Tabellenüberschrift vom MouseAdapter unbemerkt.

In Zeile 151 wird dem TableViewer ein Kontextmenü übergeben. Und dieses erscheint leider auch wenn man auf die Tabellenüberschrift klickt.

Also gehört für den MouseAdapter die Überschrift nicht mit zur Tabelle, während für das Kontextmenü die Überschrift sehr wohl zur Tabelle gehört. Das Ergebnis ist, dass bei einem Recktsklick auf die Überschrift die Variable activeColumn (Zeile 71) nicht aktualisiert wird und die Spalte daher an der falschen Stelle eingefügt wird.

Hat jemand einen Vorschlag, wie man das Problem lösen könnte?
 
Ich sehe gerade, dass es das gleiche Snippet mit neuer API gibt: http://dev.eclipse.org/viewcvs/viewvc.cgi/org.eclipse.jface.snippets/Eclipse%20JFace%20Snippets/org/eclipse/jface/snippets/viewers/Snippet019TableViewerAddRemoveColumnsWithEditingNewAPI.java?revision=1.5&view=co

Dort wird
Code:
new TableViewerColumn(TableViewer parent, int style, int index)
statt
Code:
new TableColumn(Table parent, int style, int index)
genutzt und
Code:
index
kann dabei nie 'out of range' sein. Trotzdem bleibt aber eigentlich das Problem bestehen, dass die Spalte nicht an der Stelle eingefügt wird, an der man es erwartet, wenn man auf die Tabellenüberschrift klickt...
 

Zurück
Oben