Передача данных между JComponent и объектом моделиJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Передача данных между JComponent и объектом модели

Сообщение Anonymous »

Мне нужно обновлять данные класса модели с помощью компонентов пользовательского интерфейса, и в то же время компоненты пользовательского интерфейса обновляются с изменениями в объекте данных. С подробностями о том, что значительный объем данных зависит от других данных. e.a.: СУММА A и B. СУММА должна отображаться в пользовательском интерфейсе и храниться в классе модели.
В реальном случае у меня есть около 58 редактируемых полей, смешанных из текста и чисел. И вдвое меньше вычисляемых полей.
Повозившись, я нашел много решений. Моя проблема в том, что у меня нет опыта, чтобы решить или судить, какой путь лучше всего выбрать, если вообще есть. Двумя основными кандидатами являются:
  • Первый вариант — просто добавить прослушиватели документов во все редактируемые поля пользовательского интерфейса. При изменении они обновляют данные в модели и вызывают метод для обновления всех полей в пользовательском интерфейсе. Недостаток - по моему грубому мнению - в том, что у меня более 50 полей. Я не знаю, как его закодировать, не написав отдельный прослушиватель для каждого компонента пользовательского интерфейса. Это также может затруднить последующую обработку изменений в коде.
  • Создайте массив класса, который регистрирует каждый редактируемый или вычисляемый компонент пользовательского интерфейса. Класс зарегистрирует не только компонент пользовательского интерфейса, но и, используя отражение, метод, который будет вызываться для установки или получения информации из объекта модели. Список документов по-прежнему будет обрабатывать изменения, но теперь он может быть одинаковым для всех компонентов пользовательского интерфейса, поскольку массив может обрабатывать изменения. Хорошим моментом является то, что весь перевод между моделью и пользовательским интерфейсом может быть закодирован в одном классе. Недостаток — размышления, люди всегда советуют избегать этого.
Каков лучший или хороший способ справиться с ситуацией?
Код, который я использую для тестирования:
public class Comunication {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {

//Main Window
JFrame frame = new JFrame();
frame.setTitle("SumTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(500,200));
frame.setVisible(true);

//Main Panel
JPanel pane = new JPanel();
frame.setContentPane(pane);

//Component
JTextField valueA = new JTextField("VALUE A");
JTextField valueB = new JTextField("VALUE B");
JTextField valueSum = new JTextField("VALUE SUM");
pane.add(valueA);
pane.add(valueB);
pane.add(valueSum);
}
});
}
}

class Data {
private int a;
private int b;
private int sum;

public Data() {
a = 1;
b = 2;
Calculate();
}

public void Calculate() {
sum = a + b;
}

public int getA() { return a; }
public int getB() { return b; }
public int getSUM() { return sum; }
public void setA(int i) { a = i; }
public void setB(int i) { b = i; }
}


Часть 2:
Экспериментируя с информацией, предоставленной пользователями, я взял на себя смелость попробовать что-то еще.
Одним из решений было бы создание класса прослушивателя, связывающего представление и модель. Этот прослушиватель следует немного менять каждый раз, когда он добавляется в поле (представление). Это единственный найденный способ связать поле с методом в модели без использования отражения.
Итак, алгоритм обновлений таков: при изменении представление обновляет модель.
После этого: глобальный контроллер обновляет все представления новой информацией о модели.
Проблемы, которые я обнаружил, вероятно, из-за отсутствия опыт:
  • Поскольку все представления имеют прослушиватели изменений документа: когда глобальный контроллер обновляет все представления/поля, они снова вызывают прослушиватель. Обходной путь, который я нашел, заключался в добавлении «тихого» флага к прослушивателю.
  • Когда представление обновляет модель и вызывает глобальный контроллер для обновления всех других представлений, оно не может обновиться само. Я пока не нашел причину, думаю, может быть, это вызывает петлю. Обходной путь заключался в том, чтобы сообщить глобальному контроллеру, который его вызвал, и обновить все представления, кроме вызывающего.
Полный рабочий код с решением и обходными путями приведен ниже.
Мнения будут очень приветствоваться, я хочу сделать это правильно или лучше.
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class Comunication {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {

//Main Window
JFrame frame = new JFrame();
frame.setTitle("SumTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(500,200));
frame.setVisible(true);

//Main Panel
JPanel pane = new JPanel();
frame.setContentPane(pane);

//Data Model
DataModel model = new DataModel();
GlobalUpdateController viewUpdateController = new GlobalUpdateController();

//Component
JTextField valueA = new JTextField("");
JTextField valueB = new JTextField("");
JTextField valueSum = new JTextField("");
valueA.setPreferredSize(new Dimension(30, 20));
valueB.setPreferredSize(new Dimension(30, 20));
valueSum.setPreferredSize(new Dimension(30, 20));
pane.add(valueA);
pane.add(valueB);
pane.add(valueSum);

//Listeners
valueA.getDocument().addDocumentListener(new StealthListener(valueA , viewUpdateController) {

@Override
public void updateView() {
this.view.setText( Integer.toString( model.getA() ) );
}

@Override
public void updateModel() {
model.setA( Integer.parseInt( this.view.getText() ) );
}

});

valueB.getDocument().addDocumentListener(new StealthListener(valueB , viewUpdateController) {

@Override
public void updateView() {
this.view.setText( Integer.toString( model.getB() ) );
}

@Override
public void updateModel() {
model.setB( Integer.parseInt( this.view.getText() ) );
}

});

valueSum.getDocument().addDocumentListener(new StealthListener(valueSum , viewUpdateController) {

@Override
public void updateView() {
this.view.setText( Integer.toString( model.getSUM() ) );
}

@Override
public void updateModel() {
//Do nothing
}

});

//Initial Update
viewUpdateController.updateAllViews(null);

}
});
}
}

class DataModel {
private int a;
private int b;
private int sum;

public DataModel() {
a = 3;
b = 5;
Calculate();
}

public void Calculate() {
sum = a + b;
}

public int getA() { return a; }
public int getB() { return b; }
public int getSUM() { return sum; }

public void setA(int i) { a = i; Calculate(); }
public void setB(int i) { b = i; Calculate(); }
}

class StealthListener implements DocumentListener {

JTextField view;
GlobalUpdateController viewList;
private boolean silent;

public StealthListener(JTextField view, GlobalUpdateController viewList) {
this.view = view;
this.viewList = viewList;
this.silent = false;
this.viewList.add(this);
}

public void setSilent(boolean val) {
this.silent = val;
}

public void updateView() {
// Unique to each view, to be Overriden
}

public void updateModel() {
// Unique to each view, to be Overriden
}

public void update() {
//The silent flag is meant to avoid ListenerLoop when changing the document.
//When the silent is true is meant to listen to internal changes.
if(this.silent == false) {
updateModel();
this.viewList.updateAllViews(this);
}
}

@Override
public void insertUpdate(DocumentEvent e) {
update();
}

@Override
public void removeUpdate(DocumentEvent e) {
update();
}

@Override
public void changedUpdate(DocumentEvent e) {
update();
}
}

class GlobalUpdateController {
private ArrayList viewList;

public GlobalUpdateController() {
this.viewList = new ArrayList();
}

public void add(StealthListener control) {
this.viewList.add(control);
}

public void updateAllViews(StealthListener caller) {
for( StealthListener view : viewList) {
if( caller==null || view != caller ) {

view.setSilent(true);
view.updateView();
view.setSilent(false);
}
}
}
}
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»