Академический Документы
Профессиональный Документы
Культура Документы
paumier@univ-mlv.fr
Le MVC
MVC=Modle Vues Contrleurs architecture permettant de sparer proprement la gestion des donnes et l'affichage des donnes:
LE modle gre les donnes les vues les affichent les contrleurs demandent au modle de modifier les donnes
paumier@univ-mlv.fr
Le modle
dfini par une interface indiquant ce qu'on peut faire exemple: ListModel
void addListDataListener(ListDataListener l) Object getElementAt(int index) int getSize() void removeListDataListener(ListDataListener l)
donc, un modle de liste permet d'avoir la taille, un lment donn et des listeners pour savoir quand a change
paumier@univ-mlv.fr
Le modle
l'interface dfinit ce dont les vues peuvent avoir besoin, pas ce qui concerne la mise jour des donnes:
pas de add dans ListModel ce sera le rle d'une implmentation comme DefaultListModel
toujours bien sparer l'interface de l'implmentation, pour viter de forcer la main sur la faon de grer les donnes
4
paumier@univ-mlv.fr
Le modle
le xxxListener doit fournir les mthodes informant des changements possibles exemple: ListDataListener
public void contentsChanged(ListDataEvent e) public void intervalAdded(ListDataEvent e) public void intervalRemoved(ListDataEvent e)
le modle doit appeler les fire... correspondant quand c'est ncessaire (cf. cours prcdent)
5
paumier@univ-mlv.fr
Le modle
le xxxEvent doit fournir les renseignements ncessaires sur le changement qui a eu lieu exemple: ListDataEvent
int getIndex0(): dbut de l'intervalle
paumier@univ-mlv.fr
Les vues
une vue est un mode de reprsentation des donnes souvent un objet graphique, mais a pourrait tre autre chose:
paumier@univ-mlv.fr
Les vues
une vue a pour but de montrer les donnes que son modle lui fournit pour cela, elle met un listener sur son modle pour savoir quand elle doit se mettre jour fait implicitement pour les objets usuels de Swing, quand on passe un modle au constructeur d'une vue:
final DefaultListModel model=new DefaultListModel(); JList list=new JList(model);
paumier@univ-mlv.fr
Les vues
final DefaultListModel model=new DefaultListModel(); JList list=new JList(model); JButton b=new JButton("Insert random 0-100 number at random position"); b.addActionListener(new ActionListener() { Random random=new Random(); @Override public void actionPerformed(ActionEvent e) { int index=random.nextInt(model.getSize()+1); int value=random.nextInt(101); model.add(index,value); } });
paumier@univ-mlv.fr
Les vues
final JMenu menu=new JMenu("0 item"); model.addListDataListener(new ListDataListener() { @Override public void contentsChanged(ListDataEvent e) { /* Nothing to do because we only add data */ } @Override public void intervalAdded(ListDataEvent e) { int n=model.getSize(); menu.setText(n+" item"+(n>1?"s":"")); for (int i=e.getIndex0();i<=e.getIndex1();i++) { menu.add(new JMenuItem(model.getElementAt(i).toString()),i); } } @Override public void intervalRemoved(ListDataEvent e) { /* Nothing to do because we only add data */ }
});
paumier@univ-mlv.fr
10
Les contrleurs
contrleur="chose" qui demande au modle de modifier les donnes dans l'exemple prcdent, c'tait le bouton on peut avoir plusieurs contrleurs ils doivent toujours poster leurs demandes au modle dans la thread Swing! exemple: Timer qui incrmente chaque seconde de 1000 un lment tir au hasard
paumier@univ-mlv.fr
11
Les contrleurs
ncessite une modification de la vue menu pour tenir compte des changements:
@Override public void contentsChanged(ListDataEvent e) { for (int i=e.getIndex0();i<=e.getIndex1();i++) { JMenuItem item=(JMenuItem) menu.getItem(i); item.setText(model.getElementAt(i).toString()); } }
le Timer n'ajoute ni ne retire d'lment: il en modifie un existant; c'est donc contentChanged qui est concerne
paumier@univ-mlv.fr
12
En rsum
le modle prvient les vues des changements avec les mthodes fire... les contrleurs demandent des modifications des donnes au modle
13
C1
C2
C3
paumier@univ-mlv.fr
Un exemple complet
projet: un Victim Manager pour le syndicat des tueurs en srie besoins client:
tenir jour une liste de victimes, dfinies par un nom et un tat (safe, scared, dead) on doit pouvoir modifier l'tat d'une victime (safe scared ou scared dead)
paumier@univ-mlv.fr
14
Les donnes
paumier@univ-mlv.fr
15
Les donnes
l'tat est dfini avec une jolie enum, afin de grer de beaux commentaires:
public enum State { SAFE("smile.png", "Life is beautiful", "The world is great", "Everybody is cool", "I feel groovy baby!"), SCARED("scared.png", "Oh my god! Oh my god! Oh my god!", "You'll never get me!", "I'm scared!", "Please save me!"), DEAD("rip.png", "Rest in peace", "dead", "horribly murdered"); private final ImageIcon icon; private final String[] comment; private State(String iconName, String... comment) { this.icon = new ImageIcon(State.class.getResource(iconName)); this.comment = comment; } public ImageIcon getIcon() { return icon; } public String getComment(int n) { return comment[Math.abs(n) % comment.length]; }
paumier@univ-mlv.fr
16
Le modle
VictimListModel qui va hriter de AbstractListModel (pas de DefaultListModel, car on aurait plein de mthodes dont on ne veut pas !)
paumier@univ-mlv.fr
17
Le modle
18
Le modle
comme on a restreint la visibilit de upgrade, on met Victim et VictimListModel dans un mme souspackage, pour que seul le modle puisse modifier les donnes avantage: il est au courant de tous les changements et peut donc faire tous les fireContentsChanged ncessaires proprement
public void upgradeVictim(int index) { Victim v=victims.get(index); v.upgrade(); fireContentsChanged(this,index,index); }
paumier@univ-mlv.fr
19
Un contrleur
pour modifier l'tat d'une victime de la liste, on utilise un bouton qui agit sur la victime slectionne
final JButton b=new JButton("Choose a victim"); b.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int n=list.getSelectedIndex(); if (n==-1) { /* Should not occur, because the button is supposed to * be disabled in that case */ return; } model.upgradeVictim(n); } });
20
paumier@univ-mlv.fr
paumier@univ-mlv.fr
22
Rafrachissement du contrleur
pourquoi ? parce que le bouton se rafrachit en fonction de la slection et qu'elle n'a pas chang
23
paumier@univ-mlv.fr
Rafrachissement du contrleur
});
paumier@univ-mlv.fr
24
Le renderer
en Swing, une vue utilise un unique composant pour dessiner ses lments: le renderer le renderer est mis jour pour chaque lment afficher, puis il est plac au bon endroit et dessin il ne ragit pas aux vnements! pour une JList, c'est par dfaut un DefaultListCellRenderer qui hrite de JLabel
25
paumier@univ-mlv.fr
Le renderer
le renderer d'une liste invoque setText avec ce que retourne toString pour chaque lment on peut redfinir le renderer avec:
setCellRenderer(ListCellRenderer r)
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
paumier@univ-mlv.fr
26
Le renderer
on pourrait donc utiliser autre chose qu'un JLabel dans notre exemple, on veut ajouter une image et de la couleur le DefaultListCellRenderer hritant de JLabel, il nous suffit donc de le personnaliser
paumier@univ-mlv.fr
27
Le renderer
on appelle super.get... pour garder le comportement par dfaut d'une cellule de liste (slection):
list.setCellRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { /* We call super so that the default behavior (highlight cells * when selected) will remain */ Victim v = (Victim) value; super.getListCellRendererComponent(list, v.getName() + ": " + v.getComment(), index, isSelected, cellHasFocus); setIcon(v.getState().getIcon()); switch (v.getState()) { case SAFE: setForeground(Color.GREEN); break; case SCARED: setForeground(Color.ORANGE); break; case DEAD: setForeground(Color.RED); break; } return this; } });
paumier@univ-mlv.fr
28
Rsultat
paumier@univ-mlv.fr
29
Un renderer d'arbre
autre exemple: rendu des noeuds particulier quand on a une classe avec un main:
JTree tree = new JTree(treeModel); tree.setCellRenderer(new DefaultTreeCellRenderer() { @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; Object userObject = node.getUserObject(); if (userObject instanceof Class<?>) { Class<?> clazz = (Class<?>) userObject; setText(clazz.getSimpleName()); if (null != getMainMethod(clazz)) { setIcon(runIcon); } } return this; } });
paumier@univ-mlv.fr
30