Graafilise kasutajaliidese programmeerimine I Sündmuste töötlemine Java 1.0 (vananenud) Sündmusi "tekitavad" graafilise kasutajaliidese (GKL, ingl.k. GUI) komponendid ja Java 1.0 sündmused kuuluvad klassi Event (paketist java.awt). Component klass sisaldab meetodeid boolean action (Event e, Object o) boolean handleEvent (Event e) mis tuleb alamklassides üle katta, et sündmustele reageerida (sündmusi töödelda). Sündmuste töötlemine/suunamine toimub "alt-üles" (kuni eelpoolnimetatud meetodid tagastavad false, suunatakse sündmus komponentide hierarhias kõrgemale: sündmuse tegelik tarbija tagastab true). Objekti, mis sündmuse tekitas, saab töötlemisel teada isendimuutujast e.target. Töötlusprogrammides saab üle katta mitmesugustele sündmuseliikidele vastavaid meetodeid: mouseDown, mouseUp, keyDown, keyUp, gotFocus, lostFocus, küsida lisainfot: getX, getY... jne. Ka ise saab sündmusi tekitada ja "postitada" postEvent meetodi abil. See mudel on tunnistatud ebaefektiivseks ning välja vahetatud. Peamine puudus on see, et iga sündmust peavad töötlema ka need komponendid, millel pole selle sündmusega asja. Java 1.1 alates... Sündmused on klasside hierarhias (1.0 mudelis oli ainult Event), mille juureks on EventObject (paketist java.util). Sündmuse allikas on objekt, mis teeb kindlaks mingi sündmuse toimumise ning teatab sellest kõigile objektidele, kes on registreerunud antud allika juures antud liiki sündmuste kuulajaks. Sündmuse sisuliseks tarbijaks ongi kuularobjekt, mis realiseerib liidese EventListener (paketist java.util) vastavat alamliidest. Kuulari saab luua kahel viisil: 1. realiseerides kõik antud liidese meetodid (näit. WindowListener liidese korral meetodid windowClosed, windowIconified, windowOpened, windowClosing, windowDeiconified, windowActivated, windowDeactivated) 2. spetsialiseerides olemasolevat adapteriklassi (need klassid realiseerivad vastavat liidest ning meil on tarvis tegelda ainult meile huvi pakkuvate sündmustega, näit. windowClosing, ning vastavad meetodid üle katta). Registreerumiseks peavad olemas olema nii allikas kui ka kuular. Seejuures võib sama sündmus saada töödeldud mitme erineva kuulari poolt (multicasting), iga kuular saab oma koopia sündmusest. .addListener (); Näit. class AknaAdapter extends WindowAdapter { public void windowClosing (WindowEvent e) { System.exit (0); } } ... raam.addWindowListener (new AknaAdapter()); Kuulariks on WindowAdapter alamklassi AknaAdapter objekt. Kui raam suletakse, siis saab kuular sellest teada ja käivitab ülekaetud windowClosing meetodi. Tihti kasutatakse siinkohal anonüümseid (ilma nimeta) klasse. Lisainfot sündmuse kohta saab sündmusest endast. Näit. antud juhul e.getComponent()annab objekti raam. Sündmustega seotud klasside hierarhia Event (awt: Java 1.0) EventQueue (awt) EventObject (util) AWTEvent (awt) ActionEvent (awt.event) AdjustmentEvent (awt.event) ItemEvent (awt.event) TextEvent (awt.event) ComponentEvent (awt.event) ContainerEvent (awt.event) FocusEvent (awt.event) WindowEvent (awt.event) PaintEvent (awt.event) InputEvent (awt.event) KeyEvent (awt.event) MenuKeyEvent (swing.event) MouseEvent (awt.event) MenuDragMouseEvent (swing.event) AncestorEvent (swing.event) <- AWTEvent (awt) InternalFrameEvent (swing.event) CaretEvent (swing.event) <- EventObject (util) ChangeEvent (swing.event) HyperlinkEvent (swing.event) ListDataEvent (swing.event) ListSelectionEvent (swing.event) MenuEvent (swing.event) PopupMenuEvent (swing.event) TableColumnModelEvent (swing.event) TableModelEvent (swing.event) TreeExpansionEvent (swing.event) TreeModelEvent (swing.event) TreeSelectionEvent (swing.event) UndoableEditEvent (swing.event) Paketi javax.swing.event sündmustest räägime hiljem. Liideste hierarhia EventListener (util) ComponentListener (awt.event) ContainerListener (awt.event) FocusListener (awt.event) KeyListener (awt.event) MouseListener (awt.event) MouseInputListener (swing.event) MouseMotionListener (awt.event) MouseInputListener (swing.event) WindowListener (awt.event) ActionListener (awt.event) Action (swing) AdjustmentListener (awt.event) ItemListener (awt.event) TextListener (awt.event) AncestorListener (swing.event) CaretListener (swing.event) DocumentListener (swing.event) InternalFrameListener (swing.event) DocumentEvent (swing.event) Adapteriklassid AWTEventMulticaster (awt) ComponentAdapter (awt.event) JViewport.ViewListener (swing) ContainerAdapter (awt.event) FocusAdapter (awt.event) KeyAdapter (awt.event) MouseMotionAdapter (awt.event) MouseAdapter (awt.event) ToolTipManager (swing) MouseInputAdapter (swing.event) WindowAdapter (awt.event) JMenu.WinListener (swing) InternalFrameAdapter (swing.event) Sündmuste allikad (awt) MenuComponent MenuItem <- Action CheckboxMenuItem <- Item Component <- Component Focus Key Mouse MouseMotion Button <- Action Checkbox <- Item Choice <- Item List <- Action Item Scrollbar <- Adjustment TextComponent TextArea <- Text TextField <- Action Text Container <- Container Window Dialog <- Window Frame <- Window Sündmused on siin jagatud nn. madaltaseme sündmusteks (Component, Focus, Input, Key, Mouse, MouseMotion, Container, Window) ja semantilisteks sündmusteks (Action, Adjustment, Item, Text) @ ComponentAdapter - componentHidden componentMoved componentResized componentShown @ ContainerAdapter - componentAdded componentRemoved @ FocusAdapter - focusGained focusLost @ KeyAdapter - keyPressed keyReleased keyTyped @ MouseAdapter - mouseClicked mouseEntered mouseExited mousePressed mouseReleased @ MouseMotionAdapter - mouseDragged mouseMoved @ WindowAdapter - windowClosed windowIconified windowOpened windowClosing windowDeiconified windowActivated windowDeactivated AWT - abstract windowing toolkit Liideseelemendid On kaht sorti liideseelemente: 1. AWT elemendid - nn. "rasked" elemendid, mida juhib operatsioonisüsteem 2. swing elemendid - nn. "kerged" elemendid, mida juhib java-masin Esialgu tutvume AWT elementidega. CheckboxGroup (awt) MenuComponent (awt) MenuBar (awt) MenuItem (awt) CheckboxMenuItem (awt) Menu (awt) PopupMenu (awt) MenuShortcut (awt) Component (awt) Button (awt) Canvas (awt) Checkbox (awt) Choice (awt) Label (awt) List (awt) Scrollbar (awt) TextComponent (awt) TextArea (awt) TextField (awt) Container (awt) Panel (awt) Applet (applet) JApplet (swing) ScrollPane (awt) Window (awt) Dialog (awt) FileDialog (awt) JDialog (swing) Frame (awt) JFrame (swing) Üldiselt on liideseelemendid Component klassi alamklasside esindajad (otseselt Component-klassi isendeid luua ei saa). Sellel klassil on hästi palju meetodeid, mille ülekatmisega saab liidese käitumist juhtida. Vt. paint, paintAll, repaint, update, setVisible, setSize, setBounds, setLocation, setFont, add...Listener, remove...Listener, is..., get..., dispatchEvent, createImage jpt. Konteinerid on elemendid, mis sisaldavad teisi elemente. Ka Container-klassi isendeid otseselt luua ei saa - kasutatakse alamklasse. Igal konteineril on paigutushaldur (ingl.k. layout manager), mis korraldab sisalduvate elementide paigutamist ekraanile. Olulised meetodid on add setLayout ja validate. Paneel (Panel) on levinud konteiner, mille vaikimisi paigutushalduriks on FlowLayout. Aken (Window) on konteiner, mille vaikimisi paigutushalduriks on BorderLayout. Aken on sündmuste WindowOpened ja WindowClosed allikaks. Aken saab (?) olla iseseisev paigutuse objekt operatsioonisüsteemis (nn. top-level window), paneel eeldab olemist millegi sees. Ka seda klassi ei kasutata tavaliselt otse, vaid alamklassides.Aknal pole ääri ega pealkirjariba, need lisanduvad klassis Frame. Raam (Frame) on aken, millel on pealkirjariba akna olekut kontrollivate nuppudega (sulgemine, ikoniseerimine, ...). Raami suurus on muudetav, ta on top-level window. Raam on kõigi aknasündmuste allikaks. Praktikas soovitatakse raami kasutada ülemise taseme "raske" konteinerina ning selle sees muu osa liidesest realiseerida "kergete" swing-komponentide abil. Vt. get... ja set... meetodid. Nupp (Button) on komponent, millel on tekst ja mis reageerib vajutustele (genereerib ActionEvent-sündmusi). Vt. addActionListener, getLabel, setLabel, getActionCommand, setActionCommand. Valikuruut (CheckBox) omab kaht olekut - "sees" (true) või "väljas" (false). Tavaliselt paigutatakse valikuruudud mingisse konteinerisse. Kui selleks konteineriks on CheckboxGroup, siis on lubatud täpselt ühe ruudu olekus "sees" olemine (nn. raadionupp). Vt. addItemListener, getLabel, getState, setLabel, setState, getCheckboxGroup, setCheckboxGroup ... Valik (Choice) lubab etteantud hulgast ühe elemendi valimist. Valik avaneb menüüna (suletud olekus on "peal" nähtav valitud element). Vt. addItemListener (NB! pole adapterit, ise üle katta itemStateChanged), addItem, getItemCount, getItem, getSelectedItem, select, insert, remove ... Nimekiri (List) on sarnaste funktsioonidega, aga valikud antakse keritavas aknas, kust on lubatud ka mitmene valik (getSelectedItems). Lisandub addActionListener , et signaliseerida lõpliku valiku tegemisest (actionPerformed-meetod). Silt (Label) on komponent, mis lubab näidata üht rida teksti, mida ei saa redigeerida. Vt. getText, setText ... Tekstikomponentidel (TextComponent alamklassidel) on meetodid addTextListener (kuularis vajalik katta meetod textValueChanged), removeTextListener, getText, setText, getCaretPosition, setCaretPosition, getSelectedText, getSelectionStart, setSelectionStart, getSelectionEnd, setSelectionEnd, select, selectAll, setEditable, isEditable ... Sisestusväli (TextField) on tekstikomponent, mis lubab sisestada üherealist teksti. Sisestusvälja korral genereeritakse ActionEvent, kui kasutaja lõpetab sisestamise. Leiduvad meetodid sisestusvälja suurusega tegelemiseks, samuti saab teha paroolivälju. Sisestusaken (TextArea) on tekstikomponent, mis lubab ka mitmerealist teksti. Vastavalt on olemas meetodid akna suurusega tegelemiseks ja vahendid kerimiseks. Vt. insert, append, replaceRange ... Dialoog (Dialog) on aken (seega ka konteiner, aga alternatiiv raamile), mille vaikimisi paigutushalduriks on BorderLayout ning mis on sündmuste windowClosed, windowOpened, windowClosing, windowActivated, windowDeactivated allikaks. Dialoog peab paiknema raamis. Nn. modaalne dialoog blokeerib sisestuse muudesse akendesse (kui võimalik, siis vältige seda!). Vt. show, setModal, isModal, getTitle, setTitle ... Tegelikud reaktsioonid jms. tuleb programmeerida sisemistes komponentides. Menüüde tegemiseks on eraldi MenuComponent klasside hierarhia (nimetatu ise on abstraktne klass). MenuItem on kasutusel selleks, et tekitada menüüdesse valikuid. Et Menu on MenuItem alamklass, siis saab teha kaskaadmenüüsid. Menüü (Menu) meetodeid: add, addSeparator, getItemCount, getItem, insert, remove ... Menüüvalik (MenuItem) genereerib ActionEvent (seega vajalik ActionListener). Menüüvalikuid saab keelata: setEnabled ja olekut küsida: isEnabled. Vt. ka get/setActionCommand, get/setLabel, get/setShortcut. MenuShortcut on eraldi klass Object alluvuses, mille abil menüüvalikutele saab vastavusse seada klahvikombinatsioone. Menüüriba (MenuBar) lubab panna hulga menüüsid samale ribale (eraldi veel help-menüü) ja neid hallata. CheckboxMenuItem on menüüvalik, milles omakorda saab suhelda valikuruuduga: setState, getState, addItemListener ... PopupMenu on menüü alamklass hüpikmenüü tegemiseks. Kehtivad Menu meetodid pluss show (analoogiliselt dialoogile). Siiski ei ole see aken top-level, vaid hüpikmenüü on piiritletud mingi ülemkomponendiga. Kanvaa (lõuend) (Canvas) on komponent, mis esindab ristkülikukujulist piirkonda ja lubab joonistamist, kui luua vastav alamklass ja katta seal üle paint(Graphics g)-meetod. Tegelikult toimub see töö Graphics-meetoditega. swing analoog puudub (kasutatakse vahel JPanel). ScrollPane on konteiner, millesse võib pakkida ühe komponendi (addImpl-meetod), et varustada see kerimisribadega. Säästab vaeva ja lubab meid selles loengus mitte tegelda kerimise probleemidega madaltasemel. Paigutushaldurid Konteinerid kasutavad sisu kuvamiseks paigutushalduri abi. Et nad saaksid oma tööd teha, on komponentidele võimalik määrata nende "eelistatud suurust". Tegelikult on võimalik ka üldse ilma paigutushaldurita läbi ajada (setBounds), aga see pole soovitatav. BorderLayout - paigutatakse vastavalt n.-ö. ilmakaartele: "North", "South", "East", "West", "Center" (add-meetodi parameeter). Saab paigutada kuni 5 komponenti. FlowLayout - saab paigutada piiramata arvu komponente. Komponendid paigutatakse vasakult paremale, vajadusel ridade kaupa ülalt alla (vastavalt add-pöördumiste järjekorrale). GridLayout - paigutatakse maatriksisse (ridade ja veergude arvu saab ette anda, ühe võib ka vabaks jätta) nii, et lahtrid on ühesuurused. Täitmine käib ridade kaupa vasakult paremale. CardLayout - näitab ühe komponendi ("kaardi") korraga. Hulk meetodeid majandamiseks. GridBagLayout - komponent võib hõlmata maatriksist mitu lahtrit. Kasutab GridBagConstraints-klassi. Pisut keerulisem, aga väidetavalt üsna universaalne. Praktikas on hea võimalus kombineerida erinvaid paigutusi üksteisesse sisestatud konteinerite abil (selleks kasutatakse tavaliselt paneele).