省型旧形国電の残影を求めて

戦前型旧形国電および鉄道と変褪色フィルム写真を中心とした写真補正編集の話題を扱います。他のサイトでは得られない、筆者独自開発の写真補正ツールや補正技法についても情報提供しています。写真補正技法への質問はコメント欄へどうぞ

ImageJ / Python Tips: イベントリスナー使用の陥穽

 先日解説をつけた、MRC分子生物学研究所で公開している、ImageJの対話的ダイアログのサンプルプログラムを改造して、数値入力欄からパラメータ数値を得てプレビュー画像上にROI(注目範囲、選択範囲)を表示する、対話型ダイアログボックスを作ろうと思いました。そこで思わぬ落とし穴が...

 ダイアログを表示させるとき、GenericDialogというオブジェクトを使います。ここで、数値を入力する入力ボックスを設置するには、addNumericField というメソッドを使います。NumericField から取得した値は直ちに計算に使うことができます(Numeric Field だから当然ですが。文字列の入力ボックスなら String Field を設置します)。ところが...

 イベントリスナーを設置したダイアログに Numeric Field を設置して、そこから値を取得した変数を使って計算しようとすると問題が起こります。

 非対話型のダイアログなら addNumericField で設置した数値入力ボックスから数値を取得するときは、getNextNumber() というメソッドを使って数値型変数として値を取得することができます。しかし...

 イベントリスナーを有効にして対話状況になっているときに、 getNext xxx メソッドが使えないのです。最終的に OK ボタンを押してダイアログの表示を終了させるときにしか、getNext xxx メソッドは使えません。

 で、どうするかというと、入力ツールをオブジェクトとして入力を監視するしかありません。例えば、先日お見せしたMRC分子生物学研究所のサンプルプログラム(スライダーとチェックボックスの設置してあるダイアログ)では以下のようになっていました。

    slider = gd.getSliders().get(0)

    checkbox = gd.getCheckboxes().get(0)

    previewer = ScalingPreviewer(imp, slider, checkbox)
※ScalingPreviwerはダイアログのプレビューを実行する、コード作成者がクラスとして定義したオブジェクトの名前

 

ScalingPreviewer(imp, slider, checkbox) で、プレビュー画像とスライダー、チェックボックスへの監視をつけていますが、この引数としてオブジェクトを参照させる必要があるのです。で、このスライダーの代わりに数値入力ボックスを入れるとするとどうなるかというと、例えば

    numericField0 = gd.getNumericFields().get(0)

などと書いて、この numericField0 をプレビューを行うオブジェクト (仮にその名前をROIPreviewer とします) の引数として参照させなければならないと思います。例えば...

    ROIPreviewer(imp, numericField0, checkbox)

 問題は、このROIPreviwerの中で、ここで定義したnumericField0から数値を取得しなければいけないのですが、その中でgetNextNumber()  が使えないということです。で、結局どうしたかというと、ROIPreviwer のコンストラクターで、一旦、 self.numericField0 = numericField0 と定義しておいた上で、self.numericField0 から数値を取得することになります。と・こ・ろ・が...
 getNextNumbet() だと問題なく数値として値を取得できるのですが、数値入力ボックスであるはずの self.numericField0 オブジェクトから直接数値を得ることができないのです(端的に言うと、getValue() メソッドが有効でなく、値を得るにはgetText()しか使えない)。しかも、得た値に、Python上の、int() 関数や float() 関数を適用しようとするとエラーになってしまいます。エラーメッセージを見ると java.awt.TextFieldだからだからダメとあります。つまり数値ではなくテキスト、文字列(しかもJava上の)とみなされるようです。つまり、こういう形に数値入力ボックスを変形してしまうと、あくまでもJava上のテキストボックスとしてしか認識してくれないらしく (つまり String Field [文字入力ボックス]と一緒になってしまう。何のためにaddNumericField を使ったのやら...)、値を取得できるメソッドは getText() しか使えないうえに、文字列(String)データから柔軟に数値に変形できるPythonの型変換関数も使えない...

 いやぁ、参りました。で、またネット上を散々探したところ、Java上では、Integer クラスの parseInt​ メソッドを使って文字列から整数を得られるよ、という情報が...

www.javadrive.jp

 これが、ImageJのJython上で有効なのか分かりませんが、とりあえず推測で以下のようにやってみました。

まずライブラリの呼び出しで、

from java.lang import Integer

を加えてみました。

次いで、数値を取得するために次のようにコードを書いてみました。

     i = Integer.parseInt(self.numericField0.getText())

すると... ビンゴ! 見事に整数値を取得することができました。

 

 もともとPythonを勉強し始めたのは、ImageJとGIMPを動かすのに別々の言語を勉強しなくても済むようにという理由だったのですが、しかし、ImageJ上で凝ったことをやろうとすると、Javaが剥き出しになって、Java に関する知識が必須になりますねぇ... いやはや。