0

コツをつかむためだけに簡単なUIを書いています。2 つのタブを持つタブ付きウィンドウがあります。1 つには整数をカウントアップするボタンがあり、もう 1 つには整数の内容を表示するテキスト フィールドがあります。または、少なくともそれが計画です。

すべてを 1 つのクラスに詰め込むと、すべてがうまく機能します。actionlistener からタブ 1 にアクセスし、タブ 2 のボタンを押してタブ 1 のテキスト フィールドを変更できます。

そして、ここで何をすべきかわかりません。Class Tab1 のテキストフィールドに、Class Tab2 でボタンを押したときに変更するように指示する必要があります。ここで何をするのが正しいですか?私が最初に考えたのは、Tab2 の作成時に Tab1 のインスタンスを渡すことだったので、tab1.changeText() を実行できました。しかし、相互にやり取りするタブが増えると、すぐに面倒になります。そこで、代わりに、最初のタブを開くたびにその内容を更新したいのですが、その方法がわかりません。また、それが正しいことなのかどうかもわかりません。だから、助けて!

ここにいくつかのコードがあります。「コンテンツ」はコンテンツのインスタンスであり、カウンターへの追加などのすべてのロジックを処理するクラスです。

メイン GUI クラス:

public class GUI extends JFrame {

  //Stuff..

  JTabbedPane tabs = new JTabbedPane();
  tabs.addTab("One", new Tab1(content));
  tabs.addTab("Two", new Tab2(content));

  //Stuff..

タブ 1:

public class Tab1 extends JPanel {

  public Tab1(Content content) {
    JPanel tab1 = new JPanel();
    //Stuff..
    JTextField tfCount = new JTextField(content.getCounter(), 10);
    tab1.add(tfCount);

    this.add(tab1);

    //Stuff..

タブ 2:

public class Tab2 extends JPanel {

  public Tab2(Content content) {
    JPanel tab2 = new JPanel();
    //Stuff..

    JButton btnCount2 = new JButton("Count");
    btnCount2.addActionListener(new TestListener(this.content));

    tab2.add(btnCount2);
    this.add(tab2);
  }

  private class TestListener implements ActionListener {

    Content content;

    public TestListener(Content content) {
        this.content = content;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        this.content.addToCounter(1);
    }
}

これらすべてが 1 つのクラス (およびサブクラス) にある場合は、Tab2 から tfCount にアクセスして、tfCount.setText(content.getCounter()); を実行するだけで済みます。ただし、現在 tfCount は別のクラスにあり、Tab1 のインスタンスを Tab2 に渡さない限り (tabs.addTab("Two", new Tab2(content, Tab1); のように)) アクセスできません。代わりに、Tab1 が開かれるたびに Tab1 で tfCount.setText(content.getCounter()) を実行するメソッドを持つように、Tab1 が開かれるたびにそれ自体を再描画するか、またはそれらの行に沿って何かを取得しますか?もしそうなら、どうすればいいですか?

4

1 に答える 1

3

このようにコントロールを分離すると、ビューの選択肢があります...

あなたは出来る...

各「タブ」のインスタンスを他の各タブと共有して、他のコントロールにアクセスしたり、リスナーを相互に接続したりできるようにします。これは非常に緊密に結合され、乱雑です。

もう1つの問題は、ボタンがテキストフィールドを本当に気にするのか、それともその逆なのかということです...

あなたは出来る...

int現在の値を含み、その値を変更する手段を提供する単純なモデルを作成します。

モデルにはChangeEvent、値が変更されたときに (たとえば) を起動する機能があり、関係者はそれをリッスンし、それに応じて自分自身を更新できます。

これにより、コードが分離され、複雑さが軽減され、コードのさまざまな要素の柔軟性と再利用が大幅に向上します。

これは一般にオブザーバー パターンとして知られており、Swing で広く使用されています。

可能な(リスナー)例...

私にとって、私はいつもインターフェイスから始めます。これは、必要な目標を達成するために満たさなければならない絶対的な最小要件を説明しています。各タブは現在の値を知りたがり、次の値とモデルへの変更のリスナーを設定できるようになります...

public interface NumberModel {
    public int getValue();
    public void setValue(int value);

    public void addChangeListener(ChangeListener listener);
    public void removeChangeListener(ChangeListener listener);
}

実装は、より「一般的な」実装の詳細、具体的なabstract実装が実装する必要のないものを扱います。これは、すべての実装に十分に共通であるためです。この場合、それはリスナー管理になります...

public abstract class AbstractNumberModel implements NumberModel {

    private List<ChangeListener> listeners;

    public AbstractNumberModel() {
        listeners = new ArrayList<>(25);
    }

    @Override
    public void addChangeListener(ChangeListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeChangeListener(ChangeListener listener) {
        listeners.remove(listener);
    }

    protected ChangeListener[] getChangeListeners() {
        // FIFO...
        List<ChangeListener> copy = new ArrayList<>(listeners);
        Collections.reverse(copy);
        return copy.toArray(copy.toArray(new ChangeListener[listeners.size()]));
    }

    protected void fireStateChanged() {
        ChangeListener[] listeners = getChangeListeners();
        if (listeners != null && listeners.length > 0) {
            ChangeEvent evt = new ChangeEvent(this);
            for (ChangeListener listener : listeners) {
                listener.stateChanged(evt);
            }
        }
    }
}

そして最後に、実装固有の詳細を扱う具体的な実装...

public class DefaultNumberModel extends AbstractNumberModel {

    private int value;

    public DefaultNumberModel() {
    }

    public DefaultNumberModel(int value) {
        setValue(value);
    }

    @Override
    public int getValue() {
        return value;
    }

    @Override
    public void setValue(int num) {
        if (num != value) {
            value = num;
            fireStateChanged();
        }
    }

}

たとえば、 、、およびをpublic interface NumberModel<N extends Number>保持できるモデルを定義できるようにすることで、もう少し柔軟なモデルにすることができますが、それはあなたに任せます。IntegerDoubleFloatLong

各タブビューにはsetModel(NumberModel)メソッドが必要になるため、モデルに渡すことができます。getこれらのメソッドでは、モデルとビューが同期するように、リスナーをモデルと現在の値にアタッチします。

于 2013-05-07T19:57:13.610 に答える