MVC Model, View, Controller Basert på tredeling av funksjonalitet Modell holder underliggende data View leser og visualiserer data Controller tolker input og endrer data Fordeler kan bytte ut hver enkelt del flere view mot samme data automatisk koordinering Mer komplekst
MVC-arkitekturen binder sammen komponenter og data
MVC i Swing View Controller lese vha. get-metoder endre vha. set/ add-metoder Modell endringshendelser
Typisk modell Klasse med uavhengige attributter kalt properties, basert på domenemodell F.eks. Person-klasse: name og email, begge String-objekter dateofbirth, java.util.date-objekter Modellen må ha to egenskaper metoder for å lese og skrive attributtene kunne sende ut endringshendelser
Basert på JPanel Typisk komponent JLabel med tekst tilsvarende attributtnavn komponent tilpasset attributtets klasse/datatype F.eks. PersonPanel: JTextField for name (ingen syntaksbegrensninger) JTextField for address JPanel-komponenten har en modell-property leser og skriver modellens attributter lytter til endringer i modellens attributter
JavaBeans-baserte modeller En JavaBean har visse egenskaper og følger visse navngivingskonvensjoner Alle JavaBeans har et sett såkalte properties av ulike kategorier Alle JavaBeans er kodet iht. visse konvensjoner navngiving av metoder for å lese og skrive properties, read-metode: public <type> get<property>, f.eks. public String getname() write-metode: public void set<property>(<type> p), f.eks. public void setname(string name) generering av hendelser ved endringer av properties hendelsesklasse: PropertyChangeEvent metoder for å registrere PropertyChangeListener-lyttere: add/removepropertychangelistener
Typisk kallsekvens 1. Komponenter legger seg til som lytter på modell 2. Modellen legger lytteren inn i liste 3. Komponenten (eller annet objekt) endrer på en property i modellen 4. Modellen lager en endringshendelse og kaller endringsmetoden til alle lytterne 5. Lytterne reagerer på endringshendelsen. Lytterne får endringshendelsen uavhengig av hvilket objekt som endret property en
Bound properties En bound property genererer en PropertyChangeEvent ved endring Hver endring av property må skje gjennom set-metode, også interne endringer dersom property ens nye verdi er ulik den gamle, må endringen kringkastes lyttende objekter (dvs. registrerte objekter som implementerer PropertyChangeListener-grensesnittet) Mekanikken kan delegeres til et PropertyChangeSupportobjekt, som håndterer registrering av lyttere og kringkasting av hendelser add/removepropertychangelistener firepropertychange
Class PropertyChangeSupport public class PropertyChangeSupport This is a utility class that can be used by beans that support bound properties. You can use an instance of this class as a member field of your bean and delegate various work to it. Constructor: PropertyChangeSupport(Object sourcebean) Constructs a PropertyChangeSupport object. Methods: void addpropertychangelistener(propertychangelistener listener) Add a PropertyChangeListener to the listener list. void firepropertychange(string propertyname, boolean oldvalue, boolean newvalue) Report a boolean bound property update to any registered listeners.
Interface PropertyChangeListener public interface PropertyChangeListener extends EventListener A "PropertyChange" event gets fired whenever a bean changes a "bound" property. You can register a PropertyChangeListener with a source bean so as to be notified of any bound property updates. public void propertychange(propertychangeevent evt) This method gets called when a bound property is changed. Parameters: evt - A PropertyChangeEvent object describing the event source and the property that has changed.
Klassediagram PropertyChangeSupport JPanel 1 PersonPanel getmodel() : Person setmodel(person) 0..n model 1 Person getname() : String setname(string) addpropertychangelistener(propertychangelistener) 0..n pcs 1 listeners <<Interface>> PropertyChangeListener 0..n propertychange()
Typisk kallsekvens panel : PersonPanel addpropertychangelistener person : Person pcs : PropertyChangeSupport addpropertychangelistener setname firepropertychange propertychange configurepanel
Person-klassen (model) En attributt: name (kunne i tillegg ha hatt f.eks. address, e-mail,,) Metoder for lese og skrive attributtverdier get/set-metodepar for hvert felt get-metodene er parameterløse og returnerer objekt av type tilsvarende attributtets set-metoden tar ett parameter av type tilsvarende attributtets og returnerer ingenting (void) Property-navn-konstanter objekt (String) som identifiserer property, f.eks. public final static NAME_PROPERTY = name ; konstantverdien brukes bl.a. i endringshendelsesobjekter for å angi hvilken property som er endret lyttere sjekker typisk hvilken property som er endret, for å kunne reagere riktig, f.eks. oppdatere tilsvarende tekstfelt
Person-klassen (model) Metoder for håndtere endringslyttere addpropertychangelistener(propertychangelistener) removepropertychangelistener(propertychangelistener) Beskyttet metode for å fyre av endringshendelser protected firepropertychange(property, oldvalue, newvalue) Delegerer til privat PropertyChangeSupport-instans private PropertyChangeSupport pcs = new PropertyChangeSupport(this);... public void addpropertychangelistener(propertychangelistener listener) { pcs.addpropertychangelistener(listener); }... protected void firepropertychange(string prop, Object old, Object ny) { pcs.firepropertychange(prop, oldvalue, newvalue); }
import java.beans.propertychangesupport; import java.beans.propertychangelistener; public class Person { public final static String NAME_PROPERTY = "Name"; private PropertyChangeSupport pcs; private String name = null; public Person() { pcs = new PropertyChangeSupport(this); } public String getname() { return name; } public void setname(string name) { String oldvalue = this.name; this.name = name; pcs.firepropertychange(name_property, oldvalue, name); } public void addpropertychangelistener(propertychangelistener listener) { pcs.addpropertychangelistener(listener); } }
PersonPanel-klassen (view) Modell-referanse et modell-attributt av typen Person all visning og editering skjer på dette objektet merk at modellen kan være null Property-orienterte subkomponenter JLabel tilsvarende property-navnet Lytter til property-endringer implements PropertyChangeListener public void propertychange(propertychangeevent evt)
import java.beans.*; import java.awt.event.*; import javax.swing.*; public class PersonPanel extends JPanel implements PropertyChangeListener { private Person model; private JTextField namefield; private JButton clearbutton; public PersonPanel() { namefield = new JTextField(); namefield.setcolumns(20); namefield.addactionlistener(new mytextaction()); add(namefield); clearbutton = new JButton("Clear"); clearbutton.addactionlistener(new ClearButtonAction()); add(clearbutton); } /** Action for text field * */ class mytextaction implements ActionListener { public void actionperformed(actionevent e) { model.setname(namefield.gettext()); } } /** Action for clearbutton * */ class ClearButtonAction implements ActionListener { public void actionperformed(actionevent e) { model.setname(""); } }
// Set model public void setmodel(person themodel) { model = themodel; model.addpropertychangelistener(this); } } // PropertyChangeListener public void propertychange(propertychangeevent evt) { if (evt.getpropertyname() == Person.NAME_PROPERTY) { namefield.settext(model.getname()); } }
Persons-prosjektet: Person-klassen er modellen til to PersonPanel view. Person-objektet (modellen) er observerbare alle vesentlige egenskaper kan leses vha. getmetoder Modellen sier fra når disse egenskapene endres lyttere kan registrere seg, så de får endringshendelser
import javax.swing.jpanel; import javax.swing.jframe; public class PersonPanelExample_Simple extends JPanel { private PersonPanel personpanela, personpanelb; private Person model; public PersonPanelExample_Simple() { model = new Person(); personpanela = new PersonPanel(); personpanela.setmodel(model); add(personpanela); personpanelb = new PersonPanel(); personpanelb.setmodel(model); add(personpanelb); } model model } public static void main(string args[]) { JFrame frame = new JFrame("..."); frame.add(new PersonPanelExample_Simple()); frame.pack(); frame.setvisible(true); }
Basiskomponenter Layout JList
Kontrollelementer
Hvordan bli kjent med en ny komponent Prøv den med SwingSet2-demo! Hva heter klassen og hvor ligger den i hierarkiet? JButton, arver fra AbstractButton JCheckBox, arver fra JToggleButton, som arver fra AbstractButton Hvilke data håndterer den og hvordan leses/settes de(t)? sannhetsverdier (boolean), leses/settes med isselected/setselected Hvilke vesentlige egenskaper har den? har ikon og tekst for angi mening (get/seticon, get/settext) Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? action-hendelsen for selected-egenskapen ActionListener, actionperformed og ActionEvent addactionlistener og removeactionlistener Prøv den i en enkel Swing-applikasjon!
JCheckBox Prøv den med SwingSet2-demo Hva heter klassen og hvor ligger den i hierarkiet? JCheckBox, arver fra JToggleButton, som arver fra Hvilke data håndterer den og hvordan leses/settes de(t)? sannhetsverdi (boolean) isselected/setselected Hvilke vesentlige egenskaper har den? ikon og tekst get/seticon og get/settext Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? action-hendelsen for selected-egenskapen ActionListener, actionperformed og ActionEvent addactionlistener og removeactionlistener Prøv den i en enkel Swing-applikasjon!
JSlider Prøv den med SwingSet2-demo Hva heter klassen og hvor ligger den i hierarkiet? JSlider, arver direkte fra JComponent Hvilke data håndterer den og hvordan leses/settes de(t)? heltallsverdi innen intervall get/setvalue, setminimum, setmaximum Hvilke vesentlige egenskaper har den? såkalte ticks m/tekst metoder for å angi hvilke ticks som finnes og om de og deres tekst skal tegnes Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? change-hendelsen for value-egenskapen ChangeListener, statechanged og ChangeEvent addchangelistener og removechangelistener Prøv den i en enkel Swing-applikasjon!
JTextField Prøv den med SwingSet2-demo Hva heter klassen og hvor ligger den i hierarkiet? JTextField, arver fra JTextComponent Hvilke data håndterer den og hvordan leses/settes de(t)? tekst (String) get/settext Hvilke vesentlige egenskaper har den? skriftstype (Font) og antall kolonner (columns) get/setfont, get/setcolumns Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? action-hendelsen for text-egenskapen ved trykk på ENTER-tast ActionListener, actionperformed og ActionEvent addactionlistener og removeactionlistener Prøv den i en enkel Swing-applikasjon!
JComboBox Prøv den med SwingSet2-demo Hva heter klassen og hvor ligger den i hierarkiet? JComboBox, arver fra JComponent Hvilke data håndterer den og hvordan leses/settes de(t)? lister (model) og valg av ett element (selection) get/setmodel, get/setselecteditem, get/setselectedindex Hvilke vesentlige egenskaper har den? om tekstfeltet er editerbart: get/seteditable Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? item-hendelsen for selecteditem/selectedindex-egenskapen action-hendelsen for selecteditem/selectedindex-egenskapen Prøv den i en enkel Swing-applikasjon!
JSpinner Prøv den med SwingSet2-demo Hva heter klassen og hvor ligger den i hierarkiet? JSpinner, arver fra JComponent Hvilke data håndterer den og hvordan leses/settes de(t)? objekter som inngår i en ordnet sekvens iht. reglene implementert i en SpinnerModel og getnextvalue/getpreviousvalue-metodene (se kodeeksempel) get/setvalue Hvilke vesentlige egenskaper har den?? Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? change-hendelsen for value-egenskapen Prøv den i en enkel Swing-applikasjon!
JFormattedTextField Prøv den med SwingSet2-demo Hva heter klassen og hvor ligger den i hierarkiet? JFormattedTextField, arver fra JTextField Hvilke data håndterer den og hvordan leses/settes de(t)? objekter som har en tekstsyntaks iht. reglene implementert i en JFormattedTextField.AbstractFormatter og valuetostring/stringtovalue-metodene (se kodeeksempel) get/setvalue Hvilke vesentlige egenskaper har den?? Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? propertychange-hendelsen for value-egenskapen PropertyChangeListener, propertychanged og PropertyChangeEvent addpropertychangelistener og removepropertychangelistener Prøv den i en enkel Swing-applikasjon!
Eksempel: J... Prøv den med SwingSet2-demo Hva heter klassen og hvor ligger den i hierarkiet? J, arver fra J Hvilke data håndterer den og hvordan leses/settes de(t)? <type> get/set Hvilke vesentlige egenskaper har den?? Hvilke syntaktiske hendelser genererer komponenten og for hvilke egenskaper? Hvilket lyttergrensesnitt og metoder og hendelsesklasser inngår i håndtering av hendelsen? -hendelsen for -egenskapen Listener, Performed og Event addlistener og removelistener Prøv den i en enkel Swing-applikasjon!
Oppsummering Alle basiskomponenter har samme struktur klassenavn og superklasse dataverdi(er) essensielle egenskaper hendelser og tilhørende grensesnitt, metoder og klasser Å bli kjent med en komponent innebærer å oppsøke informasjon om hver del og prøve den ut Hendelser De fleste komponenter har egne typer hendelser Noen komponenter følger JavaBeans-mønsteret og genererer PropertyChangeEvent er
JList, JTree, JTable JList
JList ListModel ListSelectionModel ListCellRenderer
JList View lese vha. get-metoder MVC Modellen Model Controller endre vha. set/ add-metoder endringshendelser
JList ListModel JList sitt modell-grensesnitt, altså den delen som fyller modell-rollen ListSelectionModel Håndtering av bruker-interaksjon, altså en del av controller-rollen ListCellRenderer Styrer visning av elementene i lista, altså en del av view-rollen
Scrolling JList støtter ikke scrolling. Det må legges på eksplisitt. Det gjøres ved å pakke den inn i en JScrollPane JScrollPane myjscrollpane = new JScrollPane(myJList); myjscrollpane.setverticalscrollbarpolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); add(myjscrollpane);
Objekt- : ListDataListener diagram modell : ListModel list : JList model : ListSelectionListener renderer renderer : ListCellRenderer selectionmodel selection : ListSelectionModel : Component
Interface ListModel, JList sin modell get-metoder (gir tilgang til data) getsize() størrelsen til lista getelementat(index) elementene i lista lyttere og hendelser registrering av lytter: add/removelistdatalistener(listdatalistener l)
Interface ListDataListener JList implementerer denne Void contentschanged(listdataevent e) Sent when the contents of the list has changed in a way that's too complex to characterize with the previous methods. Void intervaladded(listdataevent e) Sent after the indices in the index0,index1 interval have been inserted in the data model. Void intervalremoved(listdataevent e) Sent after the indices in the index0,index1 interval have been removed from the data model.
DefaultListModel Alle JList får automatisk en modell av klassen DefaultListModel. Vi kan legge inn en slik direkte: private JList myjlist; private DefaultListModel model; public JListExample_1() { model = new DefaultListModel(); myjlist = new JList(model); model.addelement("linje 1"); model.addelement("linje 2"); model.addelement("linje 3"); add(myjlist); }
JList og ListModel... Sentrale teknikk delegering Hendelse-lytter-pattern XxxEvent-klasse XxxListener-interface add/removexxxlistener Sentrale klasser/objekter ListModel ListDataListener ListDataEvent Sentrale metoder : ListDataListener list : JList addlistdatalistener og contentschanged getsize og getelementat 1: addlistdatalistener(listdatalistener) 2: contentschanged(listdataevent) 3: getsize( ) model 4: getelementat(int) mo de ll : Li stmo de l
ListSelectionModel Den eneste interaksjonen en JList støtter er tre typer seleksjon: seleksjon av enkelt element seleksjon av sekvens av elementer seleksjon av sett av sekvenser, altså ingen begrensning på seleksjonen Det er JList sin listselectionmodel-property, som håndterer seleksjonen objektet inneholder og manipulerer seleksjonen, basert på brukerens interaksjon modusen (selectionmode-property en) angir hvilken av de tre typene seleksjonslogikk som gjelder
Seleksjon ListSelectionModel-klassen håndterer logikken SINGLE_SELECTION Valg av kun ett elemenent Valg av nytt element fjerner eksisterende valg SINGLE_INTERVAL_SELECTION Valg av flere etterfølgende elementer Shift-klikk for å utvide seleksjonen i begge retninger MULTIPLE_INTERVAL_SELECTION Valg uten begrensninger på antall eller intervaller Control-klikk toggler enkelt-elementer Shift-klikk utvider seleksjonen
ListSelectionListener JList kringkaster endringer i seleksjonen til sine ListSelectionListenerlyttere Ved å registrere en slik lytter, kan andre klasser/objekter reagere på brukerens endringer i seleksjonen Typisk bruk 1 list-detail- pattern : liste med elementer, med ekstra panel med detaljer Viktige egenskaper vises i lista, med detaljer i et panel ved siden av. Når seleksjonen endres, oppdateres detalj-panelet Typisk bruk 2 Action-objekter bruker seleksjon for å utføre oppgaven sin, dvs. hente ut objekt å utføre aksjon på Seleksjonen brukes også for å aktivere/deaktivere aksjonen
...seleksjon Sentrale teknikker delegering Hendelse-lytter-pattern XxxEvent-klasse XxxListener-interface add/removexxxlistener Sentrale klasser/objekter ListSelectionModel ListSelectionListener ListSelectionEvent Sentrale metoder JList.addListSelectionListener ListSelectionListener.valueChanged list : JList 8: ad dl istse le cti on Liste ne r(l istse le cti on Liste ne r) : L istse le cti on Liste ne r 10: valuechanged(listselectionevent) 9: addlistselectionlistener(listselectionlistener) selectionmodel : ListSelectionModel
View-delen av JList ListCellRenderer interface som bygger bro mellom JList sine behov for å tegne rader i lista og Componentsubklasser gjenbruker en eksisterende Component-subklasse for å tegne hver linje i en JList ved å skrive egne komponenter for visning av liste-elementer, kan JList skreddersys visning av egne data
JList og ListCellRenderer JList delegerer tegning av hver element i lista til en ListCellRenderer getcellrenderer ListCellRenderer configurerer og returnerer en Component getlistcellrenderercomponent Component-objektet har en (foretrukket) størrelse og kan tegne seg selv getpreferredsize paintcomponent Siste Swing-versjon støtter layout i flere kolonner
JList og ListCellRenderer... list : JList 5: getlistcellrenderercomponent(jlist, Object, int, boolean, boolean) renderer renderer : ListCellRenderer 6: getpreferredsize( ) Sentral teknikk delegering Sentrale klasser/objekter ListCellRenderer Component 7: paint(graphics) : Component
JList og ListCellRenderer... Omtrentlig sekvens av operasjoner spør ListModel om størrelse getsize() itererer over alle elementene spør om verdi getelementat(int) ber renderer konfigurere og returnere komponent spør om størrelsen og gir plass ber komponenten tegne seg selv posisjon og størrelse huskes slik at en vet hvilke linjer som er hvor for hver linje som endres, gjentas dette, f.eks. verdi, seleksjon og fokus