SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine(コードジン) DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Swing再入門

Swing再入門 レンダラーとモデル

第3回 画面表示やデータ管理をカスタマイズする

レンダラー処理の流れ

 このSampleAppでは、JListを1つ作成し、JFrameに組み込んで表示させています。このJListに組み込んでいるレンダラーがColorRendererクラスです。また色の値にColorを使用すると表示テキスト(toStringされる値)が少々長くなるので、ColorをextendsしたMyColorを用意し、これを使って値を用意することにしました。

 getListCellRendererComponentメソッドで行っていることを見てみましょう。ここでは、new JLabelでJLabelのインスタンスを作成した後、この表示を必要に応じて変更しreturnする、という処理を行っています。引数で渡されたObjectColorにキャストし、そのインスタンスを元に表示色を設定しています。

Color c = (Color)object;
label.setText(c.toString());
label.setOpaque(true);

label.setFont(new Font("Serif",Font.BOLD,16));
label.setBackground(c);

 setOpaqueでJLabelを不透明にし、setBackgroundすれば指定の色でコンポーネントが表示されます。MyColorではなくColorにキャストしているのは、通常のColorでも問題なく表示できるようにしておくためです。その後、引数のisSelectedを使い、セルが選択されているかどうかによってsetForegroundの値を変更しておきます。

if (isSelected){
    label.setForeground(c);
} else {
    label.setForeground(n > 384 ? Color.BLACK : Color.WHITE);
}

 こうすることで、選択されたときとされていないときの表示を変更するようにしてあるわけです。この他、hasFocusを使って、このセルにフォーカスがあるかどうかによって表示を変更することもできます(ここでは省略してあります)。

 このColorListRendererは、次のようにしてJListに設定されています。たったこれだけで、JListのセルの表示をがらりと変えてしまうことができるのです。

list.setCellRenderer(new ColorRenderer());

もっと複雑なセル描画をさせたい

 ここではJLabelを使って表示をさせましたが、もっと複雑な描画を行わせたいような場合にはどうすればよいのでしょう。先の例では、JLabelを使ってセルの表示を行いました。しかし、レンダラーで作成する表示はComponentであればいいのですから、例えばJPanelなどを使い、コンポーネント内で細かな描画を行わせるようにすれば、より柔軟な表示を行えるようになるはずです。

 では、先ほどのColorRendererを修正して、もう少し細かな表示を行うようにしてみましょう。今度はJPanelを継承してクラスを定義してみます。

class ColorRenderer extends JPanel implements ListCellRenderer {
    private int index;
    private boolean isSelected,hasFocus;
    private MyColor object;
    
    @Override
    public Component getListCellRendererComponent(JList list,
            Object object, int index, boolean isSelected,
            boolean hasFocus) {
        this.index = index;
        this.isSelected = isSelected;
        this.hasFocus = hasFocus;
        try {
            this.object = (MyColor)object;
        } catch (ClassCastException e) {
            this.object = null;
        }
        this.setPreferredSize(new Dimension(100,20));
        return this;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (isSelected){
            g.setColor(object.darker());
        } else {
            g.setColor(object);
        }
        g.fillRect(0,0,this.getWidth(),this.getHeight());
        if (hasFocus){
            g.setColor(object.brighter());
            g.drawRect(0,0,this.getWidth() - 1,this.getHeight() - 1);
            g.drawRect(2,2,this.getWidth() - 5,this.getHeight() - 5);
        }
        if (isSelected){
            g.setColor(object.brighter());
            g.fillOval(4,4,this.getHeight() - 9,this.getHeight() - 9);
            g.fillOval(this.getWidth() - (this.getHeight() - 4),4,
                    this.getHeight() - 9,this.getHeight() - 9);
            g.setFont(new Font("Serif",Font.PLAIN,13));
            g.drawString(object.toString(),20,this.getHeight() - 7);
        }
    }
    
}
選択した項目には両端に●とRGB値が表示される。
選択した項目には両端に●とRGB値が表示される。

 ここでは、選択されたセルには、両端に●マーク、内部にRGBの値が表示されるようになります。またフォーカスがあるセルには二重の輪郭線が表示されます。「複雑な表示」という割にはシンプルですが、まぁ描画を使ったサンプルということで。

 ここでは、getListCellRendererComponentで新たにコンポーネントなどは作成しません。単に、thisを返しているだけです。今回は、このクラス自身がJPanelですから、新たにコンポーネントを用意して返す必要はないのです。そして、引数に渡された値をそれぞれprivateフィールドに保存しておきます。

 実際の描画は、paintComponentで行っています。AWTで使っていたおなじみのpaintメソッドも使えますが、Swingですからこちらを利用するのが良いでしょう(描画の仕組みについては本記事とは直接関係ないので割愛します)。ここで、isSelectedhasFocusの値ごとに描画する図形を変えています。コンポーネントをextendsする形でレンダラーを定義すれば、こうした直接描画による表示の操作が可能になるのです。

 なお、ここでは描画にColorbrighter/darkerメソッドを利用していますが、Colorの値によってはこれらはうまく機能しないことがあります(例えば、Color.WHITEbrighterでさらに明るくしようとすると失敗します)。ここではサンプルということで特にそのあたりの処理はしていませんので注意してください。

データ管理をするモデルについて

 JListでは、多くの値を使ってセルが作成されていきます。この値は、どこでどうやって管理されているのでしょうか。

 データの管理を行っているのが「モデル」と呼ばれるクラスです。これもコンポーネントの種類に応じてさまざまなものが用意されています。モデルは、データの保管だけでなく、その構造の管理なども行います。JListなどは単に一覧で表示するだけですが、コンポーネントによってはデータが構造を持っている場合もあります。こうした管理もモデルの仕事なのです。

 JListの場合、モデルはjavax.swing.ListModelインターフェイスを実装したクラスとして定義されます。標準でこれを実装済みのDefaultListModelクラスが用意されており、モデルの作成にはこれを利用するのが最も簡単でしょう。

 DefaultListModelは、内部的にVectorを使ってオブジェクトを管理しており、それらを扱うためのメソッドが用意されています。それらをオーバーライドすることでモデルの機能をカスタマイズすることができます。

 JListを実際に使ったことがあるなら、標準で表示するデータを追加・削除する機能がないことに気づいたはずです。一応、newする際に配列を渡すことで表示するデータを設定できますが、「これ、どうやってデータを操作するんだろう?」疑問に思った人は多いことでしょう。これも、DefaultListModelを利用することで解決します。すなわち、モデルをJListに設定し、そのモデルに対してデータを追加・削除していけばいいのです。

 では、先ほどのサンプルで、DefaultListModelを使った形にJListを修正してみましょう。JListを作成しているcreateListメソッドを、次のように修正してみてください。

public JList createList(){
    MyColor[] array = {
            new MyColor(255,255,255),
            new MyColor(255,0,0),
            new MyColor(0,255,0),
            new MyColor(0,0,255),
            new MyColor(255,255,0),
            new MyColor(0,255,255),
            new MyColor(255,0,255),
            new MyColor(0,0,0)};
    JList list = new JList();
    list.setCellRenderer(new ColorRenderer());
    // DefaultListModelの作成
    DefaultListModel model = new DefaultListModel();
    // モデルの設定
    list.setModel(model);
    for(MyColor c:array)
        model.addElement(c);
    return list;
}

 ここでは、DefaultListModelを作成し、setModelでモデルに設定しています。そして、このモデルに対してaddElementMyColorを追加しています。このように、モデルを利用することでJListの表示リストを自由に扱えるようになります。

次のページ
独自モデルの追加

この記事は参考になりましたか?

Swing再入門連載記事一覧

もっと読む

この記事の著者

掌田 津耶乃(ショウダ ツヤノ)

三文ライター&三流プログラマ。主にビギナーに向けたプログラミング関連の執筆を中心に活動している。※現在、入門ドキュメントサイト「libro」、カード型学習サイト「CARD.tuyano.com」を公開...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1674 2007/09/24 14:00

おすすめ

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー