0

我正在编写一个简单的 UI 只是为了掌握事情的窍门。我有一个带有两个选项卡的选项卡式窗口,一个有一个计数整数的按钮,另一个有一个显示所述整数内容的文本字段。或者至少这是计划。

如果我把所有东西都塞进一个班级,一切都会很好。我可以从我的 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);
    }
}

现在,如果所有这些都在一个类中(加上子类),我可以从 Tab2 访问 tfCount 并执行 tfCount.setText(content.getCounter());。但是,现在 tfCount 位于不同的类中,我无法访问它,除非我将 Tab1 的实例移交给 Tab2(如 tabs.addTab("Two", new Tab2(content, Tab1);)。我不能而是让 Tab1 在打开时重新绘制自身,例如在 Tab1 打开时执行 tfCount.setText(content.getCounter()) 的方法,或者类似的东西?如果是这样,我该怎么做?

4

1 回答 1

3

以这种方式分离控件后,您可以选择视图...

你可以...

与每个其他选项卡共享每个“选项卡”的实例,允许它们访问其他控件或相互附加侦听器。这是非常紧密的耦合和混乱的。

另一个问题是,按钮真的关心文本字段还是反之亦然......

你可以...

创建一个包含当前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>这将允许您定义可以包含Integer、和的模型Double,但我将把它留给您。FloatLong

每个选项卡视图都需要一个setModel(NumberModel)方法,因此您可以将模型传递给它。在这些方法中,您将为模型和get当前值附加一个侦听器,以便模型和视图同步。

于 2013-05-07T19:57:13.610 回答