Java Software
トップページに戻ります ▼CoffeeMaker プログラム解説▼

■プログラム解説・その2-タブサイズの読込と保存(と、GUIを利用した変更)-■

今回説明しているソースファイルをダウンロードする(CoffeeMaker0_1_1.java 8.18KB)●

●こうしたテキストエディタで、簡単なレイアウトを実現するには、スペースや、Tabキーのタブを使用します。
タブサイズは、Javaではデフォルトで8(全角サイズ)になっています。実は、この8というのは結構使いづらく、1行に2回ほどタブを使用すると、 その後の文章を読むのにスライドバーをずらさなければならないほどです。
これでは使いずらいので、変更を試みています。

まず、CoffeeMakerクラスの冒頭で、tabsize変数を設定しています。
これは、起動時に読み込んだ(前回と同様にsetting.iniに格納しています)タブの設定をクラス全体で利用可能にし、ファイルの読込時などでこの変数を参照することで、タブサイズを設定しているのです。
実際に設定を読み込んでいる所は、160行目のCoffeeMakerメソッドの中の

tabsize = profs.TabSizeLoad();

という所です。
この1行前で、Profilesクラスのインスタンスを作成しています。
という事は、このメソッドは当然ながら、Profilesクラスのメソッドです。
主な動作は前回説明したものと同様なので、そちらの方を参考にソースを1行ずつ検討してみてください。

次の行で、

textArea.setTabSize(tabsize);

としています。
ここで、タブのサイズをテキストエリアに設定しているわけですが、

setTabSize();

というメソッドはどこにあるのでしょうか?
java.sun.comで提供されているJDKドキュメントで調べてみると、javax.swing.JTextAreaクラスに存在しています。
(故にimport文で、Javax.swing.*の宣言をしているわけですが)
このクラスにはswingのテキストエリアを操作する為の色々と便利なメソッドが用意されています。色々と使ってみると良いでしょう。

また、今回は、GUIを利用したプロパティの変更を実現する為、[設定]メニューを追加し、その中にタブ設定を行うためのダイアログボックスを 表示するメニューを追加しています。
内部クラスとして、TabDialogクラスを追加し、ダイアログボックスの振る舞いを表記していますが、この解説は次回に回すことにします。
何故かというと、このダイアログボックスで設定を変更しても、今はまだ変更がリアルタイムに生かされないからです。
次回ではこのあたりの説明を詳しくしていきたいと思います。

■後日談・その1(バージョン0.1.2へのバージョンアップに際して)■

今回説明しているソースファイルをダウンロードする(CoffeeMaker0_1_2.java 8.61KB)●

●実は、あの後色々と動作を調べていくうちに奇妙な現象を発見しました。
テキストエリア内をドラッグして文章を選択すると、タブの大きさが設定してある通りになって選択されていくのです。
これはどういう事かというと、
「実はダイアログで設定された内容が反映されていた」
という事に他なりません。
TabDialogクラスの内容は成功だという事は、つまり、
「再描画が行われていない」
という事が原因で、設定が反映されていない様に見えたのです。
(その後、本当の原因が判明しました。後書きその2をお読みください)
それならば再描画のメソッドを呼び出せば良いのですが、結構面倒な所が多く、
(repaint();で良いと思いますが、範囲を数値で入力したりするので…)
あまり実用的ではありません。
と、いうわけで今回は、少し大きい仕事をさせて、強制的にテキストエリアを再描画させてみました。
具体的には、

String tatxtという変数にテキストの内容を全て格納。

タブの設定を行う

テキストを無理矢理ペーストして、再描画を起こす。

という段階を踏んでいます。
しかしながら、こういった強制再描画の方法は、リソースを大量に使用している
(tatxtにテキストを格納しているので、テキストのサイズに依存します)
可能性が高いので注意が必要です。

■後日談その2■

●更に調査を進めていく内に次の事が判明しました。
今回の機能変更の中に
「ファイルの書込み・読込時にタイトルバーに使用しているファイル名を表示する」
というものがありますが、この時ダイアログボックスを使用しているのが分かると思います。
SaveクラスやLoadクラス、そして今回の話のメインになるTabDialogクラスは、クラスの冒頭でこんなインスタンスを設定しています。

JTextArea textArea;
JFrame frame;

そしてこのインスタンスはクラス名と同じメソッド
(クラス名と同じメソッドはクラスの呼び出し時に一番最初に呼び出されます)
でこの様に設定されています。

this.textArea = textArea;
this.frame = frame;

「ここで言うテキストエリアはダイアログボックスを呼び出したテキストエリアだ」
「ここで言うフレームはダイアログボックスを呼び出し親のフレームだ」
という解釈で良いと思いますが、つまり、このダイアログボックスが影響を与える「もの」を指定しているのです。
ここからが本題ですが、CoffeeMakerの0_1_1以下のソースではSaveクラスを除く、Loadクラスと0_1_1で追加されたTabDialogクラスでは、JFrameのインスタンスではなく、

Component parentWindow;

というものを設定していました。
実はここが設定が反映されていなかった最大の原因であったのです。
Componentとは何かといいますと、ウィンドウ全体の事を指すらしいのですが(不勉強の為、結構あやふやです)こちらを指定しても、ウィンドウのパーツであるテキストエリアの設定を変更することが出来ないのです。
JFrameはウィンドウ内のもの全体の事を指し、こちらを通すとウィンドウの各種設定を変更することができる、らしいです。
しかしながら、
「では、後書きその1で説明したテキストエリアの再描画はいらないのでは?」
と思われる方も多いと思いますが、実はダメだったりします。
もし、半信半疑の方がいらっしゃいましたら、今回配布しています、CoffeeMaker0_1_2.javaのソースの130行辺りにあります

textArea.setText(tatxt);

の一文を消去(行頭の//を付けてコメントにしてください)し、
CoffeeMaker.java
と名前を付けて保存し、コンパイルして確かめてみてください。
ダイアログボックスからタブサイズを設定し、OKボタンを押してみても、見た目の変更がありません。
実は、設定そのものは完了しています。
(テキストエリアでドラッグし、文章を選択しようとしてみてください)
…そう、
「テキストエリアの再描画」
がsetTabSize();では行われないのです。
read();などの大きい変更のメソッドでは暗黙的に再描画が行われているようですが…。
そういう理由で、再描画を起こす命令を指定しています。

■後書きその3(バージョン0.1.3へのバージョンアップに関して)■

今回説明しているソースファイルをダウンロードする(CoffeeMaker0_1_3.java 10.7KB)●

●前回のバージョンより、タブ設定をGUIサイドから変更することが可能になったのですが、2つの問題点がありました。

  1. タブダイアログを開くとそれまでの設定したタブのサイズを表示していない
  2. 変更するのを中止しようとして[中止]ボタンや、ウィンドウの[閉じる]ボタンを押しても変更されてしまう。

これらのバグを除去する為、TabDialogクラスを変更してみました。

1.以前の設定を読み込み、デフォルトでラジオボタンを選択する

この解説の冒頭で int tabsizeを設定していたことを覚えていますでしょうか。
あの変数はCoffeeMakerクラス内でどこからでも呼び出せる様にクラスの始めで設定しました。これを今回も呼び出します。
TabDialogクラスのactionPerformed()メソッド、の途中で次のような表現の場所があると思います。

{
if (tabsize == 2) rb1.setSelected(true);
else
if (tabsize == 4) rb2.setSelected(true);
else
if (tabsize == 6) rb3.setSelected(true);
else
if (tabsize == 8) rb4.setSelected(true);
else rb2.setSelected(true);
}

これは{}がついているものの、名前がありません。
普通こうしたカッコの場合 ifなどの条件分岐の命令や、クラスやメソッドを括っているのですが、この場合は名前の無いメソッドとして扱っています。
名前が無いと処理をそのまま普通に進めます。
その処理とは、上記の分岐を見ていくと分かると思いますが、

tabsizeが〜(2,4,6,8)なら →それぞれ指定のラジオボタンを選択状態にせよ

というものです。
その後、ダイアログボックスを表示するようにしています。

2.[中止]やウィンドウの[閉じる]ボタンを有効にする。

TabDialogクラスのダイアログのみがこの2つのボタンが有効ではなく、使用するとOKボタンを押した時と同様にタブサイズが設定されてしまっていました。
これを変更する為に、

int retを設定

retにJOptionPane.showConfirmDialog()の変数を設定
(このメソッドは整数値を返すようです)

もし、retがOK_OPTIONの値でないならば…

そのまま処理を中止し、ダイアログから抜ける

という処理を追加しています。
これらの処理を追加する事により、ダイアログの機能を完全なものにしています。

[前の話へ] [トップページ] [Java Software トップページ] [次の話へ]