如何在Java Swing中同步两个视图 [英] How to synchronize two view in Java Swing
问题描述
所以我试图使用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个箭头。
- 创建一个
JPanel
,可以根据需要绘制许多箭头。请参阅执行自定义绘画课程。 - 将
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.
- Create a
JPanel
with the ability to draw many arrows as you wish. See Performing Custom Painting lesson. - Attach a
TableModelListener
to yourTableModel
in order to repaint yourJPanel
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屋!