Translate this page...

BeanDev: NodeAction und Selection Management

Eine nette Klasse, um Nodes mit Aktionen zu versehen ist die NodeAction-Klasse. Und soweit man sich an die Standard-Tutorials hält, wird man erstmal keine Probleme haben - insbesondere wenn sich alles in einem View innerhalb TopComponent läuft.

NodeAction funktioniert aber nur, wenn das zugeordnete Modell des ExplorerManager mit dem Selection Management der NetBeans Plattform verknüpft ist. Dabei ist es letztendlich irrelevant, ob z.B. ein BeanTreeView-Eintrag visuell markiert ist. Wenn der ExplorerManager von seiner Umwelt abgeschnitten ist, klappt es nicht mit einer NodeAction.

Sehr schnell bekommt man das mit, wenn man ein ExplorerManager und zugehöriges View in einer schlichten Panel-Komponente hat. Zwar funktioniert alles erstmal wie erwartet, sogar NodeActions die per

  @Override
  public Action[] getActions(boolean context) {
    return new Action[] {myNodeAction}
  }

an einen Knoten gebunden werden, zeigen sich im Popup, sind aktiv und werden sogar ausgeführt.

Leider stellt man dann im Debugger fest, dass das übergebene Node-Array in der performAction-Methode immer leer ist.

    @Override
    protected void performAction(Node[] nodes) {
      for (Node node : nodes) {
        if ( node.canDestroy() ) {
          Node parent = node.getParentNode();
          parent.getChildren().remove(new Node[]{node});
        }
      }
    }

Obige performAction-Methode würde nie etwas ausführen.

Wie bekommt man aber nun NodeAction dazu, zu erkennen, welche Knoten im ExplorerManager ausgewählt wurden?

Hier eine Möglichkeit:

Das Panel sollte das Interface Lookup.Provider implementieren und, ähnlich wie in den Tutorials zu TopComponents, ein Lookup (generiert aus einem ExplorerManager) zurückgeben:

public class MyTestPanel extends JPanel 
          implements ExplorerManager.Provider, Loopup.Provider {
  private ExplorerManager myNodeModel = new ExplorerManager();
  private BeanTreeView tree = new BeanTreeView();
  private Lookup lookup;
  public MyTestPanel () {
    initComponents();
    myNodeModel = new ExplorerManager();
    lookup = ExplorerUtils.createLookup(explorerManager, new ActionMap());
    myNodeModel .setRootContext(new MyRootNode());
  }

  public ExplorerManager getExplorerManager() {
    return myNodeModel;
  }

  public Lookup getLookup() {
    return lookup;
  }
  [...]
}

Das BeanTreeView benötigt das Interface ExplorerManager.Provider, ansonsten hat das View kein Model. Die Implementation von Lookup.Provider nutzen wir nun in der TopComponent, in der wir unser TestPanel einfügen:

public class TestTopComponent extends TopComponent {
  TestPanel tp = new TestPanel();
  public TestTopComponent() {
    add (tp);
    associateLookup(tp.getLookup()));
  }
}

Das war es auch schon, der Rest läuft automatisch. Die Methode associateLookup reicht das erzeugte Lookup aus unserem Panel durch die getLookup-Methode von TestTopComponent heraus (getLookup ist schon in TopComponent implementiert). 

Es wird aber die Regel sein, dass TopComponents eigene Lookups benötigen oder gar mehrere Panels mit Lookups nutzen. Dabei hilft aber ProxyLookup:

public class TestTopComponent extends TopComponent {
TestPanel tp = new TestPanel();
  InstanceContent content = new InstanceContent();
  public TestTopComponent() {
    add (tp);
    associateLookup(
      new ProxyLookup (
        new AbstractLookup (instanceContent),
        tp.getLookup())
    );
  }
}

Jetzt kann man selber in content seine Objekte speichern, die man global zur Verfügung stellen will und verliert nicht die Verbindung zu den selektierten Nodes in TestPanel.

Beste Grüße,
  Josch.

http://www.netbeans-forum.de/ Da werden Sie geholfen:
Das deutsche NetBeans Forum

      NetBeans Dream Team Member

Hinterlasse eine Nachricht

Meine Informationen merken

CAPTCHA Bild zum Spamschutz 

[Valid RSS]