Ik heb me al een tijdje lopen ergeren aan het mvc gebeuren van Swing, of eigelijk het gebrek aan allerlei support classes. Je hebt bv de PropertyChangeSupport en daarmee houd het wel op. Als je bv ook een voor List`s of Map ofzo wilt hebben dan zal je hem zelf moeten schrijven. Ik heb hier intussen al een aantal classes voor geschreven en zal binnenkort hier even nieuweren posten waar geen memory leaks meer in voor kunnen komen (memory leaks kunnen onstaan omdat views als listener is geregistreerd en zodoende schermen niet voor gc in aanmerking komen).
Ik neem aan dat jullie ook altijd de standaard 'controller' code maken voor bv een string veld.
Maar iedere keer dat event gebeuren, en dan die controllers nog een keer aansluiten op de gui, dat is altijd zo`n hoop dom werk. Het probleem zit hem in het feit dat de properties nog lang niet slim genoeg hebben gemaakt. Eigelijk zou iedere propertie zelf een propertychangeSupport moeten hebbem. Ik ben intussen uitgekomen op de volgende genieke objecten. (nog niet helemaal klaar).
dit is dan de persoon model:
en dit is de aansluiting in de gui:

Zoals je zit is het super simpel, omdat je totaal niet meer hoeft te denken om allerlei event afhandel zaken, dat gebeurt nu generiek. Ik ga hem nog generieker maken (auto support voor andere types, lijsten, map, sets etc) omdat je niet alleen met string wilt werken, maar dit is mijn idee. Wat vinden jullie hiervan?
Ik neem aan dat jullie ook altijd de standaard 'controller' code maken voor bv een string veld.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| public class Persoon{
public final static String VOORNAAM = "voornaam";
private String _voornaam;
private PropertyChangeSupport _pcs = new PropertyChangeSupport(this);
public Persoon(Strng voornaam){
setVoornaam(voornaam);
}
public void setVoornaam(String voornaam){
..null check
..trim+lengte check
String oldValue = _voornaam;
_voornaam = voornaam;
_pce.propertyChange(VOORNAAM,oldValue,_voornaam);
}
public void addPropListener(String property, PropertyChangeListener l){
_pcs.addListener(property,propertyChangeListener);
}
}
public VoornaamLabel extends JLabel{
public VoornaamLabel(Persoon persoon){
persoon.addListener(Persoon.VOORNAAM,new PropertyChangeListenerImpl());
setText(persoon.getVoornaam());
}
private class PropertyChangeListenerImpl implements PropertyChangeListener{
public void propertyChange(PropertyChangeEvent pce){
setText(pce.getNewValue());
}
}
}
public VoornaamTextField extends JTextField{
private Persoon _persoon;
public VoornaamTextField(Persoon persoon){
..null check
_persoon = persoon;
_persoon.addListener(Persoon.VOORNAAM,new PropertyChangeListenerImpl());
setText(persoon.getVoornaam());
addActionListener(new ActionListenerImpl());
}
private class PropertyChangeListenerImpl implements PropertyChangeListener{
public void propertyChange(PropertyChangeEvent pce){
setText(pce.getNewValue());
}
}
private class ActionListenerImpl implements ActionListener{
public void actionPerformed(ActionEvent e){
try{
_persoon.setVoornaam(getText());
}catch(IllegalArgumentException ex){
setText(_model.getValue());
JOptionPane.showMessageDialog(StringTextField.this,e.getMessage(),"", JOptionPane.ERROR_MESSAGE);
}
}
}
} |
Maar iedere keer dat event gebeuren, en dan die controllers nog een keer aansluiten op de gui, dat is altijd zo`n hoop dom werk. Het probleem zit hem in het feit dat de properties nog lang niet slim genoeg hebben gemaakt. Eigelijk zou iedere propertie zelf een propertychangeSupport moeten hebbem. Ik ben intussen uitgekomen op de volgende genieke objecten. (nog niet helemaal klaar).
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
| public class StringEvent extends EventObject{
private String _oldValue;
private String _newValue;
public StringEvent(Object source, String oldValue, String newValue){
super(source);
_oldValue = oldValue;
_newValue = newValue;
}
public String getNewValue(){
return _newValue;
}
public String getOldValue(){
return _oldValue;
}
}
public interface StringListener extends EventListener{
public void fire(StringEvent e);
}
public interface StringVetoListener extends EventListener{
public void validate(StringEvent stringEvent)throws IllegalArgumentException;
}
public class StringModel<T>{
private String _value;
private StringController _controller;
public StringModel(T source, String value){
_value = value;
_controller = new StringController(source);
}
public StringModel(T source){
_controller = new StringController(source);
}
public String getValue(){
return _value;
}
public synchronized void setValue(String newValue)throws IllegalArgumentException{
String oldValue = _value;
_controller.request(oldValue,newValue);
_value = newValue;
_controller.handleValueChange(oldValue,newValue);
}
public StringController getController(){
return _controller;
}
private class StringController{
private List<WeakReference<StringListener>> _listenerList = new LinkedList<WeakReference<StringListener>>();
private List<WeakReference<StringVetoListener>> _vetoList = new LinkedList<WeakReference<StringVetoListener>>();
private T _beanSource;
public StringController(T beanSource){
_beanSource = beanSource;
}
public void request(String oldValue, String newValue)throws IllegalArgumentException{
StringEvent stringEvent = new StringEvent(_beanSource,oldValue,newValue);
for(int k=0;k<_vetoList.size();k++){
StringVetoListener l = _vetoList.get(k).get();
if(l!=null){
l.validate(stringEvent);
}
}
}
public void handleValueChange(String oldValue, String newValue){
StringEvent stringEvent = new StringEvent(_beanSource,oldValue,newValue);
for(int k=0;k<_listenerList.size();k++){
StringListener l = _listenerList.get(k).get();
if(l!=null){
l.fire(stringEvent);
}
}
}
public void addListener(StringListener listener){
if(listener == null){
throw new NullPointerException("listener can`t be null");
}
int indexOf = indexOf(listener);
if(indexOf!=-1){
throw new IllegalArgumentException("listener:"+listener+" already is registered in StringController");
}
_listenerList.add(new WeakReference<StringListener>(listener));
}
public void addVetoListener(StringVetoListener listener){
if(listener == null){
throw new NullPointerException("listener can`t be null");
}
_vetoList.add(new WeakReference<StringVetoListener>(listener));
}
public synchronized void removeListener(StringListener listener){
if(listener == null){
throw new NullPointerException("stringListener can`t be null");
}
int indexOf = indexOf(listener);
if(indexOf == -1){
throw new IllegalArgumentException("listener:"+listener+" is not found in StringController");
}
_listenerList.remove(indexOf);
}
public synchronized void removeAllListeners(){
_listenerList.clear();
}
public boolean hasListeners(){
return _listenerList.size()>0;
}
private synchronized int indexOf(StringListener listener){
assert listener!=null:"listener can`t be null";
int index = 0;
int result = -1;
while(index<_listenerList.size()){
if(_listenerList.get(index).get() == listener){
result = index;
index = _listenerList.size();
}else{
index++;
}
}
return result;
}
private void removeDeadRefs(){
}
}
}
public class StringLabel extends JLabel{
private StringListener _stringListener = new StringListenerImpl();
public StringLabel(StringModel model){
if(model == null){
throw new NullPointerException("model can`t be null");
}
model.getController().addListener(_stringListener);
setText(model.getValue());
}
private class StringListenerImpl implements StringListener{
public void fire(StringEvent e){
if(e == null){
throw new NullPointerException("e can`t be null");
}
setText(e.getNewValue());
}
}
}
public class StringTextField extends JTextField{
private StringModel _model;
private StringListener _stringListenr = new StringListenerImpl();
public StringTextField(StringModel model){
if(model == null){
throw new NullPointerException("model can`t be null");
}
_model = model;
_model.getController().addListener(_stringListenr);
addActionListener(new ActionlistenerImpl());
setText(_model.getValue());
}
private final class StringListenerImpl implements StringListener{
public void fire(StringEvent e){
if(e == null){
throw new NullPointerException("e can`t be null");
}
setText(e.getNewValue());
}
}
private final class ActionlistenerImpl implements ActionListener{
public void actionPerformed(ActionEvent ae){
try{
_model.setValue(getText());
}catch(IllegalArgumentException e){
setText(_model.getValue());
JOptionPane.showMessageDialog(StringTextField.this,e.getMessage(),"", JOptionPane.ERROR_MESSAGE);
}
}
}
} |
dit is dan de persoon model:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
| public class Persoon{
private StringModel<Persoon> _voornaamM = new StringModel<Persoon>(this);
private StringVetoListener _voornaamVetoListener = new VoornaamVetoListener();
private StringModel<Persoon> _achternaamM = new StringModel<Persoon>(this);
private StringVetoListener _achternaamVetoListener = new AchternaamVetoListener();
private StringModel<Persoon> _woonplaatsM = new StringModel<Persoon>(this);
private StringVetoListener _woonPlaatsVetoListener = new WoonplaatsVetoListener();
public Persoon(String voornaam,String achternaam,String woonplaats){
_voornaamM.getController().addVetoListener(_voornaamVetoListener);
_voornaamM.setValue(voornaam);
_achternaamM.getController().addVetoListener(_achternaamVetoListener);
_achternaamM.setValue(achternaam);
_woonplaatsM.getController().addVetoListener(_woonPlaatsVetoListener);
_woonplaatsM.setValue(woonplaats);
}
public StringModel<Persoon> getAchternaamM(){
return _achternaamM;
}
public StringModel<Persoon> getVoornaamM(){
return _voornaamM;
}
public StringModel<Persoon> getWoonplaatsM(){
return _woonplaatsM;
}
private class VoornaamVetoListener implements StringVetoListener{
public void validate(StringEvent e){
if(e == null){
throw new NullPointerException("e can`t be null");
}
if(e.getNewValue() == null){
throw new IllegalArgumentException("voornaam can`t be null");
}
if(e.getNewValue().trim().length() == 0){
throw new IllegalArgumentException("voornaam moet meer zijn dan alleen een lege string");
}
}
}
private class AchternaamVetoListener implements StringVetoListener{
public void validate(StringEvent e){
if(e == null){
throw new NullPointerException("e can`t be null");
}
if(e.getNewValue() == null){
throw new IllegalArgumentException("achternaam can`t be null");
}
if(e.getNewValue().trim().length() == 0){
throw new IllegalArgumentException("achternaam moet meer zijn dan alleen een lege string");
}
}
}
private class WoonplaatsVetoListener implements StringVetoListener{
public void validate(StringEvent e){
if(e == null){
throw new NullPointerException("e can`t be null");
}
if(e.getNewValue() == null){
throw new IllegalArgumentException("achternaam can`t be null");
}
if(e.getNewValue().trim().length() == 0){
throw new IllegalArgumentException("woonplaats moet meer zijn dan alleen een lege string");
}
}
}
} |
en dit is de aansluiting in de gui:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public class TestPanel extends JPanel
{
private Persoon _persoon = new Persoon("jan","bakker","slochteren");
public TestPanel(){
super(new VerticalFlowLayout());
add(new StringLabel(_persoon.getVoornaamM()));
add(new StringTextField(_persoon.getVoornaamM()));
add(new StringLabel(_persoon.getAchternaamM()));
add(new StringTextField(_persoon.getAchternaamM()));
add(new StringLabel(_persoon.getWoonplaatsM()));
add(new StringTextField(_persoon.getWoonplaatsM()));
}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setContentPane(new TestPanel());
frame.setSize(300,300);
frame.setVisible(true);
}
} |
Zoals je zit is het super simpel, omdat je totaal niet meer hoeft te denken om allerlei event afhandel zaken, dat gebeurt nu generiek. Ik ga hem nog generieker maken (auto support voor andere types, lijsten, map, sets etc) omdat je niet alleen met string wilt werken, maar dit is mijn idee. Wat vinden jullie hiervan?