読者です 読者をやめる 読者になる 読者になる

SwingComponent の挙動が変わった?

もう 1 つのメニューの問題も原因が分かりました。こちらはバグではないと思いますが、ちょっと微妙。

JPopupMenu を表示させるためには、親のコンポーネントを引数にしてshow メソッドをコールします。

ここで、親のコンポーネントが取れないといっていたのが、前回の問題。それはあっけなく解決しました。

以前は次のように書いてました。

    var panel = (node.impl_createPGNode() as SGGroup).getPanel();

Node クラスの impl_createPGNode 関数が間違っていたようです。

ただしくは impl_getPGNode 関数でした。

    var panel = (node.impl_getPGNode() as SGGroup).getPanel();

ただし、impl_getPGNode 関数のように impl_ からはじまる関数はあくまでも内部的に使う関数なので、バージョンアップで変更されても文句はいえません ^ ^;;

なので、これはかまわないのです。

スクリプトをこのように変更することで、メニューは表示されます。しかし、問題は項目が表示されないことなのです。

表示されるのはちっちゃい四角だけ。なんだこりゃ?

以前はポップアップのクラスは次のように書いていました。

public class PopupMenu extends SwingComponent {
    public var label: String;
    public-init var items: Menu[];
    
    var popupMenu: JPopupMenu;
 
    override function createJComponent(): JComponent {
        popupMenu = new JPopupMenu();

        // ラベルの設定
        popupMenu.setLabel(label);
        // 項目の追加
        for (item in items) {
            popupMenu.add(item.getJComponent());
        }

        return popupMenu;
    }
 
    public function show(node: Node, x: Integer, y: Integer): Void {
        var panel = (node.impl_getPGNode() as SGGroup).getPanel();
        popupMenu.show(panel, x, y);
    }
}

つまり、メニューに項目を追加するのは createJComponent 関数で行なっていたわけです。

JavaFX 1.1 までは createJComponent 関数がコールされるのは、インスタンス変数がセットされた後でした。つまり、上のスクリプトでは items がセットされていたのです。

ところが、JavaFX 1.2 では items がセットされない状態で createJComponent 関数がコールされてしまいます。

このため、項目がないメニューが表示されてしまったのです。

時系列で表すと

  1. createJComponent をコール
  2. インスタンス変数をセット
  3. init を実行
  4. postinit を実行

となっているようです。

ここまで分かれば、修正するのは簡単。以下のように変更しました。

public class PopupMenu extends SwingComponent {
    public var label: String;
    public-init var items: Menu[];
    
    var popupMenu: JPopupMenu;

    init {
        // ラベルの設定
        popupMenu.setLabel(label);
        // 項目の追加
        for (item in items) {
            popupMenu.add(item.getJComponent());
        }
    }
 
    override function createJComponent(): JComponent {
        popupMenu = new JPopupMenu();
        return popupMenu;
    }
 
    public function show(node: Node, x: Integer, y: Integer): Void {
        var panel = (node.impl_getPGNode() as SGGroup).getPanel();
        popupMenu.show(panel, x, y);
    }
}

同じように JMenu クラスに対応する Menu クラスと、JMenuItem クラスに MenuItem クラスも変更しました。

その結果、ちゃんとメニューが表示されるようになったのです。

もともと、API ドキュメントにはコールされる順番は書いてないので、変更されたとしても文句はいえないのですが....

なんだかなぁ...