APNVZ_2 Vzor Model view controller, Observer 1
Model-View-Controller MVC vzor architektury dělí interaktivní aplikaci na tři komponenty: Model obsahuje funkcionální jádro a data. Views (pohledy) zobrazují informace uživateli. Controllers (řízení) zpracovávají uživatelský vstup. Views a controllers spolu představují uživatelské rozhraní. Mechanismus šíření změn zabezpečí konzistenci mezi uživatelským rozhraním a modelem. 2
Model-View-Controller Kontext: Interaktivní aplikace s pružným rozhraním člověkpočítač. Problém: Uživatelské rozhraní je náchylné ke změnám požadavků. Při rozšíření funkčnosti aplikace je třeba modifikovat menu. I změna nové verze základního OS přináší změny. Klasické budování takového systému je úzce spjaté s funkcionálním jádrem. 3
Model-View-Controller Síly ovlivňující řešení: Stejné informace jsou prezentovány v různých oknech. Zobrazení a chování aplikace musí odrážet okamžitou manipulaci s daty. Změny v uživatelském rozhraní by měly být snadné a dokonce možné za běhu aplikace. Podpora různých look and feel standardů nebo portování uživatelského rozhraní by nemělo ovlivnit jádro aplikace. 4
Model-View-Controller Řešení: MVC, které dělí aplikaci na zpracování (model), výstupy (views), vstupy (controllers). Komponenta model zapouzdřuje základní data a funkcionalitu. Model je nezávislý na specifikacích vstupního a výstupního chování aplikace. 5
Model-View-Controller Komponenta View (pohled) zobrazuje uživateli informace. View dostává data od modelu. Na model může existovat několik pohledů. Každé view má asociovanou komponentu controller. Controllers obdrží událost, ta je přetransformována na požadavek služby pro model nebo view. Uživatel komunikuje se systémem výhradně prostřednictvím controlleru. 6
Model-View-Controller Separace komponenty model od komponent view a controller umožňuje násobné pohledy na stejný model. Pokud uživatel změní model prostřednictvím komponenty controller jedné komponenty view, všechny ostatní komponenty view závislé na těchto datech se také změní. Komponenta model proto uvědomuje všechny komponenty view, zda-li se jejich data změnila. Komponenty view na druhou stranu obnovují data z komponenty model a aktualizují 7
Model-View-Controller Mechanismus šíření změn udržuje seznam závislých komponent uvnitř modelu. Všechny komponenty view a také vybrané komponenty controller registrují své potřeby být informován o změnách. Změny stavu modelu spouštějí mechanismus šíření změn. Tento mechanismus je reprezentován spojením komponent model s komponentami views a controllers. 8
Model-View-Controller Komponenty view představují informace pro uživatele. Různé komponenty views prezentují informace modelu různým způsobem. Každá komponenta view definuje proceduru update, která je aktivována mechanismem šíření změn. Když je zavolána procedura update, komponenta view obnoví hodnoty aktuálních dat z modelu a zobrazí je na obrazovce. 9
Model-View-Controller Během inicializace jsou všechny komponenty view asociovány s modelem a registrovány v mechanismu šíření změn. Každá komponenta view vytváří odpovídající komponentu controller. Mezi komponentami view a controller existuje asociace jedna k jedné. 10
Základní schéma MVC Observer +update() -callupdate Model -coredata -setofobservers -attach -getdata View +attachobserver() +detachobserver() +notify() +getdata() +service() -attach -mymodel -mycontroller +initialize(model)() +makecontroller() +activate() +display() +update() -create 1 -manipulate display -callservice 1 -mymodel -myview Controller +initialize(model, View)() +handleevent() +update() 11
Základní scénář práce MVC Controller Model View handleevent service notify update display getdata update getdata 12
Inicializace MVC main program Model View initialize attach makecontroller Controller initialize attach starteventprocessing 13
Implementace 1. Oddělení interakce člověk-počítač od jádra funkcionality. 2. Implementace mechanismu šíření změn. 3. Návrh a implementace komponent views. 4. Návrh a implementace komponent controllers. 5. Návrh a implementace vztahu komponent viewcontroller. 14
Výhody / nevýhody Výhody Vícenásobné pohledy na stejný model. Synchronizované pohledy. Snadno zaměnitelné komponenty views a controllers. Slabá místa Vzrůstající složitost. Rychle rostoucí počet operací update. Neefektivnost v přístupu k datům v pohledu. 15
Aplikace monitorování počasí Manuální MVC - obrázek Humidity sensor Temperature sensor Weather Station pull data WeatherData Object displays Display device Pressure sensor implementation 16
public class WeatherData implements Subject { private float temperature; private float humidity; private float pressure; public void measurementschanged() { float temperature = gettemperature(); float humidity = gethumidity(); float pressure = getpressure(); currentconditionsdisplay.update(temperature, humidity, pressure); statisticsdisplay.update(temperature, humidity, pressure); forecastdiaplay.update(temperature, humidity, pressure); Poznámky První návrh WeatherData volání metod zabezpečí aktuální stav aktualizace displejů public float gettemperature() { return temperature; public float gethumidity() { return humidity; public float getpressure() { return pressure; 17
public class WeatherData implements Subject { Poznámky private float temperature; private float humidity; private float pressure; Kódováním konkrétní implementace, není možnost přidat, odstranit další zobrazované prvky. První návrh WeatherData public void measurementschanged() { float temperature = gettemperature(); float humidity = gethumidity(); float pressure = getpressure(); Mělo by se společné rozhraní, jedná se vždy o metodu update currentconditionsdisplay.update(temperature, humidity, pressure); statisticsdisplay.update(temperature, humidity, pressure); forecastdiaplay.update(temperature, humidity, pressure); je třeba zapouzdřit 18
Publisher + subscriber = Observer Když se změní data v objektu, ti co ho sledují observers pozorovatelé jsou o tom uvědoměni. Publisher publikuje subscriber předplatitel. Dog Object Subject Cat Object Mouse Object 19
Publisher + subscriber = Observer Vzor observer definuje relaci one-to-many mezi objektem a množinou (kolekcí objektů). Když se stav objektu změní, jsou uvědoměny všechny objekty množiny (kolekce) závislých objektů. Dog Object Subject Cat Object Mouse Object Duck Object 20
Diagram tříd vzor Observer «interface» Subject registerobserver() removeobserver() notifyobservers() observer «interface» Observer update() ConcreteSubject ConcreteObserver registerobserver() removeobserver() notifyobservers() subject update() //other Observer methods 21
Síla volné vazby loose coupling Když jsou dva objekty volně spojeny, mohou vzájemně interagovat (vzájemně se ovlivňovat), ale mají o sobě velmi málo vědomostí. Vzor observer poskytuje návrh objektů, kde objekty a observery jsou volně propojeny. Jedinou věc, kterou subjekt ví o observrech je, že implementovaly dané (jisté) rozhraní. Můžeme přidat (odebrat) další observery (pozorovatele) v libovolném čase. 22
Síla volné vazby loose coupling Nikdy nebudeme potřebovat modifikovat subjekt, aby přidal nový typ observeru. Změna buď na straně subjektu, nebo observerů neovlivní druhou stranu. 23
Návrh Weather Station «interface» Subject registerobserver() removeobserver() notifyobservers() observer «interface» Observer update() «interface» DisplayElement display() ThirdPartyDisplay WeatherData registerobserver() removeobserver() notifyobservers() gettemperature() gethumidity() getpressure() measurementchanged() subject CurrentConditionsDisplay() update() display() {//display current measurements StatisticsDisplay update() display() { // display something else based on measurements ForecastDisplay update() display() { //display the average, min and max measurements update() display() { // display the forecast 24
public interface Subject { public void registerobserver(observer o); public void removeobserver(observer o); public void notifyobservers(); Poznámky public interface Observer { public void update(float temp, float humidity, float pressure); public interface DisplayElement { public void display(); 25
public class WeatherData implements Subject { private ArrayList observers; private float temperature; private float humidity; private float pressure; Poznámky První návrh WeatherData public WeatherData() { observers = new ArrayList(); public void registerobserver(observer o) { observers.add(o); public void removeobserver(observer o) { int i = observers.indexof(o); if (i >= 0) { observers.remove(i); public void notifyobservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); 26
public void measurementschanged() { notifyobservers(); Poznámky public void setmeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementschanged(); 27
public class CurrentConditionsDisplay implements Observer, DisplayElement{ private float temperature; private float humidity; private Subject weatherdata; // vazba na weatherdata Poznámky // konstruktor public CurrentConditionsDisplay(Subject weatherdata) { this.weatherdata = weatherdata; weatherdata.registerobserver(this); public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); 28
public class WeatherStation { public static void main(string[] args) { WeatherData weatherdata = new WeatherData(); CurrentConditionsDisplay currentdisplay = new CurrentConditionsDisplay(weatherData); Poznámky Implementace Weather Station StatisticsDisplay statisticsdisplay = new StatisticsDisplay(weatherData); ForecastDisplay forecastdisplay = new ForecastDisplay(weatherData); weatherdata.setmeasurements(80, 65, 30.4f); weatherdata.setmeasurements(82, 70, 29.2f); weatherdata.setmeasurements(78, 90, 29.2f); 29
Current conditions: 80.0F degrees and 65.0% humidity Avg/Max/Min temperature = 80.0/80.0/80.0 Forecast: Improving weather on the way! Current conditions: 82.0F degrees and 70.0% humidity Avg/Max/Min temperature = 81.0/82.0/80.0 Forecast: Watch out for cooler, rainy weather Current conditions: 78.0F degrees and 90.0% humidity Avg/Max/Min temperature = 80.0/82.0/78.0 Forecast: More of the same Poznámky 30
Observer Cílem tohoto návrhového vzoru je definovat závislost one-to-many (jeden k mnoha) mezi objekty Jeden objekt sledovaný (observable); mnoho objektů sledovatelé (observers), závislé objekty Průběh sledování: když se sledovaný objekt změní, jsou o tom informováni všichni sledovatelé - závislé objekty, takže mohou reagovat na změnu. Java v tomto směru poskytuje pro sledovaný objekt třídu java.util.observable. Sledovaný objekt musí být podtřídou této třídy. 31
Jak se objekt stane Observrem (objektem, který sleduje) Implementuje rozhraní Observer a zavolá metodu addobserver() pro každý observable objekt. Podobně volá deleteobserver() pro zrušení ze seznamu. 32
Sledovaný objekt - observable Daná třída musí být podtřídou třídy Observable. 1. Nejdříve musí zavolat metodu setchanged() k oznámení, že stav sledovaného objektu se změnil. 2. Pak zavolá jednu z metod notifyobservers() notifyobservers() notifyobservers(object arg) 33
Pro observery k získání oznámení Implementují metodu update(), jejíž signatura je následující: update(observable o, Object arg); Observable je subjekt, který poslal oznámení je uložen v tomto agrumentu. Object datový objekt, který je předán z metody notityobservers. 34
setchanged() { changed = true; notifyobservers(object arg) { if(changed) { for every observer on the list { call update(this.arg) changed = false; Poznámky Co se odehrává za scénou: pseudokód notifyobservers() { notifyobservers(null) 35
Použití javovského vestavěného vzoru Observer Observable observer «interface» Observer addobserver() deleteobserver() notifyobservers() setchanged() update() WeatherData gettemperature() gethumidity() getpressure() subject GeneralDisplay update() display() StatisticsDisplay update() display() ForecastDisplay update() display() 36
import java.util.observable; import java.util.observer; Poznámky public class WeatherData extends Observable { private float temperature; private float humidity; private float pressure; public WeatherData() { public void measurementschanged() { setchanged(); notifyobservers(); public void setmeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementschanged(); public float gettemperature() { return temperature; // gethumidity(), getpressure() 37
import java.util.observable; import java.util.observer; Poznámky public class CurrentConditionsDisplay implements Observer, DisplayElement{ Observable observable; private float temperature; private float humidity; // konstruktor public CurrentConditionsDisplay(Observable observable) { this.observable = observable; observable.addobserver(this); public void update(observable obs, Object arg) { if (obs instanceof WeatherData) { WeatherData weatherdata = (WeatherData)obs; this.temperature = weatherdata.gettemperature(); this.humidity = weatherdata.gethumidity(); display(); public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); 38
Observer praktická ukázka Celý návrhový vzor je demonstrován na jednoduché ukázce s jedním účtem a objekty otec a matka (typu Osoba), které na účet přispívají a objekty třídy Student, které z účtu v okamžiku, když tam přijdou peníze, peníze čerpají. V příkladu jsou uvedeni dva studenti, kteří čerpají stejným dílem. Objekt Ucet je deklarovaný jako objekt podtřídy Observable (pozorovaný objekt). Objektu třídy student implementují rozhraní Observer. 39
import java.util.observable; public class Ucet extends Observable { private int cislo; private int stav; Poznámky public Ucet() { this(0, 0, null, null); public Ucet(int cislo, int stav, Student s1, Student s2) { this.cislo = cislo; this.stav = stav; addobserver(s1); addobserver(s2); public void vlozeni (int castka) { stav = stav + castka; System.out.printf("Ucet vlozeni: %d stav: %d\n",castka, getstav()); setchanged(); notifyobservers(castka); public void vyber (int castka) { stav = stav - castka; System.out.printf("Ucet vyber: %d zustatek: %d\n",castka,getstav()); 40
public int getstav(){ return stav; public String tostring() { String tx = "Cislo uctu: " + cislo + " stav: " + stav; return tx; public void tisk() { System.out.println(this.toString()); public int getcislo(){ return cislo; Poznámky 41
public class Osoba { private String jmeno; private String bydliste; Poznámky public Osoba() { this("neuvedeno", ""); public Osoba(String jmeno, String bydliste) { this.jmeno= jmeno; this.bydliste = bydliste; public void setjmeno(string jmeno) { this.jmeno = jmeno; public String getjmeno(){ return jmeno; public void setbydliste(string bydliste) { this.bydliste = bydliste; public String getbydliste() { return bydliste; public String tostring() { return String.format("%5s %s %s %s\n", "Jmeno",getJmeno(), "bydliste:",getbydliste()); public void tiskklienta() { System.out.println(this.toString()); 42
public class Rodic extends Osoba{ private Ucet ucet; public Rodic(String jmeno, String bydliste, Ucet u){ super(jmeno, bydliste); ucet = u; Poznámky public void vlozit(int castka){ ucet.vlozeni(castka); System.out.println(getClass().getName()+" vlozil castku: "+castka); 43
import java.util.observer; import java.util.observable; public class Student extends Osoba implements Observer{ public Student(String jmeno, String bydliste){ super(jmeno, bydliste); public void update(observable ob, Object castka){ int celkem = ((Ucet)ob).getStav(); int penize; if(celkem<=0)penize = 0; else penize = (Integer)castka /2; ((Ucet)ob).vyber(penize); System.out.println(getClass().getName()+ " vybral castku: " + penize); Poznámky 44
public class TestObserver { Poznámky public static void main(string[] args) { Student karel = new Student("Karel","Praha"); Student jarmila = new Student("Jarmila","Olomouc"); Ucet ucet = new Ucet(1, 200, karel, jarmila); Rodic otec = new Rodic("Josef", "Havirov", ucet); Rodic matka = new Rodic("Alena", "Havirov", ucet); otec.vlozit(500); matka.vlozit(1200); 45
Grafické uživatelské rozhraní GUI Prvky GUI (tlačítka) jsou observable (sledované, pozorované) položky. V seznamu observerů jsou další objekty, které reagují na skutečnosti, že se s GUI prvky něco stane. Každý z observerů implementuje rozhraní ActionListener a tedy musí implementovat metodu actionperformed(). V té konkrétně specifikuje, co se stane, při dané události. 46
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; Poznámky public class SwingObserverExample { JFrame frame; public static void main(string[] args) { SwingObserverExample example = new SwingObserverExample(); example.go(); public void go() { frame = new JFrame(); JButton button = new JButton("Should I do it?"); button.addactionlistener(new AngelListener()); button.addactionlistener(new DevilListener()); frame.getcontentpane().add(borderlayout.center, button); // Set frame properties frame.setdefaultcloseoperation(jframe.exit_on_close); frame.getcontentpane().add(borderlayout.center, button); frame.setsize(300,300); frame.setvisible(true); 47
class AngelListener implements ActionListener { public void actionperformed(actionevent event) { System.out.println("Don't do it, you might regret it!"); Poznámky class DevilListener implements ActionListener { public void actionperformed(actionevent event) { System.out.println("Come on, do it!"); 48
Slabá místa java.util.observable Observable je třída a ne rozhraní. Třída Subject musí být podtřídou Observable. nemůže přidat další nadtřídu (pouze jedna nadtřída), nemůžeme implementovat metody jako u rozhraní. 49
Příklad Bruce Eckela Další příklad, kdy je datový atribut deklarovaný jako vnitřní podtřída třídy Observable nebo kdy je datový atribut jiné třídy deklarovaný jako vnitřní třída implementující rozhraní Observer. 50
UML diagram tříd Observable «interface» Observer OpenObserver Flower -onotifier -cnotifier OpenNotifier CloseNotifier Bee +openobserver() +closeobserver() CloseObserver 51
// Demonstration of "observer" pattern. import java.util.observable; public class Flower { private boolean isopen; private OpenNotifier onotify = new OpenNotifier(); private CloseNotifier cnotify = new CloseNotifier(); // konstruktor public Flower() { isopen = false; public void open() { // Opens its petals isopen = true; onotify.notifyobservers(); cnotify.open(); public void close() { // Closes its petals isopen = false; cnotify.notifyobservers(); onotify.close(); // sledovani dvou cinnosti public Observable opening() { return onotify; public Observable closing() { return cnotify; Poznámky 52
// first observable issue private class OpenNotifier extends Observable { private boolean alreadyopen = false; public void notifyobservers() { if(isopen &&!alreadyopen) { setchanged(); super.notifyobservers(); alreadyopen = true; public void close() { alreadyopen = false; Poznámky // second observable issue private class CloseNotifier extends Observable{ private boolean alreadyclosed = false; public void notifyobservers() { if(!isopen &&!alreadyclosed) { setchanged(); super.notifyobservers(); alreadyclosed = true; public void open() { alreadyclosed = false; 53
import java.util.observable; import java.util.observer; public class Bee { private String name; private OpenObserver openobsrv = new OpenObserver(); private CloseObserver closeobsrv = new CloseObserver(); public Bee(String nm) { name = nm; // An inner class for observing openings: private class OpenObserver implements Observer{ public void update(observable ob, Object a) { System.out.println("Bee " + name + "'s breakfast time!"); // Another inner class for closings: private class CloseObserver implements Observer{ public void update(observable ob, Object a) { System.out.println("Bee " + name + "'s bed time!"); Poznámky 54
public Observer openobserver() { return openobsrv; public Observer closeobserver() { return closeobsrv; Poznámky 55
import java.util.observable; import java.util.observer; public class Hummingbird { private String name; private OpenObserver openobsrv = new OpenObserver(); private CloseObserver closeobsrv = new CloseObserver(); public Hummingbird(String nm) { name = nm; Poznámky // sledovani otevreni private class OpenObserver implements Observer{ public void update(observable ob, Object a) { System.out.println("Hummingbird " + name + "'s breakfast time!"); // sledovani zavreni private class CloseObserver implements Observer{ public void update(observable ob, Object a) { System.out.println("Hummingbird " + name + "'s bed time!"); 56
public Observer openobserver() { return openobsrv; Poznámky public Observer closeobserver() { return closeobsrv; 57
import java.util.*; Poznámky public class ObservedFlower { public static void main(string args[]) { Flower f = new Flower(); Bee ba = new Bee("BA"), bb = new Bee("BB"); Hummingbird h1 = new Hummingbird("H1"), h2 = new Hummingbird("H2"); // dve sledovane veci na kvetine Observable floweropn = f.opening(); Observable flowercls = f.closing(); // dve vcely Observer bao = ba.openobserver(); Observer bac = ba.closeobserver(); Observer bbo = bb.openobserver(); Observer bbc = bb.closeobserver(); // dva kolibrici Observer h1o = h1.openobserver(); Observer h1c = h1.closeobserver(); Observer h2o = h2.openobserver(); Observer h2c = h2.closeobserver(); 58
floweropn.addobserver(bao); floweropn.addobserver(bbo); floweropn.addobserver(h1o); floweropn.addobserver(h2o); Poznámky flowercls.addobserver(bac); flowercls.addobserver(bbc); flowercls.addobserver(h1c); flowercls.addobserver(h2c); // kolibrik h2 jeste spi floweropn.deleteobserver(h2o); f.open(); // vcela bb nechce do postele flowercls.deleteobserver(bbc); f.close(); // rusi vsecny pozorovatele otevreni floweropn.deleteobservers(); System.out.println("Nikdo nesleduje otevreni"); f.open(); f.close(); 59
Hummingbird H1's breakfast time! Bee BB's breakfast time! Bee BA's breakfast time! Hummingbird H2's bed time! Hummingbird H1's bed time! Bee BA's bed time! Nikdo nesleduje otevreni Hummingbird H2's bed time! Hummingbird H1's bed time! Bee BA's bed time! Poznámky 60
Vzor MVC a web Převažující adaptace tohoto vzoru používá kombinací servletu a technologie JSP (JavaServer Pages) k uchování oddělení modelu, pohledu a kontroleru. 1. Vytvoříte HTTP request, který přijme servlet. Tato operace typicky zahrnuje, že spolu s dotazem budou zaslána data v nějaké formě jako např. uživatelské jméno a heslo. Servlet dostane tato data a syntakticky je analyzuje (parsuje). 61
Vzor MVC a web 2. Servlet pracuje jako kontroler a zpracuje váš dotaz většinou jako další (následný) dotaz na model (v tomto případě bean/ databázi). Výsledek zpracování dotazu je obyčejně vytvořen (zformován) do formy JavaBeanu. JavaBean představuje model, protože obsahuje také tzv. business logiku tedy metody pro práci s modelem. Databáze většinou již představuje jen perzistenci vložených objektů, proto nepředstavuje model. 62
Vzor MVC a web 3. Kontroler přesouvá řízení na view (pohled). View je reprezentované JSP (JavaServer Pages). Jedinou činností JSP je vytvořit stránku, která představuje pohled modelu (view of model). 4. Tento pohled JSP získá z JavaBeanu, spolu s dalšími příkazy pro řízení nutnými pro další akce. 63
Vzor MVC a web 5. Pohled vrací stránku prohlížeči prostřednictvím protokolu HTTP. Stránka je vrácena prohlížeči, kde je zobrazena jako pohled (view). Uživatel pak zadá další požadavek, který je zpracován podobným způsobem. 64
Vzor MVC a web 1 HTTP request 2 instanciuje Webový prohlížeč servlet/controller klient HTTP response 5 3 databáze / persisted data jsp/view 4 bean/ model / business logic 65
Další využití MVC JList JList Implementuje architekturu delegát - model Deleguje pro ListModels ListModel Definuje metody Registruje/ruší registraci ListDataListener mod ifies JList no tifies ListModel 66
// PhilosophersJList.java // MVC architecture using JList with a DefaultListModel import java.awt.*; import java.awt.event.*; import javax.swing.*; public class PhilosophersJList extends JFrame { // model declaration private DefaultListModel philosophers; // view declaration private JList list; Poznámky PhilosophersJList třída DefaultListModel poskytuje základní implementaci rozhraní ListModel // PhilosophersJList constructor public PhilosophersJList() { super( "Favorite Philosophers" ); // create a DefaultListModel to store philosophers philosophers = new DefaultListModel(); philosophers.addelement( "Socrates" ); philosophers.addelement( "Plato" ); philosophers.addelement( "Aristotle" ); philosophers.addelement( "St. Thomas Aquinas" ); philosophers.addelement( "Soren Kierkegaard" ); philosophers.addelement( "Immanuel Kant" ); 67
philosophers.addelement( "Friedrich Nietzsche" ); philosophers.addelement( "Hannah Arendt" ); Poznámky // create a JList for philosophers DefaultListModel view list = new JList( philosophers ); // allow user to select only one philosopher at a time list.setselectionmode( ListSelectionModel.SINGLE_SELECTION ); // create JButton for adding philosophers JButton addbutton = new JButton( "Add Philosopher" ); addbutton.addactionlistener( new ActionListener() { public void actionperformed( ActionEvent event ) { // prompt user for new philosopher's name String name = JOptionPane.showInputDialog( PhilosophersJList.this, "Enter Name" ); ); // add new philosopher to model philosophers.addelement( name ); 68
// create JButton for removing selected philosopher JButton removebutton = new JButton( "Remove Selected Philosopher" ); Poznámky removebutton.addactionlistener( new ActionListener() { ); public void actionperformed( ActionEvent event ) { // remove selected philosopher from model philosophers.removeelement( list.getselectedvalue() ); // lay out GUI components JPanel inputpanel = new JPanel(); inputpanel.add( addbutton ); inputpanel.add( removebutton ); Container container = getcontentpane(); container.add( list, BorderLayout.CENTER ); container.add( inputpanel, BorderLayout.NORTH ); setdefaultcloseoperation( EXIT_ON_CLOSE ); setsize( 400, 300 ); setvisible( true ); // end PhilosophersJList constructor 69
// execute application public static void main( String args[] ) { new PhilosophersJList(); Poznámky 70
Poznámky Aplikace PhilosophersJList demonstrující Jlist and DefaultListModel Výstup aplikace 71
JTable JTable Implementuje architekturu delegát - model Deleguje pro TableModels TableModel Declaruje metody Obnovuje a modifikuje data mod ifie s JTable notifies TableModel 72
JTable Metoda void addtablemodellistener( TableModelListener listener) void removetablemodellistener( TableModelListener listener) Popis Přidá TableModelListener do TableModel, který uvědomuje TableModelListener o změnách v TableModelu Odstraní přidaný TableModelListener z TableModelu Class getcolumnclass( int columnindex ) Vrací objekt Class pro hodnoty ve sloupci specifikovaném columnindex int getcolumncount() String getcolumnname( int columnindex ) int getrowcount() Vrací počet sloupců v TableModelu Vrací jméno sloupce ze zadaného columnindexu Vrací počet rádků v TableModelu 73
JTable Metoda Object getvalueat( int rowindex, int columnindex ) void setvalueat( Object value, int rowindex, int columnindex ) Popis Vrací referenci na Object na hodnotu uloženou v TableModelu v daném řádku a sloupci Nastaví hodnotu uloženou v TableModelu v daném řádku a sloupci boolean iscelleditable( int rowindex, int columnindex ) Vrací true, je-li specifikovaná buňka editovatelná 74
// PhilosophersJTable.java // MVC architecture using JTable with a DefaultTableModel // Java core packages import java.awt.*; import java.awt.event.*; Poznámky PhilosophersJTable import javax.swing.*; import javax.swing.table.*; public class PhilosophersJTable extends JFrame { // model declaration private DefaultTableModel philosophers; // Jtable declaration private JTable table; // PhilosophersJTable constructor public PhilosophersJTable() { super( "Favorite Philosophers" ); // create a DefaultTableModel to store philosophers philosophers = new DefaultTableModel(); // add Columns to DefaultTableModel philosophers.addcolumn( "First Name" ); philosophers.addcolumn( "Last Name" ); philosophers.addcolumn( "Years" ); 75
// add philosopher names and dates to DefaultTableModel String[] socrates = { "Socrates", "", "469-399 B.C." ; philosophers.addrow( socrates ); Poznámky String[] plato = { "Plato", "", "428-347 B.C." ; philosophers.addrow( plato ); String[] aquinas = { "Thomas", "Aquinas", "1225-1274" ; philosophers.addrow( aquinas ); String[] kierkegaard = { "Soren", "Kierkegaard", "1813-1855" ; philosophers.addrow( kierkegaard ); String[] kant = { "Immanuel", "Kant", "1724-1804" ; philosophers.addrow( kant ); String[] nietzsche = { "Friedrich", "Nietzsche", "1844-1900" ; philosophers.addrow( nietzsche ); String[] arendt = { "Hannah", "Arendt", "1906-1975" ; philosophers.addrow( arendt ); // create a JTable for philosophers DefaultTableModel table = new JTable( philosophers ); 76
// create JButton for adding philosophers JButton addbutton = new JButton( "Add Philosopher" ); Poznámky addbutton.addactionlistener( new ActionListener() { public void actionperformed( ActionEvent event ) { // create empty array for new philosopher row String[] philosopher = { "", "", "" ; ); // add empty philosopher row to model philosophers.addrow( philosopher ); 77
// create JButton for removing selected philosopher JButton removebutton = new JButton( "Remove Selected Philosopher" ); Poznámky removebutton.addactionlistener( new ActionListener() { ); public void actionperformed( ActionEvent event ) { // remove selected philosopher from model philosophers.removerow( table.getselectedrow() ); 78
// lay out GUI components JPanel inputpanel = new JPanel(); inputpanel.add( addbutton ); inputpanel.add( removebutton ); Poznámky Container container = getcontentpane(); container.add( new JScrollPane( table ), BorderLayout.CENTER ); container.add( inputpanel, BorderLayout.NORTH ); setdefaultcloseoperation( EXIT_ON_CLOSE ); setsize( 400, 300 ); setvisible( true ); // end PhilosophersJTable constructor // execute application public static void main( String args[] ) { new PhilosophersJTable(); 79
Poznámky Výstup aplikace 80