1

完全な免責事項: 私は CS の学生です。この質問は、オブジェクト指向プログラミング用に最近割り当てられた Java プログラムに関連しています。コンソール関連の作業はいくつか行いましたが、GUI と Swing または Awt を使用したのはこれが初めてです。テキストを表示するウィンドウを作成するコードと、テキストをさまざまな色で回転させるボタンを作成するコードが与えられました。次に、代わりに色のラジオ ボタンを作成するようにプログラムを変更するように依頼されました。これは、API を調査する練習を行うことも目的としていました。私はすでに課題を提出しており、講師からコードをここに投稿する許可を得ています。

Javaでボタンアクションを実装する最良の方法は何ですか? いろいろいじった後、次のようなボタンを作成しました。

class HelloComponent3 extends JComponent
    implements MouseMotionListener, ActionListener
{
    int messageX = 75, messageY= 175;

    String theMessage;
    String redString = "red", blueString = "blue", greenString = "green";
    String magentaString = "magenta", blackString = "black", resetString = "reset";

    JButton resetButton;
    JRadioButton redButton, blueButton, greenButton, magentaButton, blackButton;
    ButtonGroup colorButtons;

    public HelloComponent3(String message) {

    theMessage = message;

    //intialize the reset button
    resetButton = new JButton("Reset");
    resetButton.setActionCommand(resetString);
    resetButton.addActionListener(this);

    //intialize our radio buttons with actions and labels
    redButton = new JRadioButton("Red");
    redButton.setActionCommand(redString);
    ...

そして、アクションリスナーを追加しました...

redButton.addActionListener(this);
blueButton.addActionListener(this);
...

actionPerformed メソッドのスタブは、使用方法を示すために既に作成されていますが、テンプレートにはボタンが 1 つしかないため、複数のボタンを実装する方法が明確ではありませんでした。String をオンにしてみましたが、String はプリミティブ型ではないため、switch ステートメントには使用できないことにすぐに気付きました。if-else チェーンを即興で作成することもできましたが、代わりに思いついたのがこれです。エレガントとはほど遠いように思えますが、もっと良い方法があるはずです。あるとすれば、それは何ですか?文字列をオンにする方法はありますか? それとも、よりスケーラブルな方法でアクションを選択しますか?

public void actionPerformed(ActionEvent e){

    if (e.getActionCommand().equals(resetString)) {
        messageX = 75; messageY = 175;
        setForeground(Color.black);
        blackButton.setSelected(true);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(redString) ) {
        setForeground(Color.red);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(blueString) ) {
        setForeground(Color.blue);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(greenString) ) {
        setForeground(Color.green);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(magentaString) ) {
        setForeground(Color.magenta);
        repaint();
        return;
    }

    if ( e.getActionCommand().equals(blackString) ) {
        setForeground(Color.black);
        repaint();
        return;
    }
}
4

5 に答える 5

1

これを書く代わりに:

resetButton.addActionListener(this);

これを書くこともできます:

resetButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        resetButtonActionPerformed(evt);
    }
});

そして、すべてのアクションに対して1つの大きなactionPerformed()を作成する代わりに、次のように作成できます(そして作成する必要があります)。

public void resetButtonActionPerformed(ActionEvent evt) {
    messageX = 75; messageY = 175;
    setForeground(Color.black);
    blackButton.setSelected(true);
    repaint();
}

これが最も洗練されたソリューションであるかどうかはわかりませんが、少なくとも、if構造ではそれほど大きなものはありません。

于 2008-10-08T19:08:01.580 に答える
0

2つの代替アプローチ:

  1. Actionインターフェースを実装し、Colorフィールドと色を設定するactionPerformedメソッドを持つ新しいクラスを作成します
  2. コマンド名からColorインスタンスへのHashMapを管理し、マップでコマンド名を検索します
于 2008-10-08T19:13:02.913 に答える
0

適切なアプローチの 1 つは、要素が文字列に一致する列挙型を宣言し、 valueOf(str) をオンにすることです (リンクされた例は、かなりの安全性でこれを行う方法を示しています)。

匿名の内部クラスを避ける理由は、それが最善の解決策かもしれませんが、おそらくクラスにその構造が (まだ) ないためです。

于 2008-10-08T19:19:39.483 に答える
0

すでに提案したように、匿名内部クラスを使用して ActionListener インターフェースを実装できます。別の方法として、匿名の内部クラスを使用する必要はありませんが、代わりに単純なネストされたクラスを使用できます。

resetButton = new JButton(new ResetAction());
redButton = new JButton(new ColorAction("Red", Color.red));

その後...

private class ResetAction extends AbstractAction {
    public ResetAction() {
        super("Reset");
    }

    public void actionPerformed(ActionEvent e) {
        messageX = 75; messageY = 175;
        setForeground(Color.black);
        blackButton.setSelected(true);
        repaint();
    }
}

private class ResetAction extends AbstractAction {
    private Color color;

    public ColorAction(String title, Color color) {
        super(title);
        this.color = color;
    }

    public void actionPerformed(ActionEvent e) {
        setForeground(color);
        repaint();
    }
}

このアプローチ (または内部クラスを含む任意のアプローチ) が、外部クラスに ActionListener を実装するよりも優れている理由については、「デザイン パターン」を参照してください。

「『クラス継承』よりも『オブジェクト合成』を優先する。」(ギャング・オブ・フォー 1995:20)

匿名の内部クラスとこれらの名前付きの内部クラスのどちらを選択するかは、主にスタイルの問題ですが、このバージョンの方が理解しやすく、多くのアクションがある場合に明確になると思います。

于 2008-10-09T23:38:08.773 に答える
-1

うーん。1 つのメガ クラスに大量の無関係なインターフェイスを実装しないでください。代わりに、無名の内部クラスを使用してください。それらは少し冗長ですが、必要なものです。イベントごとに 1 つ使用すると、大きな if-else チェーンは必要ありません。イベントをデコードし、ターゲット オブジェクトにとって意味のあるメソッドを呼び出すために、内部クラス内に十分なコードを保持することをお勧めします。さらに、内部クラスをパラメーター化できます。おそらく、実際のウィジェットへの参照を保持する必要がないことに気付くでしょう。

あなたの例では、JComponent を JPanel として使用しているようです。大きな違いはありませんが、JPanel を使用してウィジェットのブロックを収集します。さらに、サブクラス化する必要はほとんどないので、そうしないでください。

たとえば、次のようになります。

   addColorButton("Green" , Color.GREEN );
   addColorButton("Red"   , Color.RED   );
   addColorButton("Yellow", Color.YELLOW);
   addColorButton("Blue"  , Color.BLUE  );
   ...

private void addColorButton(String label, Color color) {
    JRadioButton button = new JRadioButton(label);
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
            target.setForeground(color);
            target.repaint();
        } 
    });
    colorGroup.add(button);
    panel.add(button);
}
于 2008-10-08T19:18:18.690 に答える