今日はものすごい疲れた・・・。
Swingよく分からない・・・。
今日も仕事です。
仕事ではJavaを使うことになっています。
GUI部分についてはSwingを使います。
で、GUIのところに、TitledBorderのタイトル部分にComponentを配置する、
というのをやることになりそうだと言うことで、以下のサイトを参考に色々いじってました。
http://terai.xrea.jp/Swing/ComponentTitledBorder.html
http://www.jroller.com/santhosh/entry/component_titled_border
試しに上のサイトのサンプルを動かしてみるとバグが・・・。
実際に動かしてみると分かりますが、タイトルに配置したコンポーネントの挙動が
普通にコンポーネント配置した場合と違います。
ボタンを置くと分かりやすいかな?
まず(1)マウスをコンポーネントからどかすとロールオーバーが解除されない。
そして、(2)ボタンを押したままマウスをボタンの外に移動して離すとボタンが押されたままになる。
これを解決するため、自分なりにソースをいじってみました。
最初は1番の問題。(以下、Santhoshさんのソースを基に書いてます)
これは51行目でタイトルに配置したコンポーネント(27行目、comp)内にマウスがあるときのみ、
comp.dispatchEvent()(55行目)を呼んでいるため。
なので、タイトルのコンポーネントを出てもdispatchEventを呼べるように直します。
51行目のif分の条件式を二つに分けて
if (rect != null) {
if (rect.contains(me.getPoint()) { //Santhoshさんのと変えてます
//マウスがcomp内のときの処理もdispatchEvent
}
else {
//マウスがcomp外のときの処理もdispathEvent
}
}
みたいにして、うまくcomp.dispatchに渡すMouseEventを渡してやればいいと思います。
しかし、comp外のときの処理によっては別の問題が発生します。
ボーダーを適用するコンポーネント(container、28行目)にマウスが入ったら
タイトルコンポーネントがロールオーバーされます。
これを回避するため、containerにはMouseMotionListenerを登録し、
mouseDragged()とmouseMoved()にはdispatchEvent()を呼ぶように実装します。
そして、mouseEntered()(78行目)のdispatchEvent()は消します。
さらに、マウスがタイトルコンポーネント(containerではない)に入ったかの判定フラグを用意します。
そして、
マウスがcomp内、かつフラグがfalseなら、フラグをtrueにしてMOUSE_ENTEREDのMouseEventを、
マウスがcomp内、かつフラグがtrueなら、53行から58行の内容のMouseEventを、
マウスがcomp外、かつフラグがtrueなら、フラグをfalseにしてMOUSE_EXITEDWのMouseEventを、
マウスがcomp外、かつフラグがfalseなら、53行から58行の内容のMouseEventを、
comp.dispatchEvent()に渡してやればいい・・・と思います。(うろ覚え)
これで、マウスをcomp外で放したときにも対応できるので2番の問題も解決します。
上で説明したないように、FocusListenerを付加させてフォーカスにも対応したのが、
Santoshさんのページの下のほうにある投稿です。
インデントされてないので見にくいですが・・・。
で、実際に実行してみると、TitledBorderのタイトルの配置と違うことに気付きました。
TitledBorderのタイトルは、ボーダーのインセットの中央に配置されます。
一方、ComponentTitledBorderはボーダー上部にくっつくように配置されます。
また、x座標も違います。
new ComponentTitledBorder(checkBox, panel, BorderFactory.createLineBorder(Color.RED, 50));
とかにすると分かりやすいと思います。
これはSantoshさんのソースの49行目のRectangleの引数を調整してやればいいです。
int rectx = borderInsets.x + offset; //ボーダーの厚みプラスオフセット分だけ右にずらす
int recty = (borderInsets.height-size.height)/2; //コンポーネントをボーダーインセットの真ん中に
if (recty < 0) recty = 0; //ボーダーの厚みがコンポーネントの高さより小さい場合は0にする
rect = new Rectangle(rectx, recty, size.width, size.height);
こんな感じですかね。
こうすると、マウスとタイトルコンポーネントの当たり判定がずれるので、
53行目も変更します。
pt.translate(-rect.x, -rect.y);
と、こんなんで動くと思う。
会社で書いたソースを見てこのブログ書けたら楽なんだけど、
うちのところ、外部アクセスにうるさくて個人ブログすらまともに見れないので、
自分の頭にあるものをピックアップして書きました。
また作るのも面倒なんで・・・。
大体うまくいってますが(うまく言って欲しい)まだ問題があります。
まあ、使い方によりますがね、タイトルコンポーネントに
階層になっているコンポーネントを入れるとうまくいきません。
具体的には、
JPanel contentPanel = new JPanel();
JPanel panel = new JPanel();
panel.add(new JCheckBox("checkbox"));
panel.setBorder(
new ComponentTitledBorder(panel,
contentPanel,
BorderFactory.createLineBorder(Color.RED))
);
みたいにすると、タイトルには空のパネルだけが表示されます。
これを解決するためにはコンテナー内部を階層的に表示、dispatchEventするしか・・・。
Container.revalidate()で解決するといいなー。
と、こんなことやってたら1時間も残業してしまいました。
頭いてー。
階層表示はまたあとで・・・。
帰ってきてから夕食を食べてメイドガイ。
くくく、が口癖になりそうで怖いわ。
大分空気を読めないメイドガイだが、
ご主人も空気の読めなさではいい勝負をしていると思います。
残り2話というところで今日は終了。
久しぶりにまともなブログを書いたから疲れた。
ダメ人間だね。
さて、DQ9をやって寝ますかね。
[1回]
PR