如何在Java Swing中同步两个视图 [英] How to synchronize two view in Java Swing

查看:142
本文介绍了如何在Java Swing中同步两个视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图这样做:在我的GUI中,我有一个JTable与一个自定义模型,在GUI的其他部分,我有一个面板,我画一些箭头。我想同步这两个视图,所以让我们说如果我的JTable中有5行,我将在箭头面板中画出5个箭头,如果我对行数进行修改,我必须有相同数量的行
所以我试图使用Design Pattern Observer。



为了简单起见,我尝试提供一个可在一个文件中计算的示例:
我在第一个Panel(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>观察员;

private int numberSync;

public SynchronizeNumber(){
super();
观察者= new ArrayList< Observer>();

}

public SynchronizeNumber(int numberSync){
super();
this.numberSync = numberSync;
观察者= 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.numberSync);
}
}

/ **
* @返回数字
* /
public int getNumberSync(){
返回numberSync;
}

/ **
* @param number
*要设置的数字
* /
public void setNumberSync(int numberSync) {
this.numberSync = numberSync;
notifyObservers();
}
}

class ButtonPanel扩展JPanel实现Observer {

private int numberButton;

public ButtonPanel(){
super();
}

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

}

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

/ **
* @param numberLabel
* numberLabel设置
* /
public void setNumberButton(int numberButton) {
this.numberButton = numberButton;
}

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

class LabelPanel扩展JPanel实现Observer {

private int numberLabel;

public LabelPanel(){
super();
}

public LabelPanel(int numberLabel){
super();
this.numberLabel = numberLabel; (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 ) 学科;
numberLabel = synchronizeNumber.getNumberSync();
System.out.println(LabelPanel,numberLabel:+ numberLabel);
}
}

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

/ **
* @param numberLabel
* numberLabel设置
* /
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));

//创建主题synchronizeNumber
SynchronizeNumber synchronizeNumber = new SynchronizeNumber();

//将数字设置为1
synchronizeNumber.setNumberSync(1);

//创建观察器buttonPanel和labelPanel
ButtonPanel buttonPanel = new ButtonPanel(synchronizeNumber.getNumberSync());
LabelPanel labelPanel = new LabelPanel(synchronizeNumber.getNumberSync());

//添加buttonPanel和labelPanel作为观察者
synchronizeNumber.addObserver(buttonPanel);
synchronizeNumber.addObserver(labelPanel);

//手动修改
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观察者而不是API,因为多个扩展是不可能的

解决方案


模式,因为我认为这是最好的解决方案。


Swing是一个事件驱动的API,几乎像Observer在有事件和听众订阅的意义上,模式听这些事件。例如 JButton 组件调度 ActionEvent ,每次按下并通知订阅 ActionListener 发生了什么事。 / p>

同样的原则,是 TableModel 来分派 TableModelEvent 每次数据被更改(行添加/删除,单元格更新等)并通知订阅 TableModelListener



您可以使用此事实来实现您的主要目标:


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





  1. 创建一个 JPanel ,可以根据需要绘制许多箭头。请参阅执行自定义绘画课程。

  2. TableModelListener 附加到您的 TableModel 中,以便重新绘制您的 JPanel 当行被插入/删除时。







我有两个课程,我想要两个
类之间的最小依赖关系。


如果您应该遵循我的建议,您应该可以创建一个独立且可重复使用的 JPanel ,如下所示:

  class MyCustomPanel extends JPanel {

private int numberOfArrows = 0;

@Override
public void paintComponent(Graphics g){
super.paintComponent(g); //永远不会忘记调用super.paintComponent(g)
图形图形= g.create();
int y = 10; (int i = 0; i< numberOfArrows; i ++){
graphics.drawLine(10,y,getWidth() - 10,y);
//而不是线绘制你的箭头
y + = 10;
}
graphics.dispose();
}

/ **
*设置必须绘制的箭头数量的公共方法。
* @param箭头
* /
public void setNumberOfArrows(int arrow){
numberOfArrows =箭头;
repaint();
}

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

这样你的面板可以从箭头的数量外部独立于如何确定(它可以是表模型中的行数,列表中的元素数量,固定值,无论您想要什么)。


I'm trying to do this: In my GUI, I have one JTable with a custom model, and in other part of the GUI, I have one panel where i draw some arrows. I want to "synchronize this two view. So let's say if we have 5 rows in my JTable, I will draw 5 arrows in the panel of arrows. If I make a modification in the number of row, I must have the same number of row. So I'm trying to use Design Pattern Observer.

To make simple, I try to provide an example computable in one file: I create n buttons in my first Panel (ButtonPanel) and I create n label in the second panel (LabelButton).

The problem is : How to synchronize the number of label withthe number of label with 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);
    }

}

edit: I use my own DP Observer and not from the API because multiple extending is not possible

解决方案

I use Observer pattern because I think it is the best solution.

Swing is an Event Driven API and acts pretty much like an Observer Pattern in the sense that there are events and listeners subscribed to listen those events. For instance JButton component dispatches an ActionEvent every time it is pressed and notifies to subscribed ActionListeners that something happened.

With the same principle, is responsibility of TableModel to dispatch a TableModelEvent every time data has been changed (rows added/deleted, cells updated, etc) and notify subscribed TableModelListeners in such events.

You can use this fact to accomplish your main goal:

So let's say if we have 5 rows in my JTable, I will draw 5 arrows in the panel of arrows.

  1. Create a JPanel with the ability to draw many arrows as you wish. See Performing Custom Painting lesson.
  2. Attach a TableModelListener to your TableModel in order to repaint your JPanel when rows are inserted/deleted.


I have two classes and I want a minimun dependency between the two classes.

If you follow my suggestions, you should be able to create an independent and reusable JPanel like this:

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);
    }
}

This way your panel can take the number of arrows from the outside independently on how it is determined (it could be number of rows in a table model, number of elements in a list, a fixed value, whatever you want).

这篇关于如何在Java Swing中同步两个视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆