多くの情報を切り替えて参照/操作するとき,タブはとても便利です。最近,Internet Explorer 7(IE 7)がタブを用いたGUIを採用したため,ほとんどのブラウザがタブ対応になりました。

このようにタブを用いたGUIはよく使われています。JavaでもJTabbedPaneクラスを使用すれば,タブを用いたGUIを作成できます。

しかし,何かが足りません。

FirefoxでもIE 7でもいいので,タブのところを観察してみてください(図1)。

firefox
ie7
図1 クローズ・ボタンのあるタブ

そう,クローズ・ボタンが付いているのです。Eclipseが採用しているSWTだとタブにボタンを付けることができるのですが,従来のSwingでは無理でした。

ここで,Java SE 6の登場です。Java SE 6ではJTabbedPaneクラスのタブにSwingのコンポーネントを貼ることができるようになったのです。これを利用すれば,タブのクローズ・ボタンを実現できます。

まずは簡単なサンプルで,タブにコンポーネントを貼ってみましょう。

サンプルのソースコード TabbedPaneSample1.java

10個のタブを生成し,そこにJLabelオブジェクトを貼るサンプルです。

pane = new JTabbedPane();

for (int i = 0; i < 10; i++) {
    JLabel label = new JLabel("Tab " + i);
    pane.addTab(null, label);

    // タブに貼るコンポーネントを生成
    JLabel tabLabel
        = new JLabel("tab " + i,
                     new ImageIcon("T"+(i+1)+".gif"),
                     JLabel.LEADING);

    // タブに貼るコンポーネントを設定
    pane.setTabComponentAt(i, tabLabel);
}

今までのJTabbedPaneクラスの使い方では,addTabメソッドの第1引数にタブに表示する文字列を指定していました。しかし,タブにコンポーネントを貼るときには,第1引数をnullにしておきます。

次に,setTabComponentAtメソッドを使用して,タブに貼るコンポーネントを設定します。第1引数がタブのインデックス,第2引数がタブに貼るコンポーネントです。

addTabメソッドでタブに表示する文字列もしくはアイコンを指定していたとしても,setTabComponentAtメソッドで設定したコンポーネントが優先されます。

このサンプルを実行した結果が図2です。

ここではJLabelクラスを使いましたが,Swingのコンポーネントであれば何でも貼ることができます。とはいっても,JTableクラスやJTreeクラスを貼るのはほとんど意味がありませんが。

タブにラベルを貼る
図2 タブにラベルを貼る

では,クローズ・ボタンのあるタブのサンプルを作ってみましょう。

サンプルのソースコード TabbedPaneSample2.java

タブに貼るのはJPanelオブジェクトで,そこにラベルとクローズ・ボタンを配置します。

ボタンといっても,ここではJLabelクラスを使用しています。JButtonクラスでもイメージを使用できるのですが,イメージのサイズに比べてボタンのサイズが大きくなってしまいます。もちろん,setPreferredSizeメソッドでサイズを調整すればいいのですが,少し面倒です。そこで,マウス・イベントが扱えてサイズの調整が不要なJLabelクラスをここでは使用しました。

// ラベルとボタンを貼るパネル
JPanel panel = new JPanel();
panel.setOpaque(false);
panel.setLayout(new BorderLayout(5, 5));

// ラベルの生成
// アイコンはデフォルトで用意されているものを使用
JLabel label = new JLabel(title,
                    UIManager.getIcon("FileView.fileIcon"),
                    JLabel.LEFT);
panel.add(label, BorderLayout.CENTER);

// タブのクローズを行うボタン
// マウスイベントが使用できればいいので,
// ここではラベルを使用
ImageIcon icon = new ImageIcon("close.gif");
JLabel closeLabel = new JLabel(icon);
panel.add(closeLabel, BorderLayout.EAST);

// タブにパネルを設定
pane.setTabComponentAt(index, panel);

ラベルは,Swingで標準的に使用できるアイコンを使用しました。UIManagerクラスのgetIconメソッドを使えば,標準で提供されているアイコンを取得できます。

FileView.fileIconはファイルを表すときに使われるアイコンであり,白い四角形の右上が少し折れたイメージになっています。

このアイコン以外にも,ディレクトリを表すFileView.directoryIconなどを使用できます。

クローズ・ボタンには赤の×印のイメージを用意しました。これをパネルの右側に配置します。あとは最後の行で,このパネルをタブに設定しています。

さて,肝心なのはクローズ・ボタンをクリックされたときのイベント処理です。

// クローズ・ボタンが押されたときの処理
closeLabel.addMouseListener(new MouseAdapter() {
    public void mousePressed(MouseEvent event) {
        // ボタンが押されたタブを選択
        Component tabComp
            = ((Component)event.getSource()).getParent();
        int index = pane.indexOfTabComponent(tabComp);

        // タブを削除
        pane.remove(index);
    }
});

クローズ・ボタンはイベントのgetSourceメソッドで得られるので,クローズ・ボタンが貼られているパネルは,getParentメソッドで取得できます。

タブに貼られたコンポーネントのインデックスを取得するにはJTabbedPaneクラスのindexOfTabComponentメソッドを使用します。インデックスが取得できれば,そのインデックスのタブを削除します。

実行してクローズ・ボタンを押してみてください。ちゃんとタブが削除されるはずです(図3)。

クローズ・ボタン以外にも,タブにフォーカスされたらアイコンを変化させるなどの応用が可能です。また,タブに対するイベント処理が可能になったため,Eclipseなどのように,タブをダブルクリックしたら表示領域が大きくなるといった動作も実現できます。

アプリケーションのユーザビリティを高めるためにも,いろいろな応用を考えてみてはいかがでしょうか。

クローズ・ボタンつきのタブ
図3 クローズ・ボタンつきのタブ

著者紹介 櫻庭祐一

横河電機 ネットワーク開発センタ所属。Java in the Box 主筆

今月の櫻庭

この時期,気になるのは何といってもJavaOne。年に1回,Javaの最大のお祭りです。

今年は5月8日から11日。ゴールデンウィークの直後にサンフランシスコのモスコニセンターで開催されます。

今年はどんなサプライズが飛び出すのでしょうか。Java SE 7はどうなるのか,Java EE 6は。JRubyをはじめとするスクリプトも気になるところ。今から,ワクワクドキドキなのです。