【问题标题】:How to synchronize two view in Java Swing如何在 Java Swing 中同步两个视图
【发布时间】:2014-07-22 11:28:29
【问题描述】:

我正在尝试这样做:在我的 GUI 中,我有一个带有自定义模型的 JTable,而在 GUI 的其他部分,我有一个面板,我可以在其中绘制一些箭头。我想“同步这两个视图。假设我们的 JTable 中有 5 行,我将在箭头面板中绘制 5 个箭头。如果我对行数进行修改,我必须有相同的行数排。 所以我正在尝试使用设计模式观察者。

为了简单起见,我尝试在一个文件中提供一个可计算的示例: 我在我的第一个面板 (ButtonPanel) 中创建了 n 个按钮,并在第二个面板 (LabelButton) 中创建了 n 个标签。

问题是:如何用DP Observer同步标签个数和标签个数

import java.awt.Color;
import java.awt.GridLayout;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

interface Observer {
    public void update(Subject subject, int number);
}

interface Subject {
    public void addObserver(Observer observer);

    public void delObserver(Observer observer);

    public void notifyObservers();
}

class SynchronizeNumber implements Subject {
    private ArrayList<Observer> observers;

    private int numberSync;

    public SynchronizeNumber() {
        super();
        observers = new ArrayList<Observer>();

    }

    public SynchronizeNumber(int numberSync) {
        super();
        this.numberSync = numberSync;
        observers = new ArrayList<Observer>();

    }

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);

    }

    @Override
    public void delObserver(Observer observer) {
        observers.remove(observer);

    }

    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(this, this.numberSync);
        }
    }

    /**
     * @return the number
     */
    public int getNumberSync() {
        return numberSync;
    }

    /**
     * @param number
     *            the number to set
     */
    public void setNumberSync(int numberSync) {
        this.numberSync = numberSync;
        notifyObservers();
    }
}

class ButtonPanel extends JPanel implements Observer {

    private int numberButton;

    public ButtonPanel() {
        super();
    }

    public ButtonPanel(int numberButton) {
        this.numberButton = numberButton;
        for (int i = 1; i <= numberButton; i++)
            this.add(new JButton("" + i));
    }

    /**
     * @return the numberLabel
     */
    public int getNumberButton() {
        return numberButton;
    }

    /**
     * @param numberLabel
     *            the numberLabel to set
     */
    public void setNumberButton(int numberButton) {
        this.numberButton = numberButton;
    }

    @Override
    public void update(Subject subject, int number) {
        if (subject instanceof SynchronizeNumber) {
            SynchronizeNumber synchronizeNumber = (SynchronizeNumber) subject;
            numberButton = synchronizeNumber.getNumberSync();
            System.out.println("ButtonPanel, numberButton: " + numberButton);
        }
    }
}

class LabelPanel extends JPanel implements Observer {

    private int numberLabel;

    public LabelPanel() {
        super();
    }

    public LabelPanel(int numberLabel) {
        super();
        this.numberLabel = numberLabel;
        for (int i = 1; i <= numberLabel; i++)
            this.add(new JLabel("label numbe: " + i));
        this.setBorder(new LineBorder(Color.blue));
    }

    @Override
    public void update(Subject subject, int number) {
        if (subject instanceof SynchronizeNumber) {
            SynchronizeNumber synchronizeNumber = (SynchronizeNumber) subject;
            numberLabel = synchronizeNumber.getNumberSync();
            System.out.println("LabelPanel, numberLabel: " + numberLabel);
        }
    }

    /**
     * @return the numberLabel
     */
    public int getNumberLabel() {
        return numberLabel;
    }

    /**
     * @param numberLabel
     *            the numberLabel to set
     */
    public void setNumberLabel(int numberLabel) {
        this.numberLabel = numberLabel;
    }
}

public class Test {

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setLayout(new GridLayout(2, 1));

        // create an subject synchronizeNumber
        SynchronizeNumber synchronizeNumber = new SynchronizeNumber();

        // set number to 1
        synchronizeNumber.setNumberSync(1);

        //create observers buttonPanel and labelPanel 
        ButtonPanel buttonPanel = new ButtonPanel(synchronizeNumber.getNumberSync());
        LabelPanel labelPanel = new LabelPanel(synchronizeNumber.getNumberSync());

        // add buttonPanel and labelPanel as observers
        synchronizeNumber.addObserver(buttonPanel);
        synchronizeNumber.addObserver(labelPanel);

        // make a change manually
        synchronizeNumber.setNumberSync(4);
        f.add(buttonPanel);
        f.add(labelPanel);
        f.setSize(400, 400);
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }

}

编辑:我使用自己的 DP Observer 而不是来自 API,因为无法进行多次扩展

【问题讨论】:

  • “假设我们的 JTable 中有 5 行,我将在箭头面板中绘制 5 个箭头。” 绝对有必要使用观察者模式吗?这是任务还是要求?如果没有,那么每次从表模型中插入/删除一行时,实现TableModelListener 来更新面板会更容易。
  • 我使用观察者模式是因为我认为它是最好的解决方案。我有两个类,我希望这两个类之间有一个最小的依赖关系。
  • @dic19 不是监听者模式吗?

标签: java swing user-interface design-patterns observer-pattern


【解决方案1】:

我使用观察者模式是因为我认为它是最好的解决方案。

Swing 是一个事件驱动的 API,其行为与观察者模式非常相似,因为有事件和订阅者来监听这些事件。例如,JButton 组件在每次按下它时调度一个ActionEvent,并通知订阅的ActionListeners 发生了一些事情。

根据相同的原则,TableModel 负责在每次数据更改(添加/删除行、更新单元格等)时调度 TableModelEvent 并在此类事件中通知订阅的 TableModelListeners。

你可以利用这个事实来实现你的主要目标:

假设我们的 JTable 中有 5 行,我将在其中绘制 5 个箭头 箭头面板。

  1. 创建一个JPanel,它可以随心所欲地绘制许多箭头。请参阅Performing Custom Painting 课程。
  2. TableModelListener 附加到您的TableModel 以便在插入/删除行时重新绘制您的JPanel

我有两个类,我希望两者之间有一个最小的依赖关系 类。

如果你按照我的建议,你应该能够像这样创建一个独立且可重复使用的JPanel

class MyCustomPanel extends JPanel {

    private int numberOfArrows = 0;

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g); // never forget to call super.paintComponent(g)
        Graphics graphics = g.create();
        int y = 10;
        for(int i = 0; i < numberOfArrows; i++) {                
            graphics.drawLine(10, y, getWidth() - 10, y); // instead of lines just draw your arrows
            y += 10;
        }
        graphics.dispose();
    }

    /**
     * Public method to set the number of arrows that has to be drawn.
     * @param arrows 
     */
    public void setNumberOfArrows(int arrows) {
        numberOfArrows = arrows;
        repaint();
    }

    @Override
    public Dimension getPreferredSize() {
        return isPreferredSizeSet() 
             ? super.getPreferredSize() : new Dimension(200,200);
    }
}

这样,您的面板可以独立地从外部获取箭头的数量(可以是表格模型中的行数、列表中的元素数、固定值,无论您想要什么)。

【讨论】:

  • 感谢您的解释!!
【解决方案2】:

我已经完全按照你的意愿实现了:

import java.awt.Color;
import java.awt.GridLayout;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

interface Observer {
    public void update(Subject subject, int number);
}

interface Subject {
    public void addObserver(Observer observer);

    public void delObserver(Observer observer);

    public void notifyObservers();
}

class SynchronizeNumber implements Subject {
    private ArrayList<Observer> observers;

    private int numberSync;

    public SynchronizeNumber() {
        super();
        observers = new ArrayList<Observer>();

    }

    public SynchronizeNumber(int numberSync) {
        super();
        this.numberSync = numberSync;
        observers = new ArrayList<Observer>();

    }

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);

    }

    @Override
    public void delObserver(Observer observer) {
        observers.remove(observer);

    }

    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(this, this.numberSync);
        }
    }

    /**
     * @return the number
     */
    public int getNumberSync() {
        return numberSync;
    }

    /**
     * @param number
     *            the number to set
     */
    public void setNumberSync(int numberSync) {
        this.numberSync = numberSync;
        notifyObservers();
    }
}

class ButtonPanel extends JPanel implements Observer {

    private int numberButton;

    public ButtonPanel() {
        super();
    }

    public ButtonPanel(int numberButton) {
        this.numberButton = numberButton;
        for (int i = 0; i < numberButton; i++)
            this.add(createButton(i));
    }

    /**
     * @return the numberLabel
     */
    public int getNumberButton() {
        return numberButton;
    }

    /**
     * @param numberLabel
     *            the numberLabel to set
     */
    public void setNumberButton(int numberButton) {
        this.numberButton = numberButton;
    }

    @Override
    public void update(Subject subject, int number) {
        if (subject instanceof SynchronizeNumber) {
            SynchronizeNumber synchronizeNumber = (SynchronizeNumber) subject;
            int diff = numberButton + (number - numberButton);
            // if diff and numberButton are equal do nothing
            if (diff < numberButton) {
                for (int i = numberButton - 1; i >= diff; i--) {
                    this.remove(this.getComponent(i));
                }
            } else if (diff > numberButton) {
                for (int i = numberButton; i < diff; i++) {
                    this.add(createButton(i));
                }
            }
            numberButton = number;
            System.out.println("ButtonPanel, numberButton: " + numberButton);
        }
    }

    private JButton createButton(int i) {
        return new JButton("" + ++i);
    }
}

class LabelPanel extends JPanel implements Observer {

    private int numberLabel;

    public LabelPanel() {
        super();
    }

    public LabelPanel(int numberLabel) {
        super();
        this.numberLabel = numberLabel;
        for (int i = 0; i < numberLabel; i++)
            this.add(createLabel(i));
        this.setBorder(new LineBorder(Color.blue));
    }

    @Override
    public void update(Subject subject, int number) {
        if (subject instanceof SynchronizeNumber) {
            SynchronizeNumber synchronizeNumber = (SynchronizeNumber) subject;
            int diff = numberLabel + (number - numberLabel);
            // if diff and numberButton are equal do nothing
            if (diff < numberLabel) {
                for (int i = numberLabel - 1; i >= diff; i--) {
                    this.remove(this.getComponent(i));
                }
            } else if (diff > numberLabel) {
                for (int i = numberLabel; i < diff; i++) {
                    this.add(createLabel(i));
                }
            }
            numberLabel = number;
            System.out.println("LabelPanel, numberLabel: " + numberLabel);
        }
    }

    /**
     * @return the numberLabel
     */
    public int getNumberLabel() {
        return numberLabel;
    }

    /**
     * @param numberLabel
     *            the numberLabel to set
     */
    public void setNumberLabel(int numberLabel) {
        this.numberLabel = numberLabel;
    }

    private JLabel createLabel(int i) {
        return new JLabel("label name:" + ++i);
    }
}

public class Test {

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setLayout(new GridLayout(2, 1));

        // create an subject synchronizeNumber
        SynchronizeNumber synchronizeNumber = new SynchronizeNumber();

        // set number to 1
        synchronizeNumber.setNumberSync(1);

        // create observers buttonPanel and labelPanel
        ButtonPanel buttonPanel = new ButtonPanel(synchronizeNumber.getNumberSync());
        LabelPanel labelPanel = new LabelPanel(synchronizeNumber.getNumberSync());

        // add buttonPanel and labelPanel as observers
        synchronizeNumber.addObserver(buttonPanel);
        synchronizeNumber.addObserver(labelPanel);

        // make a change manually
        synchronizeNumber.setNumberSync(4);

        synchronizeNumber.setNumberSync(3);
        synchronizeNumber.setNumberSync(11);
        synchronizeNumber.setNumberSync(5);
        synchronizeNumber.setNumberSync(7);

        f.add(buttonPanel);
        f.add(labelPanel);
        f.setSize(400, 400);
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-27
    • 2017-09-06
    • 2018-12-03
    • 1970-01-01
    相关资源
    最近更新 更多