忍者ブログ

マインのブログ

マインが何かを気まぐれに書く日記です。

[PR]

カテゴリー:

2024/03/19(Tue)12:52

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

No.|CommentTrackback

空白文字を可視化するテキストエリアをゴリ押しで作ってみた

カテゴリー:プログラムとか

2014/12/23(Tue)21:59

えーと、2013年の4月にテキストフィールドに入力した空白文字を可視化するやつをブログに書きました。
ちなみに、下のリンクです。
http://walla48.blog.shinobi.jp/Entry/2180/
見直してみたら、かなり無駄の多いソースでした・・・。
ブログに書いたやつは特に直す気はないので、分かる人がうまく直せばいいと思います。
ま、見てる人いないと思うけど。

で、それから1年半以上経過して、今度はテキストアリア(JTextArea)に挑戦。
なんかテキストフィールドみたいにするとおかしくなったので色々見直してました(それでテキストフィールドの無駄ソースが分かったんですが)。

やることは簡単。
またViewのpaint(Graphics)をオーバーライドして空白文字のところに図形を表示するようにします。
基本的にはテキストフィールドと同じですが、改行処理が追加になっただけ。
1文字を描画するX座標とY座標を1文字ずつ計算します。
X座標は、1文字前までの文字列の幅を保存しておきます。文字列の幅は、改行が出てきたら0に戻します。
Y座標は、改行が出てくるたびに文字の高さ分増加させます。
これで、1文字ごとの描画するX座標とY座標を計算することが出来ます。

X座標は、改行が出てきたら0に戻す以外はテキストフィールドと同じですね。
で、半角スペースや全角スペース、タブのときだけ図形を表示するだけ。これもテキストフィールドと同じです。

あとは、空白文字のところに図形を表示するViewを使うようにするだけなんですが、なーんかテキストフィールドのようにやったらうまく行かなかったんですよね。
なんかテキストエリアの中央に文字列が表示される・・・。
なんでかなーと思ってみてみたら、テキストフィールドはFieldView、テキストエリアはPlainViewでした。
つまり、テキストエリアなのに1行表示するFieldViewを使っていたため、テキストエリアの中央に文字列が表示されていたようです。
これが分かったら簡単、PlainViewをextendsして空白文字のところを図形にするViewを作って、このViewを使うTextAreaUIを作って適用するだけ。

実行結果は下のような感じ。それっぽくなりました(文字は大きくしてます)。


と、ここまで書いていてJavaに詳しい人はお気付きかと思いますが、上だけでは不完全です。
なぜなら、JTextAreaは折り返し設定が出来るからです!
JTextAreaは、折り返し設定(JTextArea.setLineWrap(boolean))を有効にすると、PlainViewではなくWrappedPlainViewを使って文字列を表示します(気になる人はBasicTextAreaUI.create(Element)のソースを見てください)。
つまり、折り返し設定が有効の場合は、空白文字を可視化するように改造したWrappedPlainViewを使うようにしないといけないのです。
折り返しを考慮して座標を決めるようにするとは思うのですが、どうやったらうまく決められるかがすぐに思いつかないので手を付けていません。

そんなわけで、いろいろ不完全なのでソースも載せません。
分かる人が、上のよく分からない説明を見つつ、テキストフィールドの奴を元に勝手に改造すればいいと思います。

あとは、個人的には改行も可視化したいなー。
なんかのテキストエディターみたいに、\r\n、\n、\rで図形を分けられるとかっこいいけど、どうもJTextAreaは、\nしか改行してくれないみたいだから、1つでいいかな。
また、ateraiさんのソースをパク・・・、もとい、参考にしてみようかなー。

拍手[0回]

PR

No.2190|Comment(0)Trackback

空白文字を可視化するテキストフィールドをゴリ押しで作ってみた

カテゴリー:プログラムとか

2013/04/06(Sat)22:28

昨日の夜あたりから、JavaSwingで、空白文字を可視化するテキストフィールドの作成に挑戦していました。
参考にしたのは、以下のaterai氏のサイトの「JTextPaneで全角スペースやタブを可視化」というサンプル。
http://terai.xrea.jp/Swing.html

途中の御託はいいからどんなのか見せろよ!という方は、最後の方を見てください。
ここからは、ちょっと説明を含めていろいろ書きます。

初めは、JEditorPaneをJTextFieldみたいに1行表示にしようと思いましたが、あえなく断念。
PlainDocument.insertString()をパクって改行を無視させたり色々やってみましたが、
・UIがJTextFieldみたいにならない。やることが多すぎてめんどー。
・キーアクションの設定がめんどー。
と、いろいろあってやめました。

そのあと、BasicTextFieldUIで、aterai氏のサンプルのEditorKitを読み込ませる方法に変更。
素直にこっちやっていればよかった・・・。
やることは簡単。
BasicTextFieldUI.getEditorKit()をオーバーライドして、aterai氏のサンプルのMyEditorKitを返すようにするだけ。
おお、簡単簡単。
ただ、UIって、MetalとかWindowsとかMotifとかいろいろあるので、JTextFieldのサブクラスを作って、
UIがMetalTextFieldUIなら、それのサブクラスを設定して、とちょっとひねってみてます。

ただ、aterai氏のWhitespaceLabelViewでは可視化したものが変な位置に表示されてしまいました。
テキストフィールド内に文字列が収まれば問題ないのですが、テキストフィールドの幅より長い文字列が入ると、
可視化のために表示した図形がスクロール前のところに表示されたままになる、という問題です。
サンプルは、JTextPane用の物なので、JTextFieldのようにスクロールペインなしでスクロールすることを考慮していないのが原因と思われます。(詳しくないので正確なことはわかりません)

そこで、同サイトにあった「JEditorPaneで改行を表示」というサンプルを見てみると、modelToView()というスクロール(っぽいの)に対応したコードがあるじゃないですか!
で、さっそくこれをパ・・・、もとい参考にして組み直してみました。
が、今度は図形が行末に表示されるようになりました・・・。
よくよく見ると、modelToView()の第1引数がgetEndOffset()になっていました。
これは、表示する範囲の最後を意味するらしく、そこからスクロール後の座標を計算していたために行末になってたっぽいです。
直し方は、getStartOffset()で行の先頭から座標を計算するようにするだけ。

色々書きましたが、ほとんどがサンプルソースをそのままで、自分で新しいことは特にやってません。
これだけだとあんまりなので、ちょっと汎用性を持たせるために、外部から置き換える文字と変わりに表示する図形を紐づけられるようにしてみました。

以下にサンプロプログラムとソース、実行結果のスクリーンショットを置きます。
ちなみに、サンプルプログラムではWordみたいに、
・半角スペースは小さい中点にする
・タブは小さい→にする
・全角スペースは□にする
ようになってます。
ただ、なぜかタブはうまくいかないことがある・・・。JTextFieldでもなんかうまくいかないんだけど、何故だろう??


↑スクリーンショットです。

WSVTextField_src.zip
↑サンプルプログラムのソースです。

WSVTextField_doc.zip
↑JavaDocです。

WSVTextField.jar
↑サンプルプログラムのJarです。Java1.6を想定しています。

で、いつものごとく免責事項を。
この記事で紹介したサンプルソースやプログラムを使用して起こったいかなる不具合、不都合などについて、私マインは一切の責任を負いません。
全て自己責任で使用してください。
また、ソース中やJavaDocに記載している内容に誤りがあっても責任を負いませんし、説明もしません。
それから、もしここのソースを使う場合は、aterai氏に感謝しましょう。
それと、勝手に紹介してすみません・・・m(_ _)m

それにしても、久しぶりのまともっぽいブログだった。
さて、スパロボUXを始めますか。

拍手[0回]

No.2180|Comment(1)Trackback

JTableをプログラムからスクロールするとヘッダーがずれて表示される

カテゴリー:プログラムとか

2010/08/01(Sun)21:01

えと、今日のブログプログラム編です。
1日の出来事編は1つ前の記事を見てください。

話は金曜にさかのぼります。
金曜に仕事中、変なものを見つけたと報告があった。
JTableをスクロールするとテーブルヘッダーがずれるというもの。
定時間際の発見だったので、ちょっと残って調査してました。
スクロールといってもスクロールバーをマウスで動かすのではなく、
Component.scrollRectToVisible()を使ったスクロールです。
scrollRectToVisible()を使ってテーブルの左上のセルを表示させようとすると
テーブルヘッダーだけがスクロールする前の位置にあるというもの。
別の場所でのscrollRectToVisible()はちゃんと動いているので、
現象の起こったところがおかしいはず。

自分で作ったカスタムコンポーネントがいけないんだろうなーと思って
色々いじったり、デバッガで止めてみたりしたけど結局よく分からなかった。
1時間くらいやって、あまり残業するなと言われ帰りました。
で、今日、と言うか今さっき。
原因究明のため、ちょっとプログラムを組んでみた。
上にも書いたとおり、コンポーネントの問題ではなく、
処理フローの問題と思われる。
というかそれしかない。

1つ思い当たる節があって、プログラムを組んでみたら
すぐに現象が発生した。
テストプログラムの概要は以下のとおり。
・ボタンを押すと表示されているテーブルが切り替わる(メニューみたいなイメージ)
・テーブルを切り替えるとき、テーブルの左上のセルが表示されるようにする
現象発生操作は以下のとおり。
1.テーブルAを表示させる。
ss0.JPG

2.列幅を大きくして右にスクロールさせる
ss1.JPG

3.テーブルBを表示させる
ss01.JPG

4.またテーブルAを表示させると・・・
ss2.JPG

ちなみに処理的には下みたいな感じでやってます。
1.ボタンが押されたら表示しているテーブルを持つパネルを右のパネルからはずす
2.表示するテーブルをスクロールする
3.右のパネルに表示するテーブルを持つパネルを追加する
4.右のパネルを再描画(revalidateとrepaint)をする

詳しい人はこれ見ただけで原因が分かると思いますが、
オレにはすぐには分かりませんでした。
問題を解決するためには上の2と3の手順を逆にします。
問題の現象が起こった原因は想像でしかないのですが、
表示されていないコンポーネントの座標は計算できないという
Swing(というかJavaのGUI関係かな?awtとか)の仕様によるものかと。

通常ならスクロールペインを操作する時は表示されているため、
スクロールするたびにヘッダーの位置を計算して表示しているのではないかなと思います。
しかし、上の手順でスクロールしてしまうと、
親コンポーネントがないので座標を算出できず、
前のヘッダー位置で表示してしまっているのではないかと。
まあ、つまり、モノを表示する時はコンポーネント階層を組んだあとに
座標関係を更新(スクロールとか)して、それから「表示」させろということですかね。
つーか、テーブル部分はちゃんとスクロールできてるんだから
ヘッダーもスクロールしてくれよ・・・。

ということで、一応問題解決。
明日報告しますか。
でも、自動的にスクロールしなくていいよと言われたからなー。
元に戻して終わりですかね。
Javaむずいっす。

明日も仕事か。
行きたくねーな・・・。

拍手[1回]

No.1991|Comment(0)Trackback()

Javaに振り回された1日

カテゴリー:プログラムとか

2010/06/22(Tue)21:44

まあ、タイトルのとおりです。
クソJavaのせいで色々面倒なことになってます。
ああ、これどうしよ・・・。
あ、ちなみにここから下はとても長い&つまらないので
プログラムとかJavaとかに興味がない人は見なくていいですよ。

今日もプログラム。
Java Swingで作ったプログラムの、キーボード操作とマウス操作を組み合わせた時に
変な動きになるということで、色々やってました。
変なことになるのは次のような操作をしたとき。
1.JList上で項目を選択する
2.1番の時にクリックは押したままにする
3.Alt+Tabで別のウィンドウをアクティブにする
4.またAlt+Tabで元のJavaアプリウィンドウをアクティブにする
5.キーボードの上下ボタンを押すとセレクションは動くのにセレクション変更を拾えない!
といったものでした。

何でかなーと思って調べてみました。
そしたら以下が判明。
知っている人は知っていると思いますが、セレクション変更を検知する
ListSelectionListenerはクリックを押した時と放した時で2回は呼ばれます。
このときの重複をはじくためにListSelectionListener.valueChanged()内で
ListSelectionEvent.getValueIsAdjusting()がtrueかfalseのどちらかで処理するようにするのが
どうも定石のようです。
ちなみに、マウスドラッグでセレクションをぐーと動かしたりすると
ListSelectionEvent.getValueIsAdjusting()がtrueになります。
クリックを放す(マウスリリース)とListSelectionEvent.getValueIsAdjusting()がfalseに
なります。

自分のプログラムではfalseの時に処理するようにしてました。
理由としては、キーボードの上下でセレクションを変更すると
ListSelectionEvent.getValueIsAdjusting()がfalseになるためです。
このListSelectionEvent.getValueIsAdjusting()ですが、
「このイベントが複数の変更イベントのうちの 1 つである場合に true を返します」
と、よく分からない感じでAPIに書いてありますが、
まあ、要するに、「連続して変更されているかもしれない時はtrueになりますよ」というような意味かと。
つまり、マウス操作のときはドラッグで連続して変更されるかもしれないので
ドラッグ中はtrueになるらしいです。
で、終わったら(リリースしたら)falseになるんでしょうね。
キーボード操作ではキープレス一個ごとに見るので連続しないから常にfalseになるのではないかと。
押しっぱも連打と同じだと見ているんでしょう。

まあ、そんな理由からListSelectionEvent.getValueIsAdjusting()がfalseになったときに
セレクション変更検知の処理をしてたんです。
で、なぜうまく行かなかったかというと、これがクソJavaの罠でした。
まずは、ListSelectionEvent.getValueIsAdjusting()の変移を調べてみることに。
そしたら、マウスをクリックしたままアクティブウィンドウを別のにして元に戻してから
キーボード操作をするとそのあとはずっとtrueになりました・・・。
もー、What's the fXXkて感じですよ。
もう少し調べるために今度はマウスリスナーとつけて見てやってみました。
そしたら、マウスを押したままアクティブウィンドウを変更したら
マウスリリースが呼ばれないでマウスイクジットが呼ばれてました。
まあ、よくよく考えればこれは当たり前のことですが、
問題はこのときにListSelectionEvent.getValueIsAdjusting()がtrueのままになっていること。
どうもキーボード操作のときにListSelectionEvent.getValueIsAdjusting()がfalseになるのではなく、
前回のListSelectionEvent.getValueIsAdjusting()の値のままになるようです。
なので、マウス操作でtrueのままになるとそのあとは永遠にキーボード操作でもtrueになって
オレの実装ではうまく行かなくなってました。

こんなのJavaのバグかと思うんですが、
今までそういうのが話題に上がってないところを見ると、これが普通のようなので、
なんとか解決できないかなーと思ってちょっと考えて見ました。
まず考えたのは「マウス押しっぱでウィンドウが変わったらリリースと判断するようにする」ということ。
まあ、簡単ですわな。
class MyMouseAdapter extends MouseAdapter {
    private JList list = null;
    private boolean pressed = false;
    public MyMouseAdapter(JList l) {
        list = l;
    }
    public void mousePressed(MouseEvent e) {
        pressed = true;
    }
    public void mouseReleased(MouseEvent e) {
        pressed = false;
    }
    public void mouseExited(MouseEvent e) {
        if (pressed) {
            MouseEvent newEvent =
                new MouseEvent(e.getComponent(), MouseEvent.RELEASED, e.getWhen(),
                                                 e.getModifiresEx(), e.getX(), e.getY(), e.getClickCount(),
                                                 e.isPopupTrigger(), e.getButton());
            list.dispatchEvent(newEvent);
        }
    }
}
つーのを、JListに付けてやればいいわけですよ。

でも、先輩に「ドラッグ中でもセレクションが変わったら検知できるようにしてほしい」と
言われたので、ListSelectionEvent.getValueIsAdjusting()がtrueで判定することになりました。
もちろんキーボード操作も見越して。
で、考えたのが以下のリスナー。
class ListSelectionChangeListener implements ListSelectionListener {
    private boolean truedFlag = false;
    public void valueChanged(ListSelectionEvent e) {
        if (e.getValueIsAdjusting()) {
            truedFlag = true;
            selectionChanged(e);
        }
        else {
            if (truedFlag) {
                selectionChanged(e);
            }
            truedFlag = false;
         }
    }
    public void selectionChanged(ListSelectionEvent e) {
        //ここにセレクションが変わったときの処理を書く
    }
}
これならマウスリリースの時をはじけて、かつ、falseとtrueの両方のときのキーボード操作に
対応できました。(簡単にしかテストしてないんですけどね・・・)
ちょっとやってみた感じうまくいってそうなので先輩に見てもらったんですが、
Javaの仕様が(本当に)オレの想定通りなのか疑問という点と、
Ctrl+Aの時にselectionChanged()が2回呼ばれるということでボツになりました。
(なのでここにさらしてるんですけどね)

まず、Ctrl+AでもselectionChanged()が2回呼ばれる原因ですが、
BasicListUIの中にあるHandler(マウス、キーボードなどのリスナーパック)で
Ctrl+Aのアクションを見てみると、setSelectionInterval()とaddSelectionInterval()を
getValueIsAdjuting()がtrueになるように呼んでいる所為でした。
両方のメソッドはセレクションを変更するのでListSelectionEventが発行されます。
もー、何やってんよ。
仕様が想定通りかというのは、ちゃんとドキュメントに書いてあるかが心配されました。
「実際にそうなってもドキュメント(APIとか)に書いてないことは安易に実装すべきでない」と言われ、
しゅんとなりました。

で、午後はずっと考察&やり直し。
色々考えましたよ。
valueChanged()が呼ばれるたびに選択されているインデックスを比べてみる、とか。
でも、これは性能が悪くてですね。
セレクションの変更は基本は追加と解除の2つで、「切り替え」がないので、
選択されている最小インデックス、最大インデックス、選択数だけを保存すればいいんですが、
選択数はListSelectionEventではすぐに取れません。
ListSelectionEvent.getSource()でListSelectionModelを取り出して、
モデルから最小インデックスと最大インデックスを取って、
それをループして何個選択されているかを調べないと選択数が分かりません。
JList.getSelectedIndices()やJTable.getSelectedRowCount()も同じようにループさせてます。
作り方次第ですけど、たくさんデータがあるときに何回もループさせると
ヒジョーに大変なことになるので、却下。

なので、もうListSelectionListenerの中でどうこうするのではなく、
セレクション変更の処理でどっかのメソッドを呼んでどうせJListを参照するんだから
そこで最小、最大、選択数を取って前回呼ばれたときと同じ選択状態が調べることになりました。
はあ。
今日は調査&試行錯誤で何時間無駄にしたんだろ・・・。
てか、Javaがセレクション変更をすぐに検知できるリスナーか何か作れよ。

今日で2つくらいバグが直るかなーと思ったら1つも直らなかった。
もーー。
だんだん時間がなくなってきたのでちょっとイライラしてます。
カルシウム取ります。
定時から少し残って頭の中を整理してました。
明日はソースを整理しないと。
疲れるなー。

ということで、今日はぜんぜん進展してません。
あと2週間?くらいしかないというのに。
Javaはもうちょっと色々できるようにして欲しいです。
あと、何をどうするとどうなるのか全部書きやがれ(怒)。
中身のデフォルト実装もどういう動作か書きやがれ(怒×2)。

さて、もう風呂に入るかな。
上がったらDQMJ2で選手権に登録して、それからXenobladeでもやるか。
あ、上のほうに書いたソース、別に使ってもいいですけど
あんまテストしてないし今書いたからスペルミスとかあるかもですよ?
使うときはそれを覚悟してください。
長々と駄文失礼しました。

拍手[0回]

No.1972|Comment(0)Trackback()

早くもGW最終日

カテゴリー:プログラムとか

2010/05/04(Tue)18:32

オレは今日がGW最終日です。
ああ、結局この連休はDQMJ2しかやってなかったな・・・。
なんか明日鬱りそうだ。
スローペースで仕事しよう・・・。

明日は休出なので今日がGW最終日。
最初にも書きましたが、ブログも書かずにずっとDQMJ2をやってました。
うろちょろしてたせいで今だレオソード倒せてません。
つーか、スキルの継承ミスったな・・・。
あと、ちょっと前に書いた配合云々の話、まったくの見当違いもいいところでしたね。
DQMJの攻略サイトを見てようやく思い出しましたよ。
頭の中がずっとGBのままになってる古い人間でした。

えーと、明日から仕事ということで、リハビリにプログラムを書いてました。
今回は階層構造のスクロールペインのスクロール伝播、とでも題しておきましょうか。
Java SwingのJScrollPaneは、その上でマウスホイールを回すとスクロールするんですが、
中にJScrollPaneがあるときに、中のJScrollPane上でホイールを回すと
中のJScrollPaneにしかスクロールが動作しません。
なんのこっちゃわからないと思いますが、JScrollPaneの中に
JScrollPaneを持つJPanelでも置いて外のJScrollPaneにだけスクロールバーが表示されるように
サイズ調整したうえでホイールを回してみるとわかると思います。

で、中のJScrollPaneのスクロールの必要がない時は
外のJScrollPaneがスクロールするべきだと思ってます。
実際、仕事でも先輩からそういう指摘がありましたし、
この忍者ブログのエディターもそういう動きするじゃないですか。
なので小1時間くらいでこれを実装したわけです。
実装したあと色々試してみましたが、なんとか動いている様子。
2階層までしか試してないけど、理論上は何階層でもいけるはず。
仕事では3階層以上は想定してないんでテストしなくていいかな、と。
これで宿題が1つ減った。

今回はUIをいじりましたが、こういう設定Javaが用意してないんですかね?
てか、デフォルト動作だろ。
メソッド1個呼んだだけでこういうのできるようになってるのかなー。
Javaよく分かりません。
色々できるのはいいけど、どれをどうすれば何が出来るかがわからないのがいけないと思います。
まあ、API仕様書なんてどこもこんな感じですよね・・・。

えと、今回はサンプルコードなしで。
仕事で使ったものでも、先輩曰く「ばれなきゃOK」とか言ってたけど、ばれたら怖いんで。
まあ、先にここに書いたものを仕事で使うようになったものは隠してませんけどね・・・。
前々から思ってることだけど、こういうのってどうなんでしょうね。
社内SNSの日記に書くのもいけないのかな・・・。
パーツ程度ならせめて社内で共有とかできればいいのに。

さて、DQMJ2でもやろうかな。
はあ、もう休みも終わりか・・・。<くどい

拍手[0回]

No.1947|Comment(0)Trackback()

Javaアプリの格納パスを取得する

カテゴリー:プログラムとか

2010/02/11(Thu)20:51

Javaで実行ファイル(Jarファイル)の格納パスを取得する方法です。
一応、Eclipseで実行した時はプロジェクトの出力先フォルダを
取得できるようにしてみました。
こうすると、Eclipseで組んでる時とJarにしたときで
同じフォルダ構成が使えるので色々便利かなーと。

まず、普通の実行パスの取得方法は、
System.getProperty("user.dir");
で取得できます。
が、これだと「Jarファイルを実行したパス」しか取れません。
例えば、コマンドプロンプトでデスクトップから
Cドライブ直下のJarファイルを実行すると上のメソッドの戻り値は
デスクトップのパスになり、Jarファイルの格納パスではありません。

Jarの格納パスを取るには、確実に存在するクラスファイルのパスをURIで取得して、
それをうにゃうにゃするとJarの格納パスが取れます。
「うにゃうにゃ」で何をやるかは、まあ、取得したURIを見てもらえば分かると思います。
気をつけないといけないのはJarファイルの時は頭に「jar:」がついてること、
デフォルトパッケージの時はgetPackage()はnullになることですかね。
パスをURLで扱わないのは、なんかURLだと日本語パスがおかしくなったような気がするため。
そんなにテストしてないのでなんとも言えませんが。

一応、実行した時のイメージを貼っておきます。
・Jarファイルで実行した時
InstallPathGetterTestSS1.JPG
・Eclipseで実行した時
InstallPathGetterTestSS2.JPG

あと、ソースとJarファイルを。
InstallPathGetterTest.jara
InstallPathGetterTest.jar

拍手[0回]

No.1920|Comment(0)Trackback()

スクロールの必要がないときにスクロールバーをサイズいっぱいにする

カテゴリー:プログラムとか

2010/01/06(Wed)00:31

えー、以前スクロールの有無でスクロールバーを無効/有効を切り替える方法を書きました。
今回はこれをちょっと改造してスクロールバーをサイズいっぱいにする(見せかける)方法です。
これはWord2007の垂直方向のスクロールバーみたいなイメージです。

その方法ですが、スクロールペインのスクロールバーに追加したAdjustmentListenerで
スクロールの有無を判定します。
スクロールの有無はJScrollBar.getMaximum()とJScrollBar.getVisibleAmount()を見ます。
maximumとvisibleAmountの値が同じ時はスクロールの必要がないときです。
maximum>visibleAmountのときはスクロールが必要な時です。
もし、スクロールが必要ない時はスクロールバーの最大値を+1してやります。
最大値の設定方法はJScrollBar.setMaximum(int)で出来ます。
ノブをドラッグすると若干移動してしまいますが、放すと元に戻ります。
また、上下右左のボタンを押してもスクロールしません。

前作ったサンプルプログラムを改造したのでSSを置きます。
MineScrollPaneSS1_v2.JPG
スクロールが必要ないとき

MineScrollPaneSS2_v2.JPG
スクロールが必要なとき

Jarファイル、ソース、Javadocは下です。
あまりテストしてないので、ちゃんと動けばいいんですけど・・・。
サンプルプログラム
ソース
Javadoc

参考までに:「スクロールの有無でスクロールバーの無効/有効を切り替える」に関する記事

以下、スクロールバーの挙動以外の変更点です。
どちらも従来のsetHorizontalScrollBarPolicyとsetVerticalScrollBarPolicyの挙動にあわせる変更です。
・独自のスクロールバーポリシーをセットした時にバウンドプロパティを通知するように変更
・ポリシーを変更した時にスクロールペインを再描画するように変更

拍手[0回]

No.1896|Comment(0)Trackback()

あれ?意外に余裕?

カテゴリー:プログラムとか

2010/01/01(Fri)00:49

なーんか意外にネット軽いですねー。
年明けてもう30分以上たちますからねー。
ということで、
明けましておめでとうございます。
今年もよろしくお願いします。

えーと、前の日記を書いてからちょろちょろとプログラムを組んでました。
今回やってたのはスクロールペインのちょっとした改造みたいなことやってました。
やってたことは、スクロールの必要がない場合、バーは無効(不活性、非活性)になる、というやつ。
IEやEclipseではよくあることですが、JScrollPaneではスクロールバーの表示ポリシーは
・必要に応じて表示する
・常に表示しない
・常に表示する
の3つしかないです。
なので、そのまま使っただけではIEやEclipseみたいなことが出来ないわけです。

で、スクロールの有無によってスクロールバーの有効・無効の切り替えの方法ですが、
JScrollPaneのスクロールバー(getHorizontalScrollBar()とgetVerticalScrollBar()で取得)に
AdjustmentListenerを設定して、それば呼び出されるたびにスクロールバーの
状態を見て有効・無効を切り替えます。
スクロールの有無はJScrollBar.getMaximum()とJScrollBar.getVisibleAmount()を見ます。
maximumとvisibleAmountの値が同じ時はスクロールの必要がないときです。
maximum>visibleAmountのときはスクロールが必要な時です。
その判定をJScrollBar.setVisible()で有効・無効を切り替えます。

それでプログラムを組んでみました。
えと、名前が変なのは無視してください。
一応、マインなのでJの代わりにMineを付けてみただけです。
MineScrollPaneSS1.JPG
スクロールが必要ないとき

MineScrollPaneSS2.JPG
スクロールが必要な時

で、以下、Jarファイル、ソースファイル、Javadocです。
サンプルとして実行してみたい時はJarファイルをダウンロードして実行してください。
そのプログラムのソースがzipになってます。
一応、Javadocも作ってみました。
参考までに

サンプルプログラム
ソース
Javadoc

なお、このプログラム、ソースなどを使用して起きたいかなる不具合等については
私マインは一切の責任を負いません。
自己責任でお願いします。
まあ、ちょっとした意見とかなら受け付けますけど。
あと、ソースはかなりテキトーに作ってるんで最善のものかは知りません。
あしからず。

拍手[0回]

No.1891|Comment(0)Trackback()

プログラミング的なことをちょろちょろと

カテゴリー:プログラムとか

2009/10/06(Tue)20:32

久しぶりの1日2回のブログ。
仕事でやってたプログラミングのことをちょろちょろと。
興味のない人は見なくていいですよ。
面白くないですし。

えーと、今回書くのは前にも書いたComponentTitledBorderのこと。
サンプルはてんぷらさんに載ってますが、
てんぷらさんのソースが修正されていました。
しかし、(オレとしては)これでもまだ不十分だったので色々修正を加えました。
不十分だったところは、前にも書いたもののとおり、
階層構造のコンポーネントをタイトルに置けないことでした。
まずはてんぷらさんのソースをダウンロード。
そのあとpaintBorder()のSwingUtilities.paintComponent()の前あたりに、
タイトルコンポーネント(compと言う変数だったかな?)のdoLayout()とvalidate()を呼ぶ。
そしてpaintBorder()の最後にpaintBorder()の第1引数のComponentをrepaint()をする。
このままだと無限ループのような形になるのでフラグでも立ててやって、
最初の描画の時だけ2回描画するようにします。
なぜ2回描画する必要があるのか。
それは知りません。
こうやらないとちゃんと表示されません。
Javaの仕様です。
たぶん。

これでボタンとかチェックボックスとか色々持ったパネルをタイトルコンポーネントにして表示できます。
次はdispatchEvent()の修正。
まず、タイトルコンポーネントが階層構造になっているかをチェック。
Containerのインスタンスであるかをinstanceofで調べればいいです。
あとは、コンテナー内のコンポーネント全てに対しててんぷらさんのdispatchEventの
中にあることみたいなのを書いていけばOKです。
再帰を使えばすぐ出来ます。
しかし、色々触っていると分かると思いますが、
ビミョーにonMouseとかがうまくいってません。

解決法は、タイトルコンポーネント内のそれぞれのコンポーネントに対して
MouseEventをいじってそれをdispatchEventに渡すようにします。
何のこっちゃと思うかもしれませんが、タイトルコンポーネント内の
全てのコンポーネントに以下のようなことします。
まず、「以前のマウス座標」を保持するメンバー変数を用意します。
最初にdispatchEventに渡されたMouseEvent(mEventとする)が、
MouseEvent.MOUSE_RELEASEであるかとチェックします。
もしMOUSE_RELEASEならそのままmEventをdispatchEventに渡してやります。

もしMOUSE_RELEASEでなければ次に、SwingUtilities.convertMouseEvent()で
帰ってきたMouseEvent(meとする)の座標がコンポーネント内にあるかを調べます。
component.contains(me.getPoint())ですぐに調べられます。
もし、コンポーネント内にあるのであれば、次に以前のマウス座標が
そのコンポーネント内にあったかを調べます。

ここで、今の座標がコンポーネント内かつ前の座標もコンポーネント内であれば、
同じコンポーネントの中をマウスが移動したことになるので
dispatchEventにはmeをそのまま渡してやります。
もし、今の座標がコンポーネント内だけど以前の座標がコンポーネント外であれば
そのコンポーネントにマウスが入ったことになるので、
meのIDをMouseEvent.MOUSE_ENTEREDに置き換えたMouseEventを
dispatchEventに渡してやります。

もし、今の座標がコンポーネント内でなければ
次に以前の座標がコンポーネント内であるかをチェックします。
以前の座標がコンポーネント内であるなら
マウスはコンポーネントを出たことになるので、
meのIDをMouseEvent.MOUSE_EXITEDに置き換えたMouseEventを渡してやればOKです。

これで少なくともオレが想定するComponentTitltedBorderの動作が出来てると思います。
ソースとサンプルプログラムは・・・。
いつかと言うことで・・・。
今週末くらいに元気でゲームに飽きてたら作ります。
まあ、これだけ出来ててもまだ完璧じゃないんですけどねー。
タイトルコンポーネントを置けるところが左上一箇所だけなんで。
中央とかに置けるように出来たらかっこいいですねー。

と、取り留めない文章になりました。
ごめんなさい。
コードがないとプログラムのことをブログで書くのは無理ですな。
なんとなく雰囲気だけでも分かってもらえるとかなりうれしいです。

拍手[0回]

No.1829|Comment(0)Trackback()

6連休が始まる

カテゴリー:プログラムとか

2009/09/18(Fri)00:20

明日から6連休です。
やほーい。
・・・、連休明けはきつそうだな・・・。

今日も仕事。
でも、そんなに作業はしてない。
仕事で使うソフトの使い方を書いてたり、テストプログラムを作ってたりした。
JavaのSwingを使っているんですけど、結構難しい。
Eclipseではどうやってるんでしょうかね。
今日はチェックボックスリストに挑戦。
Eclipseで実行する時にファイルの更新を保存しますかの
ダイアログのリストみたいなのを作ろうとしてました。
結論から言えばできましたが、これをどうやったら汎用化できるのだろうか・・・。

JListにチェックボックスを入れるのは以外に簡単です。
JCheckBoxを拡張し、ListCellRendererを実現してやって、
格納するデータにフラグを持たせてやればいいです。
或いは、JCheckBoxをリストに格納してやればいいです。
有効無効の切り替えは、JListにMouseListenerを登録して、
クリックした時にマウスカーソルの場所からリストのインデックスを取得、
そのインデックスのデータのフラグを変更するなり、
チェックボックスのチェックをつけたりはずしたりするなりすればいいです。

ただ、この方法だとチェックボックスの四角だけでなく、
文字列をクリックしてもチェックの有効/無効が切り替わります。
Eclipseの保存確認ダイアログをいじると分かると思いますが、
文字列のところをクリックしても有効/無効は切り替わりません。
なので、ちょっと変更。

始めはリストセルのチェックボックスの四角のところにマウスカーソルがあるとき、
みたいな判定をつけようとしたのですが、ちょっと別なことをやってみました。
今回やってみたのは、データを登録する際にチェックボックスとラベルを持つ
パネルをリストに入れる、という方法です。
ListModelとListCellRendererを改造したものを使えば出来ます。
マウスのあるインデックスのデータ(パネル)を取り出して、
そのパネルのチェックボックスの有効/無効を切り替えることが出来ます。
もちろん、チェックボックスの上にマウスカーソルがあるとき、という条件が必要ですが。
この方法だと、Eclipseみたいに、チェックボックスの右にアイコンがあって、
その右に文字列を表示、みたいなことも比較的簡単に出来ます。

最初に書いたとおり、汎用化できるのかとかまだ検証してません。
テストもそんなにしてないので実際は使えない可能性も。
これが出来なかったらJTableにチェックボックスを入れるヤツに変更ですかね。
これならてんぷらにサンプルがあるし。

と、こんなことをやってたら定時になりました。
きりがよかったのでさっさと帰ってきました。
帰ってきてメールをチェック。
まだポケモンの支払いは来てませんでした。
アマゾンを見てみると、ゴールドの値段が6000円になっていた。
どうも、昨日オレが申し込んだ後にアマゾンが確保していた分が埋まったみたいです。
なかなか際どいタイミングだったようです。
昨日のメールを見て、ちゃんと定価以下の値段であることも確認しました。
後は待つだけか。

夕食後、DQ9をやってました。
うえー、金稼ぎだリー・・・。
ダンジョンに1階潜って5000ちょっとか・・・。
もう少し稼げるといいんだが・・・。
やっぱレベルか?レベルなのか??

そのあとmixiアプリで遊んでました。
サンシャイン牧場とアルヴィオンを登録してみました。
牧場のほうはバグか何かでブラウザが3回ほど落ちました・・・。
マイミク関連の操作はしないようにしよう・・・。
平日とかふつーに操作できないから作物が全滅しそうだな・・・。
アルヴィオンは戦闘が自動で進むのである程度運が必要。
まだ最初のクエストすらクリアできない・・・。
もう1つくらい攻撃魔法カード入れてみるか?

日記を書いてたらもうこんな時間。
牧場を一回覗いてから寝ますかね。

拍手[0回]

No.1811|Comment(0)Trackback()