TreeTable updaten (fireEvent)

Hallo, da Swing ja leider keine Möglichkeit einer TreeTable anbietet, benutze ich diese Implementierung in meinem Programm: http://www.hameister.org/JavaSwingTreeTable.html.

Das Problem ist, dass ich JCheckboxen in dieser Gui-Komponente habe, die ich auch ändern können will. Dabei sollen außerdem, wenn die Root Checkbox aktiviert wurde, alle anderen Checkboxen ebenfalls aktiviert werden. Wird eine “subroot” checkbox angewählt wiederum deren Kinder Checkboxen. Der Code dazu funktioniert auch, leider werden diese Ändeurngen immer erst angezeigt wenn ich die TreeTable falte und wieder aufklappe, sprich neuzeichnen. Über myTreeTable.updateUI(); könnte ich das auch neu zeichnen, aber ich setze ja die Änderungen im Model. Das heißt eigentlich müsste ich hier im Model eine der fire…() Methoden aufrufen.
Hier mal der Code mit der ich den Wert der Checkboxen ändere:


private void setValueForCheckbox(Object node, Object aValue,
			Method method) throws IllegalArgumentException,
			IllegalAccessException, InvocationTargetException {
		//Root
		if (node == root) {
			//alle sub-roots
			for (int i = 0; i < getChildCount(root); i++) {
				TVDataNode everySubRoot = (TVDataNode) getChild(root, i);
				method.invoke(everySubRoot, (Boolean) aValue);
				//children von sub-roots
				for (int j = 0; j < everySubRoot.getChildren().size(); j++) {
					method.invoke(((TVDataNode) getChild(everySubRoot, j)),
							(Boolean) aValue);
				}
			}
		}
		// 1 subroot & children
		if(isChild(root,node)) {
			for(int i = 0;i<getChildCount(node);i++) {
				method.invoke((TVDataNode)getChild(node,i), (Boolean)aValue);
			}
		}
	}

	public void setValueAt(Object aValue, Object node, int column)
			throws IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {

		switch (column) {
		case 0:
			((TVDataNode) node).setRootName((String) aValue);
			break;
		case 1:
			((TVDataNode) node).setName((String) aValue);
			break;
		case 2:
			((TVDataNode) node).setSeen((Boolean) aValue);
			setValueForCheckbox(node, aValue,
					TVDataNode.class.getDeclaredMethod("setSeen", Boolean.TYPE));
			break;
		case 3:
			((TVDataNode) node).setBought((Boolean) aValue);
			setValueForCheckbox(node, aValue,
					TVDataNode.class.getDeclaredMethod("setBought",
							Boolean.TYPE));
			break;
		default:
			break;

		}
	}

Mein AbstractTreeTableModel von dem das Model in dem diese Methoden sich befinden erbt, findet ihr nochmal hier: (oder auf der oben verlinkten Seite):


public abstract class MyAbstractTreeTableModel implements MyTreeTableModel {
    protected Object root;
    protected EventListenerList listenerList = new EventListenerList();
 
    private static final int CHANGED = 0;
    private static final int INSERTED = 1;
    private static final int REMOVED = 2;
    private static final int STRUCTURE_CHANGED = 3;
 
    public MyAbstractTreeTableModel(Object root) {
        this.root = root;
    }
 
    public Object getRoot() {
        return root;
    }
    public void setRoot(Object root) {
        this.root = root;
    }
 
    public boolean isLeaf(Object node) {
        return getChildCount(node) == 0;
    }
 
    public void valueForPathChanged(TreePath path, Object newValue) {
    }
 
    /**
     * Die Methode wird normalerweise nicht aufgerufen.
     */
    public int getIndexOfChild(Object parent, Object child) {
        return 0;
    }
 
    public void addTreeModelListener(TreeModelListener l) {
        listenerList.add(TreeModelListener.class, l);
    }
 
    public void removeTreeModelListener(TreeModelListener l) {
        listenerList.remove(TreeModelListener.class, l);
    }
 
    private void fireTreeNode(int changeType, Object source, Object[] path, int[] childIndices, Object[] children) {
        Object[] listeners = listenerList.getListenerList();
      
        TreeModelEvent e = new TreeModelEvent(source, path, childIndices, children);
        for (int i = listeners.length - 2; i >= 0; i -= 2) {
            if (listeners** == TreeModelListener.class) {
 
                switch (changeType) {
                case CHANGED:
                    ((TreeModelListener) listeners[i + 1]).treeNodesChanged(e);
                    break;
                case INSERTED:
                    ((TreeModelListener) listeners[i + 1]).treeNodesInserted(e);
                    break;
                case REMOVED:
                    ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e);
                    break;
                case STRUCTURE_CHANGED:
                    ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e);
                    break;
                default:
                    break;
                }
 
            }
        }
    }
 
    protected void fireTreeNodesChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
        fireTreeNode(CHANGED, source, path, childIndices, children);
    }
 
    protected void fireTreeNodesInserted(Object source, Object[] path, int[] childIndices, Object[] children) {
        fireTreeNode(INSERTED, source, path, childIndices, children);
    }
 
    protected void fireTreeNodesRemoved(Object source, Object[] path, int[] childIndices, Object[] children) {
        fireTreeNode(REMOVED, source, path, childIndices, children);
    }
 
    protected void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object[] children) {
        fireTreeNode(STRUCTURE_CHANGED, source, path, childIndices, children);
    }
 
}


Ich bin mir fast sicher, dass es am besten wäre wenn ich fireTreeNodesChanged() aufrufen würde aus meiner setValueForCheckbox Methode, aber ich bin mir nicht sicher welche Argumente ich übergeben muss.

Viele Grüße

irgendwie fireTableDataChanged() auf das Model der Table würde vielleicht auch reichen,

zum fireTreeNode() kann ich nicht direkt etwas sagen, aber das Befüllen kannst du ja angehen,
Child-Indexe + Objekte sollten klar sein, Source ist vielleicht egal,

Path am anspruchvollsten zusammenzubauen, aber je länger man drüber nachdenkt und daran arbeitet,
desto deutlicher und letztlich zweifelsfrei im Aufbau, zu überprüfen

siehe API TreeModelEvent zur Bedeutung der Parameter,
siehe Suchmaschinen ‘java firetreenodeschanged example’,
siehe Sourcecode von DefaultTreeModel (per Suchmaschine zu finden) für einen rekursiven Zusammenbau des Paths

nichts weltbewegendes, immer Schritt für Schritt arbeiten

[QUOTE=SlaterB]irgendwie fireTableDataChanged() auf das Model der Table würde vielleicht auch reichen,
[/QUOTE]

Da hast du auf jeden Fall recht. Ich habe mal einen Blick in das Tabellenmodell geworfen. Dort findet sich folgender Code:


  tree.addTreeExpansionListener(new TreeExpansionListener() {
            public void treeExpanded(TreeExpansionEvent event) {
                fireTableDataChanged();
            }
 
            public void treeCollapsed(TreeExpansionEvent event) {
                fireTableDataChanged();
            }
        });

Beim auf bzw. zuklappen werden die Daten ja auch geändert. Daher sollte der Aufruf der Methode schon passen. Fragt sich nur wie ich in dem TreeTableModel an die äquivalente TableModel Instanz komme…

na mindestens durch direkte Verdrahtung,
das TreeModel wird doch an das TableModel übergeben, genau da wo die zuletzt genannten Methoden definiert werden

Ok danke, habs hinbekommen :slight_smile: