[英]How to synchronize two view in 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> 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,因為無法進行多次擴展
我使用Observer模式因為我認為它是最好的解決方案。
Swing是一個事件驅動的API,其行為非常類似於觀察者模式,因為有訂閱的事件和監聽器可以監聽這些事件。 例如, JButton組件每次按下時都會調度一個ActionEvent,並通知訂閱的ActionListener發生了某些事情。
使用相同的原則, 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); // 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);
}
}
通過這種方式,您的面板可以獨立地確定外部箭頭的數量(它可以是表模型中的行數,列表中的元素數,固定值,無論您想要的是什么)。
我已完全按照您的意願實現它:
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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.