8. GRAFICKÉ UŽIVATELSKÉ ROZHRANÍ Abstract Window Toolkit (AWT) je část Java Core API, kterou tvoří balíky:
java.awt, java.awt.event (od JDK 1.1), java.awt.image, java.awt.datatransfer (od JDK 1.1).
AWT umožňuje tvorbu grafického uživatelského rozhraní (GUI), tj. práci se vstupy a výstupy v graficky orientovaných systémech (Windows 95/NT, X Window). Programy využívající AWT jsou v duchu jazyka Java plně přenositelné, ale zároveň je ovládání a vzhled jednotlivých prvků GUI, komponent, přizpůsobeno zvyklostem konkrétního systému.
KOMPONENTY GUI programu tvoří komponenty. Strom tříd komponent v java.awt vypadá takto:
Component o Button o Canvas o Checkbox o Container Panel java.applet.Applet ScrollPane Window Dialog o FileDialog Frame o Label o List o Scrollbar o TextComponent TextArea TextField
Nejdůležitější jsou rodičovské třídy komponent a kontejnerů: Abstraktní třída Component definuje metody pro zobrazení grafické komponenty a zpracování a zasílání událostí. Abstraktní třída Container definuje metody pro přidávání, odebírání a manipulaci s komponentami - instance potomků této třídy mohou vlastnit další komponenty.
Způsob rozložení komponent v kontejneru určují layout managery - instance tříd:BorderLayout, CardLayout, FlowLayout, GridBagLayout,GridBagConst raints, GridLayout. Samozřejmě je možné si navrhnout vlastní manažer. Činnost programu využívajícího komponenty je následující: program vytvoří kontejner , do kterého následně může přidávat další komponenty. Při vykreslování se postupuje shora dolů; pořadí vykreslování komponent na stejné úrovni není definováno. Program reaguje na pokyny uživatele tím, že jednotlivé komponenty zachycují události (vstupy z klávesnice a myši) a na základě nich se vykonává další činnost.
ZPRACOVÁNÍ UDÁLOSTÍ Způsob předávání a zpracování událostí se v JDK 1.1 zásadně liší od JDK 1.0, neboť starý způsob byl "shledán těžkopádným". Kombinování obou způsobů se nedoporučuje. Kromě akcí, které uživatel vyvolává přímo (pohyb myši, stisk klávesy) se za událost považuje i například otevření okna, výběr položky v menu apod. JDK 1.0 - pokud nastane libovolná událost, vytvoří se instance třídy java.awt.Event. Tato instance se propaguje zdola nahoru hierarchií komponent, počínaje komponentou, nad níž událost nastala - u každé komponenty se volá metoda handleEvent() s parametrem instance události. JDK 1.1 - o nastalé události jsou informovány jen ty objekty (nemusí jít pouze o komponenty), které o to požádají (zaregistrují se). O jedné události (instanci třídy java.util.EventObject) může být informováno i více objektů nebo také žádný. Události se dělí do několika tříd definovaných v balíku java.awt.event:
ActionEvent - nastane při stisku tlačítka apod., KeyEvent - nastane při stisku klávesy, MouseEvent - nastane při pohybu myši, stisknutí tlačítka myši apod., WindowEvent - nastane při otevření, zavření okna apod. ...
VÝSTUP GRAFIKY Grafický kontext neboli objekt, pomocí kterého je možné provádět grafický výstup, reprezentují instance třídy java.awt.Graphics. Tato třída definuje metody pro kreslení grafických primitiv (čára - drawLine(), ovál - drawOval(), polygon - drawPolygon() apod.), výstup textu -drawString(), vykreslení obrázku - drawImage() atd.
Grafický kontext má přiřazen každá zobrazená komponenta - výstup do jejího kontextu se provádí v metodách update(java.awt.Graphics g) a paint(java.awt.Graphics g). Manipulaci s obrázky (včetně načítání formátu balíku java.awt.image a třída java.awt.Image.
GIF
a
JPEG)
slouží
třídy
z
Příklad Následující program demonstruje použití AWT. Obsahuje dvě komponenty: plátno (potomka třídyjava.awt.Canvas), které umožňuje kreslení pomocí myši, a tlačítko "Clear", které plátno vymaže. Program funguje jako applet i jako aplikace. Události zpracovává s využitím modelu. package demo; import java.applet.Applet; import java.awt.event.*; import java.awt.*; /** * Hlavní třída programu SimpleDraw . * @author Petr Toman * @version JDK 1.1 */ public class SimpleDraw extends java.applet.Applet { /** * Metoda init() se volá, je-li program spuštěn jako applet. * @see java.awt.Frame * @see java.awt.Button * @see java.awt.Canvas */ public void init() { // vytvoření plátna -- plochy pro kreslení PaintCanvas paintCanvas = new PaintCanvas(); // vytvoření tlačítka s nápisem "Clear" Button button = new Button("Clear"); // registrace plátna jako příjemce události při stisku tlačítka button.addActionListener(paintCanvas); // nastavení layout manageru setLayout(new BorderLayout()); // vložení plátna a tlačítka "Clear" do appletukontejneru add(paintCanvas, "North"); add(button, "South"); }
/** * Metoda main() se volá, je-li program spuštěn jako aplikace. * Provádí totéž, co init() , pouze nejprve vytvoří okno ( frame ), * do kterého umisťuje komponenty. * @param args parametry příkazové řádky (nepoužito) */ public static void main(String[] args) { Frame frame = new Frame("SimpleDraw"); PaintCanvas paintCanvas = new PaintCanvas(); Button button = new Button("Clear"); button.addActionListener(paintCanvas); frame.add(paintCanvas, "North"); frame.add(button, "South"); frame.pack(); frame.show(); } } /** * Třída sloužící pro vytvoření plátna. Zachycuje události "pohyb myši" * a "stisk tlačítka" -- proto implementuje uvedená rozhraní. * @see java.awt.event.MouseMotionListener * @see java.awt.event.ActionListener */ public class PaintCanvas extends Canvas implements MouseMotionListener, ActionListener { Graphics offGraphics; // skrytý grafický kontext Image offImage; // skrytý obrázek (buffer) int oldx, oldy; // "staré" souřadnice myši /** Konstruktor */ public PaintCanvas() { // nastavení barvy pozadí na bílou setBackground(Color.white); // registrace sebe ( this ) jako příjemce události "pohyb myši" addMouseMotionListener(this); } /** * Metoda getMinimumSize() musí být implementována kvůli * určení velikosti pro layout manager. * @return minimální velikost komponenty (plátna). */ public Dimension getMinimumSize() { return new Dimension(300,200);
} /** * Metoda getPreferredSize() musí být implementována kvůli * určení velikosti pro layout manager. * @return preferovanou velikost komponenty (plátna). */ public Dimension getPreferredSize() { return getMinimumSize(); } /** * Metoda mouseDragged() je volaná při pohybu a současném držení * tlačítka myši. */ public void mouseDragged(MouseEvent e) { // je-li možno provádět výstup, vykreslí čáru if (offGraphics != null) offGraphics.drawLine(oldx, oldy, e.getX(), e.getY()); // uschování souřadnic myši oldx = e.getX(); oldy = e.getY(); // překreslit plátno! repaint(); } /** * Metoda mouseMoved() je volaná při pohybu myši (bez stisku tlačítka). */ public void mouseMoved(MouseEvent e) { // uschování souřadnic myši oldx = e.getX(); oldy = e.getY(); } /** * Metoda actionPerformed() je volaná stisku tlačítka "Clear". */ public void actionPerformed(ActionEvent e) { // zrušení skrytého bufferu (bude provedeno vymazání) offImage = null; // překreslit plátno! repaint(); }
/** * Metoda update() je volána při překreslování komponenty. * Standardně vymaže pozadí a volá metodu paint() . * Je předefinována, aby nedocházelo k blikání. */ public void update(Graphics g) { paint(g); } /** * Metoda paint() provádí vykreslení obsahu plátna -překopíruje * skrytý buffer do grafického kontextu komponenty ( parametr g ). */ public void paint(Graphics g) { int width = getSize().width; int height = getSize().height; if (offImage == null) { // vytvoření prázdného bufferu offImage = createImage(width, height); offGraphics = offImage.getGraphics(); } // nastala změna velikosti komponenty? if (offImage.getWidth(this) != width || offImage.getHeight(this) != height) { // ano - vytvořit skrytý buffer aktuální velikosti... Image img = createImage(width, height); offGraphics = img.getGraphics(); // ... a zkopírovat starý buffer offGraphics.drawImage(offImage,0,0,this); offImage = img; } // zobrazení bufferu do grafického kontextu komponenty g.drawImage(offImage,0,0,this); } } Pro applet je třeba vytvořit HTML dokument, který obsahuje text: <APPLET CODE = demo.SimpleDraw.class WIDTH = 300 HEIGHT = 230>