夏風邪ひいて熱が出たり咳が出たり鼻水出たりでしんどいですが、皆さん体調いかがでしょうか。
さて、風邪ひいていようと暇なものは暇なので、タイトル通りの物を作っていました。
イメージとしてはこんなのね。(Firefoxの検索窓)
ソースコードはこちら。NodamushiFXControls
クラスは CompletionTextFieldです。
候補や挿入方法はCandidateインターフェースで定義してあるだけなので、よく言えば自由がある、悪く言えばユーザーが用意しないといけない。
デモ用に作ったCandidateインターフェースの実装(ForwardMatchCandidate)ではこんな感じに動作します。
自作PopupControlの作り方
意外とここの部分でつまった。
最も単純な方法では、TooltipのGraphicに表示させたいNodeを突っ込んで表示するってのが楽そうだけど、やっぱそれだと微妙だよね。
Tooltipの元となっているPopupWindowないし、PopupControlから派生させたい物です。
今回はPopupControlにNodeを表示させる方法を調べたところ、単純にSkinを登録するだけでした。
私が作ったコードではこんな感じ。ComboBoxSkinのコードを参考にしています。(ていうか、ほとんどここはまんまか)
final PopupControl p = new PopupControl(){ @Override public Styleable getStyleableParent(){ return getSkinnable();//ポップアップ元のノードを返しています } { setSkin(new Skin<Skinnable>(){ @Override public Skinnable getSkinnable(){return CompletionTextFieldSkin.this.getSkinnable();} @Override public Node getNode(){return getPopupContent();} @Override public void dispose(){} }); } };
JavaFX8ではListViewの行の高さを取得できなかった
ListViewを表示するときに、ある一定の行までは表示して、それ以上はスクロールバーで対応させたい。
つまり、n行を表示するための高さを取得して、それをPrefHeightとすれば良いのだが、この1行の高さというのが実は取得できない。
でも、ComboBoxとかではそれを実現しているように見える。ではどうやっているのかとソースコードを調べ、最終的に次のコードに落ち着いた。
private static final Class<?> VIRTUALCONTAINERBASE; private static final Method GET_VIRTUAL_FLOW_PREFERRED_HEIGHT,//n行分の高さを取得するメソッド UPDATE_ROW_COUNT;//今何行分のアイテムがあるのかSkinに強制的に更新させる static{ Class<?> c; Method m,m2; try { c=Class.forName("com.sun.javafx.scene.control.skin.VirtualContainerBase"); m = c.getDeclaredMethod("getVirtualFlowPreferredHeight", int.class); m2 =c.getDeclaredMethod("updateRowCount"); m.setAccessible(true); m2.setAccessible(true); } catch (final Exception e) { c = null;m=null;m2=null; } VIRTUALCONTAINERBASE=c; GET_VIRTUAL_FLOW_PREFERRED_HEIGHT=m; UPDATE_ROW_COUNT=m2; } private double getListViewPrefHeight() { double ph; final int maxRows = min(textField.getVisibleRowCount(),getCandidateSize()); if (VIRTUALCONTAINERBASE!=null &&listView.getSkin()!=null && VIRTUALCONTAINERBASE.isAssignableFrom(listView.getSkin().getClass())) { try{ //これ↓を挟まないと次のgetVirtualFlowPrefreredHeightでちゃんと高さが出なかった。 UPDATE_ROW_COUNT.invoke(listView.getSkin()); ph =(double) GET_VIRTUAL_FLOW_PREFERRED_HEIGHT.invoke(listView.getSkin(), maxRows); }catch(final Exception e){ final double ch = maxRows * 25; ph = Math.min(ch, 200); } } else { final double ch = maxRows * 25; ph = Math.min(ch, 200); } return ph; }
う~ん、リフレクションかぁ。com.sunパッケージかぁ(´Д⊂ヽ
とりあえず、これに期待するしかないっすね。。。いったいどの程度JavaFX9でPublic APIが増えるんでしょうかね。
JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
特に落ちもまとめもありませんが、以上。