ラベル Swing の投稿を表示しています。 すべての投稿を表示
ラベル Swing の投稿を表示しています。 すべての投稿を表示

2012年2月25日土曜日

JSpinnerの表示文字列を中央寄せに

JSpinnerといえば

どうも、プログラマのyu1rowです。
以前「JSpinnerのちょっと困った話」っていう小ネタのエントリを投稿しましたが、これが結構アクセス数多いんですね。
今回はその続きというか、派生の話題です。

要は「horizontalAlignment」が欲しいってだけ

JSpinnerにはhorizontalAlignmentがありませんでした。
でも欲しかったんで足しました。
今回はそれだけです。
需要、あるかなぁ?

JSpinnerにメソッドを付け足したクラスを作ります。
足された公開メソッドは以下の2つ。
  • void setHorizontalAlignment(int alignment)
  • int getHorizontalAlignment()
JSpinnerを継承したJAlignSpinnerクラスのコードを以下に示します。
package com.yu1row.blog;

import javax.swing.JFormattedTextField;
import javax.swing.JSpinner;

/**
 * Spinner implemented property horizontalAlignement.
 * @author yu1row
 */
public class JAlignSpinner extends JSpinner {

 private static final long serialVersionUID = 1L;

 private JFormattedTextField getTextField() {
  return (JFormattedTextField) getEditor().getComponents()[0];
 }

 public void setHorizontalAlignment(int alignment) {
  getTextField().setHorizontalAlignment(alignment);
 }

 public int getHorizontalAlignment() {
  return getTextField().getHorizontalAlignment();
 }
}


使い方

setHorizontalAlignmentの引数には以下を指定できます。
javax.swing.SwingConstants.LEFT左詰
javax.swing.SwingConstants.CENTER中央
javax.swing.SwingConstants.RIGHT右詰
javax.swing.SwingConstants.LEADING(日本語環境なら)左詰:デフォルト
javax.swing.SwingConstants.TRAILING(日本語環境なら)右詰

実際に使ってみたコード例を以下に示します。
import java.awt.Container;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.SwingConstants;

import com.yu1row.blog.JAlignSpinner;


public class ShowAlignSpinner {
 public static void main(String args[]) {
  JFrame frame = new JFrame();
  Container c = frame.getContentPane();

  c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS));
  JAlignSpinner spinner;

  // LEFT
  spinner = new JAlignSpinner();
  spinner.setHorizontalAlignment(SwingConstants.LEFT);
  c.add(spinner);
  // CENTER
  spinner = new JAlignSpinner();
  spinner.setHorizontalAlignment(SwingConstants.CENTER);
  c.add(spinner);
  // RIGHT
  spinner = new JAlignSpinner();
  spinner.setHorizontalAlignment(SwingConstants.RIGHT);
  c.add(spinner);
  // LEADING
  spinner = new JAlignSpinner();
  spinner.setHorizontalAlignment(SwingConstants.LEADING);
  c.add(spinner);
  // TRAILING
  spinner = new JAlignSpinner();
  spinner.setHorizontalAlignment(SwingConstants.TRAILING);
  c.add(spinner);

  frame.setSize(300, 200);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setVisible(true);  
 }
}

以上です!

2011年8月11日木曜日

JSpinnerのちょっと困った話

JSpinnerを使おうと思いまして


Java+Swingのお仕事が続く毎日、yu1rowです。
スピナーってありますよね。
「増やす」ボタンと「減らす」ボタンが付いてるテキストボックス、みたいな。
数値入力ができるモードで、ちょっと困ったんで、その話。

止まっちゃうんですが!?


50~200まで入力できて、「増やす」と「減らす」ボタンを押すと、25ずつ増えたり減ったりするスピナーを作りました。
「↑」とか「↓」のキーボード入力でも増やしたり減らしたりできます。

ところが。

キーボードからも入力できるんで、「199」とかも入力できるんですね。
でも、「199」の状態で「増やす」ボタンを押しても増えてくれないんですよ。
199+25=224なんで、上限の「200」を超えちゃうからなんでしょうけど…。
こっちとしては、「200」になって欲しいわけです。

反対に、「55」の状態から「減らす」ボタンを押しても同じです。
「50」になって欲しいなぁ…と。

結局どうしたのか?



 ボタンを押したときのイベントと、テキストボックスでキー入力したときのイベントを捕まえて対処しました。
JSpinnerの中には以下のものが入っています
  • JButton (2個)
  • SpinnerModel (1個)
さらに、SpinnerModelの中には以下のものが入っています
  • JFormattedTextField (1個))
この2個のJButtonと1個のJFormattedTextFieldのイベントを捕まえちゃいます。
2個のJButtonにはそれぞれ以下の名前がついています
  • 「Spinner.nextButton」
  • 「Spinner.previousButton」
フレームに"spinner"という名前のJSpinnerがあるとする場合、以下のコードで2個のボタンにイベントを登録できます。
※コード中の「setMinimumValue()」と「setMaximumValue()」というメソッドは後述

for (Component c : spinner.getComponents()) {
    if ("Spinner.nextButton".equals(c.getName())) {
        // 次ボタンのイベント登録
        ((JButton) c).addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setMinimumValue();
            }
        });
    } else if ("Spinner.previousButton".equals(c.getName())) {
        // 前ボタンのイベント登録
        ((JButton) c).addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setMaximumValue();
            }
        });
    }
}

イベントから呼び出す「setMinimumValue()」と「setMaximumValue()」、そこから使用される「isSpinnerNumberModel()」は以下のように記述します。

/**
 * スピナーのモデルが {@link SpinnerNumberModel} かどうかを取得します。
 * @return スピナーのモデルが {@code SpinnerNumberModel} の場合 {@code true} 、
 * そうでない場合 {@code false}
 */
private boolean isSpinnerNumberModel() {
    SpinnerModel model = spinner.getModel();
    // modelがnull
    if (model == null) { return false; }
    // 数値モデル以外
    if (model instanceof SpinnerNumberModel == false) { return false; }
    return true;
}

/**
 * 最大値を設定します。
 * <p>
 * このメソッドは以下のどれかの条件に当てはまる場合は何も行いません。
 * <ul>
 * <li>スピナーのモデルが {@link SpinnerNumberModel} ではない</li>
 * <li>既に最大値がセットされている</li>
 * <li>次にセットすべき値 ({@link JSpinner#getNextValue()}) が {@code null} ではない</li>
 * </ul>
 * 以上の条件以外の場合、最大値 ({@link SpinnerNumberModel#getMaximum()}) が設定されます。
 * </p>
 */
private void setMinimumValue() {
    if (!isSpinnerNumberModel()) { return; }
    // SpinnerNumberModelにキャスト
    SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel();
    // 既にMaximumであれば無視
    if (model.getValue().equals(model.getMaximum())) { return; }
    // 次にセットするべき値がある場合は無視
    if (spinner.getNextValue() != null) { return; }
    // 最大値をセット
    if (model.getMaximum() != null) { model.setValue(model.getMaximum()); }
}

/**
 * 最小値を設定します。
 * <p>
 * このメソッドは以下のどれかの条件に当てはまる場合は何も行いません。
 * <ul>
 * <li>スピナーのモデルが {@link SpinnerNumberModel} ではない</li>
 * <li>既に最小値がセットされている</li>
 * <li>次にセットすべき値 ({@link JSpinner#getPreviousValue()}) が {@code null} ではない</li>
 * </ul>
 * 以上の条件以外の場合、最小値 ({@link SpinnerNumberModel#getMinimum()}) が設定されます。
 * </p>
 */
private void setMaximumValue() {
    if (!isSpinnerNumberModel()) { return; }
    // SpinnerNumberModelにキャスト
    SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel();
    // 既にMinimumであれば無視
    if (model.getValue().equals(model.getMinimum())) { return; }
    // 次にセットするべき値がある場合は無視
    if (spinner.getPreviousValue() != null) { return; }
    // 最小値をセット
    if (model.getMinimum() != null) { model.setValue(model.getMinimum()); }
}

キーボードの「↑」と「↓」キーのイベントを捕まえて値を変更させる場合のイベントは、以下のように登録します。
※ここでも前述の「setMinimumValue()」、「setMaximumValue()」、「isSpinnerNumberModel()」というメソッドを使用しています

// SpinnerNumberModelでない場合はイベント登録しない
if (isSpinnerNumberModel()) {
    // JFormattedTextFieldを取得
    JFormattedTextField textField 
        = (JFormattedTextField) spinner.getEditor().getComponents()[0];
    // keyPressedイベントの登録
    textField.addKeyListener(new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    setMinimumValue();
                    break;
                case KeyEvent.VK_DOWN:
                    setMaximumValue();
                    break;
            }
        }
    });
}

一応、これで目的の動作をしているようです。
※ご使用に際しては、自己の責任と計画を以てお願いします

これでよかったんかいな?


上記のようなモノを実装したカスタムしたコンポーネントを作って、今回はやり過ごしました。
ホンマはプロパティーひとつで出来ちゃうような、スマートなやり方があるのかもしれません。
今回はそれが見つけられなかったので、こんな強引なやり方で対処することになりました。
もっとスマートなやり方、募集中です。

2011年8月9日火曜日

JComponentのvisibleChanged?

色々忙しくて全く更新できていません


本業の方では仕事が変更になり、C#からJavaへ使用言語が変わりました。だからというわけでは...あるんですが、備忘録的にメモを残します。

Swingのお仕事


今回のお仕事では、Swingをメインに据えて作業していくことになりました。
そこで戸惑ったのが、C#ではVisibleプロパティを使って、ボタンなど、画面のモノの表示を消したり出したりしていました。
そしたら、Control.VisibleChangedなんてイベントが走りましてね、これを捕まえることができたんですが...

JavaのSwingコンポーネントでは?どうすんの?

何はともあれソースっす


結論から言うと、java.awt.event.ComponentListenerを追加すりゃなんとかなりました。
例えばボタンを作りましてね、そのVisibleを監視するのは以下のように

private void initComponents() {
    JButton button = new JButton("ボタンでっせ");
    button.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentShown(final ComponentEvent e) {
            buttonVisibleChange(true);
        }

        @Override
        public void componentHidden(final ComponentEvent e) {
            buttonVisibleChange(false);
        }
    });
    add(button);
}

private void buttonVisibleChange(boolean visible) {
    System.out.println(visible);
}

  • componentShown() が表示されるとき
  • componentHidden() が消えるとき

見たまんまですね(^ー^

とにかく、C#とはちょっと勝手が違って悪戦苦闘気味ですが、こんな備忘録が増えていくかもしれません。