0

NetBeansNodesAPIに問題があります。

私はこのコード行を持っています:

Node n = (new MyNode(X)).getChildren().getNodeAt(Y);

new MyNode(X)同じを使用してを呼び出すとX、コンテキストに関係なく、常に同じ方法でMyNodeが初期化されます。

それを単独で配置すると(たとえば、メニューアクションで)、Yth子を正常に取得します、他のNode / Childrenのものが発生するイベントに配置すると、が返されますnull

MyNodeのChildren実装は、Children.Keysの簡単なサブクラスであり、おおよそ次のようになります。

// Node
import org.openide.nodes.AbstractNode;

class MyNode extends AbstractNode {

    MyNode(MyKey key) {
        super(new MyNodeChildren(key));
    } 
}


// Children 
import java.util.Collections;
import org.openide.nodes.Children;
import org.openide.nodes.Node;

public class MyNodeChildren extends Children.Keys<MyKey> {
    MyKey parentKey;

    MyNodeChildren(MyKey parentKey) {
        super(true); // use lazy behavior
        this.parentKey = parentKey;
    }

    @Override
    protected Node[] createNodes(MyKey key) {
        return new Node[] {new MyNode(key)};
    }

    @Override
    protected void addNotify() {
        setKeys(this.parentKey.getChildrenKeys());
    }

    @Override
    protected void removeNotify() {
        setKeys(Collections.EMPTY_SET);
    }
}

// MyKey is trivial.

これはの怠惰な振る舞いと関係があると思いますChildren.Keys。私はAPIのソースを持っており、それをステップスルーしてみましたが、それらは非常に混乱しているため、まだ何も理解していません。

最新のプラグインを備えたNetBeansIDE7.0.1(ビルド201107282000)。

編集:詳細

奇妙な振る舞いの行は、ExplorerManagerの選択されたノードのプロパティ変更のハンドラー内にあります。奇妙なことに、MyNodeインスタンスがExplorerManagerが使用している階層になく(ExplorerManagerのノードと同じクラスでもない)、他の目的で使用されていない場合でも機能しません。 。

基礎となるモデルの代わりにノードにアクセスすることは、私のユースケースでは実際に必要です(PropertySetsで何かを行う必要があります)。MyNodeの例は、まだ問題がある単純なケースです。

4

2 に答える 2

4

APIorg.openide.nodes.ChildFactoryのいずれかを使用する特別な必要がない限り、子ノードの作成に使用することをお勧めします。Childrenしかし、一般的なケースでChildFactoryは、それで十分です。

Nodes APIを使用する際に留意すべきことの1つは、モデルをラップするのはプレゼンテーション層のみであり、Explorer APIと組み合わせて使用​​すると、などのNetBeansプラットフォームのさまざまなビューコンポーネントで使用できるようになることですorg.openide.explorer.view.BeanTreeView

MyModel次のようなモデルを使用します。

public class MyModel {

    private String title;
    private List<MyChild> children;

    public MyModel(List<MyChild> children) {
        this.children = children;
    }

    public String getTitle() {
        return title;
    }

    public List<MyChild> getChildren() {
        return Collections.unmodifiableList(children);
    }
}

ChildFactory<MyModel>ノードの作成を担当するを作成できます。

public class MyChildFactory extends ChildFactory<MyModel> {

    private List<MyModel> myModels;

    public MyChildFactory(List<MyModel> myModels) {
        this.myModels = myModels;
    }

    protected boolean createKeys(List<MyModel> toPopulate) {
        return toPopulate.addAll(myModels);
    }

    protected Node createNodeForKey(MyModel myModel) {
        return new MyNode(myModel);
    }

    protected void removeNotify() {
        this.myModels= null;
    }  
} 

MyNode次に、プレゼンテーション層とラップである実装MyModel

public class MyNode extends AbstractNode {

    public MyNode(MyModel myModel) {
        this(myModel, new InstanceContent());
    }

    private MyNode(MyModel myModel, InstanceContent content) {
        super(Children.create(
                new MyChildrenChildFactory(myModel.getChildren()), true),
                new AbstractLookup(content)); // add a Lookup
        // add myModel to the lookup so you can retrieve it latter
        content.add(myModel);
        // set the name used in the presentation
        setName(myModel.getTitle());
        // set the icon used in the presentation
        setIconBaseWithExtension("com/my/resouces/icon.png");
    }
}

そして今、これは、それがaを取り、次に作成することを除いて、MyChildrenChildFactory非常に似ています:MyChildFactoryList<MyChild>MyChildNode

public class MyChildFactory extends ChildFactory<MyChild> {

    private List<MyChild> myChildren;

    public MyChildFactory(List<MyChild> myChildren) {
        this.myChildren = myChildren;
    }

    protected boolean createKeys(List<MyChild> toPopulate) {
        return toPopulate.addAll(myChildren);
    }

    protected Node createNodeForKey(MyChild myChild) {
        return new MyChildNode(myChild);
    }

    protected void removeNotify() {
        this.myChildren = null;
    }  
} 

次に、その実装は次のMyChildNodeようになりMyNodeます。

public class MyChildNode extends AbstractNode {

    public MyChildNode(MyChild myChild) {
        // no children and another way to add a Lookup
        super(Children.LEAF, Lookups.singleton(myChild));
        // set the name used in the presentation
        setName(myChild.getTitle());
        // set the icon used in the presentation
        setIconBaseWithExtension("com/my/resouces/child_icon.png");
    }
}

そして、次のような子供用モデルが必要になりMyChildますMyModel

public class MyChild {

    private String title;

    public String getTitle() {
        return title;
    }
}

最後に、すべてを使用するために、たとえば、を実装BeanTreeViewするに存在するaを使用します。TopComponentorg.openide.explorer.ExplorerManager.Provider

 // somewhere in your TopComponent's initialization code:
 List<MyModel> myModels = ...
 // defined as a property in you TC
 explorerManager = new ExplorerManager();
 // this is the important bit and we're using true 
 // to tell it to create the children asynchronously 
 Children children = Children.create(new MyChildFactory(myModels), true);
 explorerManager.setRootContext(new AbstractNode(children));

に触れる必要はなくBeanTreeView、実際には、プラットフォームに含まれている任意のビューコンポーネントである可能性があることに注意してください。これはノードを作成するための推奨される方法であり、私が述べたように、ノードの使用は、プラットフォームに含まれるさまざまなコンポーネントで使用されるプレゼンテーション層として使用されます。

次に子を取得する必要がある場合は、実装されたメソッドを使用してExplorerManager取得できる子を使用できます。これは、実装されており、実際にはビューコンポーネント自体がノードを取得する方法です。TopComponentExplorerManager.Provier.getExplorerManager()TopComponentExplorerManager.Provider

ExplorerManager explorerManager = ...
// the AbstractNode from above
Node rootContext = explorerManager.getRootContext();
// the MyNode(s) from above
Children children = rootContext.getChildren().getNodes(true);
// looking up the MyModel that we added to the lookup in the MyNode
MyModel myModel = nodes[0].getLookup().lookup(MyModel.class);

Children.getNodes(true)ただし、このメソッドを使用してノードを取得すると、すべてのノードとその子が作成されることに注意する必要があります。これは、子を非同期で作成するようにファクトリに指示したために作成されませんでした。これはデータにアクセスするための推奨される方法ではありませんが、代わりにへの参照を保持し、List<MyModel>可能であればそれを使用する必要があります。のドキュメントからChildren.getNodes(boolean)

...一般に、このメソッドを呼び出して有用なデータを取得しようとしている場合は、おそらく何か間違ったことをしています。通常、子のノードではなく、基礎となるモデルに情報を要求する必要があります。

繰り返しになりますが、Nodes APIはプレゼンテーション層であり、モデルとビューの間のアダプターとして使用されることを覚えておく必要があります。

これが強力なテクニックになるのはChildFactory、異なるさまざまなビューで同じものを使用する場合です。上記のコードは、TopComponents変更を加えることなく多くの場合に再利用できます。FilterNode元のノードに触れることなく、ノードの表示の一部のみを変更する必要がある場合にも、を使用できます。

Nodes APIの学習は、間違いなく発見したように、NetBeansプラットフォームAPIを学習する上で最も難しい側面の1つです。このAPIをある程度習得すると、組み込みの機能をさらに活用できるようになります。

Nodes APIの詳細については、次のリソースを参照してください。

于 2011-10-26T10:57:20.470 に答える
1

NetBeans PlatformDevelopersメーリングリストのTimonVeenstraは、これを解決してくれました

explorerManagerのアクションは、一貫性を確保するために保護されています。たとえば、エクスプローラーマネージャーのノード選択リスナーは、選択変更イベントの処理中に同じエクスプローラーマネージャーを操作できません。これは、読み取りと書き込みのアップグレードが必要になるためです。変更は拒否され、沈黙の死を迎えます。

初期化時にMyNodeルートノードをエクスプローラーマネージャーに追加しますか、それともリスナーのどこかに追加しますか?

私の問題の行は、ExplorerManagerの選択変更リスナーにあります。Children.MUTEXロックがExplorerManagerによって設定され、Children.Keysインスタンスがそのノードにデータを入力できないようになっていると思います...?

とにかく、ノードアクセスをEventQueue.invokeLater(...)に移動したので、選択が変更されたイベントが終了した後に実行され、それが修正されました。

于 2011-10-26T18:19:49.703 に答える