Graafikakomponendi loomine Omatehtud jooniste ning komponentide aluseks sobib lõuend (Canvas). Ta sobib lihtsaks joonistamiseks, kuid samas saab ta panna ka teateid vastu võtma, s.t. näiteks hiirevajutusele reageerima. Kui oled kord komponendi loonud, siis saad seda tervikuna kasutada seal kus parajasti vaja on. Kui oled komponendi tööga rahul, siis võid tarvitada teda ilma sisemisse ehitusse süvenemata. Alati ei pea komponendi loomisel kõike otsast tegema, vaid võib kasutada juba varem olemas olevaid tükke. Samuti võib luua varemvalmistatud komponendile alamklassi ning seal soovitud meetodid muuta. Nii võib kerge vaevaga lisada tekstialale võimaluse, et ta väljastaks oma sees oleva ridade arvu või paneks lisatavatele ridadele tühikud ette. Kui aga tahetakse sündmused ja kujundused täiesti ise määrata, siis tuleb aluseks võtta tühi pind ehk lõuend. Siin näites joonistatakse lõuendile soovitud nurkade arvuga hulknurk. Nurkade arvu saavad väljapoolsed muuta vaid meetodi abil. Iga muutmisega kaasneb uus joonistamine. import java.awt.*; public class Nurgad extends Canvas{ protected int nurkadearv; public Nurgad(){ nurkadearv=3; } public Nurgad(int uusarv){ nurkadearv=uusarv; } public void muudaNurkadeArv(int uusarv){ nurkadearv=uusarv; repaint(); } public void paint(Graphics g){ int korgus=getSize().height; int laius=getSize().width; double nurgavahe=2*Math.PI/(double)nurkadearv; int raadius=Math.min(korgus, laius)/3; int keskx=laius/2; int kesky=korgus/2; int vanax=keskx; int vanay=kesky+raadius; int uusx, uusy; for(int i=1; i<=nurkadearv; i++){ uusx=keskx+(int)(raadius*Math.sin(i*nurgavahe)); uusy=kesky+(int)(raadius*Math.cos(i*nurgavahe)); g.drawLine(vanax, vanay, uusx, uusy); vanax=uusx; vanay=uusy; } } } Loodud komponenti saab kasutada seal, kus vaja hulknurki joonistada. Siin näites pannakse rakendi ekraanile üheksa hulknurka, nurkade arvuga kolmest üheteistkümneni. import java.applet.Applet; public class Nurgarakend extends Applet{ public void init(){ setLayout(new java.awt.GridLayout(3, 3)); for(int nr=3; nr<12; nr++){ add(new Nurgad(nr)); } } } Samuti saab loodud komponendi abil lasta kasutajal valida, mitme nurgaga hulknurka soovib. Selleks panin rakendile kerimisriba ning loodud komponendi. Rakendi panin kerimisriba kuulajaks (AdjustmentListener). Kui kerimisriba määratud koha väärtust muudetakse, siis saadetakse uus väärtus rakendile, kes selle omakorda saadab hulknurka joonistavale komponendile. import java.applet.Applet; import java.awt.*; import java.awt.event.*; public class Nurgarakend2 extends Applet implements AdjustmentListener{ Nurgad ng=new Nurgad(); Scrollbar sb=new Scrollbar( Scrollbar.VERTICAL, 3, 2, 2, 20 ); public void init(){ setLayout(new BorderLayout()); add("West", sb); add("Center", ng); sb.addAdjustmentListener(this); } public void adjustmentValueChanged(AdjustmentEvent e){ ng.muudaNurkadeArv(e.getValue()); } } Graphics2D Põhilised joonistamisfunktsioonid on klassis java.awt.Graphics. Alates versioonist 1.2 pakub laiendatud joonistamisvõimalusi eelmise alamklass Graphics2D. Kui esimesel juhul tuli alati arvutada ekraanikoordinaatides ning joone laiuseks oli üks punkt, siis siin võib valida omale sobiva taustsüsteemi ning ka joonistamisel saab enam parameetreid määrata. Kuna Graphics2D on klassi Graphics alamklass, siis ta oskab kõike mida eellanegi ning vajadusel saab temaga joonistada samade meetoditega, mis klassist Graphics omale sisse harjunud. Ühilduvuse huvides on komponendi meetodi paint parameetriks endiselt Graphics, kuid tegelikult antakse sellesse meetodisse joonistamiseks isend, kes suudab ka Graphics2D klassis kirjeldatud operatsioone täita. Juhul, kui spetsiifilisi omadusi vajatakse, tuleb muutuja tüüp enne teisendada. Joone omadused Joone tõmbamisel saab Graphics2D juures klassi BasicStroke abil määrata joone laiust, otsa kuju ning kahe joone ühendust (võimalused leiad API dokumetatsioonist). import java.awt.*; public class Joon1 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; float laius=15; int jooneots=BasicStroke.CAP_ROUND; int uhendus=BasicStroke.JOIN_BEVEL; g.setStroke(new BasicStroke(laius, jooneots, uhendus)); g.drawRect(10, 10, 70, 100); g.drawLine(100, 10, 140, 200); } } Joonistusala piiramine Joonistamisala on võimalik piirata käsuga clip, andes ette kujundi, mille piires tohib joonistada. Siin näites määratakse joonistamise alaks ellipsi pind ning seejärel joonestatakse seest täidetud ristkülik. Tulemusena tekib ekraanile vaid ellipsi ning ristküliku ühisosa. import java.awt.*; import java.awt.geom.*; public class Kujund1 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; Shape kujund=new Ellipse2D.Float(10, 10, 300, 100); g.clip(kujund); g.fillRect(20, 20, 400, 60); } } Venitamine, keeramine Joonistuspinda saab liigutada, venitada ja keerata. AffineTransform'i abil saab määrata, kuidas ja kui palju. Esimese näite puhul lükatakse koordinaatide alguspunkti saja ühiku võrra paremale ning alla. import java.awt.*; import java.awt.geom.AffineTransform; public class Transform2 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; g.setTransform(AffineTransform.getTranslateInstance(100, 100)); g.fillRect(20, 20, 40, 20); } } rida g.setTransform(AffineTransform.getScaleInstance(3, 1.5)); suurendab joonist x-telje suunas 3 ning y-suunas 1,5 korda. g.setTransform(AffineTransform.getRotateInstance(Math.PI/4, 100, 75)); keerab joonist Pi/4 ehk 45 kraadi võrra ümber punkti 100, 75 g.setTransform(AffineTransform.getShearInstance(Math.PI/4, 0)); keerab püsttelge Pi/4 võrra. Kui soovida mitut muutust üheskoos, siis võib luua AffineTransform tüüpi isendi ning talle soovitud muutusi järjekorras rakendada. import java.awt.*; import java.awt.geom.AffineTransform; public class Transform6 extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; AffineTransform tr=new AffineTransform(); tr.rotate(Math.PI/4, 50, 100); tr.translate(150, 0); g.setTransform(tr); g.fillRect(20, 20, 40, 20); } } Muster, värviüleminek Joonistamisel saab lisaks ühele värvile soovi korral pinda katta ka nii värviülemineku kui piltidest koostatud mustriga. Soovitud katmisstiil tuleb määrata Graphics2D meetodiga setPaint. Värviülemineku andmeid kannab GradientPaint. Konstruktoris tuleb määrata kaks punkti ning kummagi punkti juurde kuuluv värv. Nendes punktides vastab joonise värv sinna määratud värvile, punkte ühendaval sirget mööda muutub värv sujuvalt ühest värvist teiseks. Tavajuhul jääb kummagi punkti "selja taha" punktile vastav värv, kuid kui lisada konstruktorisse tõeväärtusmuutuja, siis saab panna värvi tsükliliselt lainetama nii, et laine pikkuseks jääb kahe punkti vahe. import java.awt.*; import java.awt.geom.*; public class Kujund2a extends Canvas{ public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; g.setPaint(new GradientPaint(0, 100, Color.yellow, getSize().width, 100, new Color(0, 200, 100) )); g.fillRect(0, 0, getSize().width, getSize().height); } } Pinna mustriga katmisel tuleks kasutada klassi TexturePaint võimalusi, andes konstruktorile parameetriks pildi millega katta, lisaks ka pildi suuruse ja asukoha, millest alates pilte kõrvuti laduda. Kujundi äärejooned Kujundi (näiteks ellipsi) äärejooned annab BasicStroke meetod createStrokedShape. Nii näiteks on võimalik kujundist vaid äärejooned välja joonistada või siis teise värviga esile tuua. public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; BasicStroke b1=new BasicStroke(15); Shape kujund=b1.createStrokedShape( new Ellipse2D.Float(100, 100, 50, 70) ); g.fill(kujund); g.setColor(Color.green); g.draw(kujund); } Kuna nii ellips on kujund ning ka jämedajoonelise ellipsi äärejooned on samuti kujundid, siis juhul, kui annan äärejoontele jämeduse, võin ka nendelt omakorda äärejooned küsida. Nii saan tulemuseks juba neli joont: kaks üksteisele lähedal asuvat ovaali sees ning teised kaks ovaali välisringis. public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; BasicStroke b1=new BasicStroke(15); BasicStroke b2=new BasicStroke(3); Shape kujund=b1.createStrokedShape( new Ellipse2D.Float(100, 100, 50, 70) ); Shape kujund2=b2.createStrokedShape(kujund); g.draw(kujund2); } Kui sooviksin nende joontega midagi eraldi teha, näiteks neid igaüht isevärvi värvida, siis on mul võimalik kujund joonteks jagada klassi PathIterator abil. Selle abil saan kätte iga joone andmed. Sirgjoonel piisab kahest punktist. Kolme punkti abil määratakse kõverjoon, kus kaks punkti on otspunktideks ning kolmas näitab, milline peab kaar tulema. Nelja punktiga määratud joone puhul on samuti kaks otspunktideks, ülejäänud kahe punkti abil aga määratakse joone suunda otspunktist väljumisel. Uusi kujundeid aitab kombineerida klass GeneralPath. Talle tuleb lihtsalt öelda millise koha peale joon või ring või muu olemasolev kujund paigutada. Kriipsujuku saab tema abil küllalt kergesti valmis ning siis võib seda kasutada nagu iga muud kujundit. public void paint(Graphics alggr){ Graphics2D g=(Graphics2D)alggr; GeneralPath gp=new GeneralPath(); gp.append(new Ellipse2D.Float(20, 50, 40, 40), false); gp.append(new Line2D.Float(40, 100, 40, 150), false); g.draw(gp); } Pilditöötlus Image on java jaoks nii väljastpoolt failist võetud kui ise joonistatud pilt. Tühja pildi joonistamiseks saab luua meetodi createImage abil. Image osutab pildi andmetele, tema kaudu saab pilti kusagil näidata. Pildi muutmiseks tuleb pildilt küsida klass Graphics (või tema alamklass Graphics2D). Selle nn. graafilise konteksti juures on meetodid, mille abil saab pildile midagi (juurde) joonistada. Valmis pilti kuhugile joonistades saab määrata tema kõrgust ja laiust, Graphics2D abil ka keerata või venitada. Võib mitmest pildist ühe kokku kombineerida ning sinna vajadusel jooni, ringe ja muid kujundeid juurde joonistada. Keerulisemate kujundite loomisel on kiiremaks mooduseks ta mälus punkti kaupa välja arvutada ning siis loodud massiivist pilt luua. Nii saab näiteks värviüleminekute juures ilusti igale punktile värvi arvutada ning hoolitseda, et ükski punkt värvita ei jääks. Pilti arvudeks muutes saab pildi andmed näiteks faili salvestada või Interneti kaudu teisele kasutajale saata. Ka on selle abil võimalik pilti analüüsida. Kui pildi käest andmed küsida ning pärast nende muutmist andmetest uus pilt luua, siis saab pilti päris mitut moodi mõjutada. Võib ühe värvi teisega asendada, kujundite piirpindu silendada või teravdada. Suurema mõttetöö korral ka olemasolevast pildist kujundeid eraldada ning nendega omaette midagi ette võtta (näiteks raamatust kopeeritud pildist teksti välja lugeda). Animatsiooni puhul on mõistlik uus ekraanipilt enne mälus valmis teha ning alles siis ekraanile joonistada. Sellisel juhul ei hakka pilt uue kujundi loomise ajal vilkuma. Animatsioon võtab suhteliselt palju ressursse, kuid võtete abil saab liikumist näidata ka aeglasema arvuti peal. Kui taust püsib paigal ning vaid esiplaani kujund liigub, siis piisab tausta korra valmistamisest ning iga uue pildi loomiseks joonistada taust alla ning kujund sobivasse kohta peale. Veelgi enam: piisab, kui taust joonistada vaid selle osa peale, kus liikuv kujund viimati oli (meetod clip laseb määrata, millisesse pildi piirkonda joonistada, mujale suunatud joonistuskäsud jäävad täitmata). Kui liikumine piirdub vaid mõne(teistkümne) pildi vahetamisega, siis on mõistlikum pildid enne välja arvutada/joonistada ning siis ükshaaval ringis vahetada. Kopeerimine Programmide sees ning ka programmide vahel kasutatakse andmete vahetamiseks mälupuhvrit (clipboard). Sinna saab andmeid paigutada ning sealt vajadusel kopeerida. Kui puhver on operatsioonisüsteemi juures ning sinna pääsevad ligi mitmed programmid, siis saab selle abil nende vahel andmeid vahetada. Et andmeid sobiksid, peavad osapooled aru saama andmete formaadist. Kõige lihtsamaks formaadiks on lihtne tekst, kuid selle kaudu saab kõike vahetada, mida on võimalik baitideks muundada. Järgnevast näitest suurem osa kulub kujundusele, kus luuakse raam, pannakse sinna sisse tekstiväli, tekstiala ning menüü. Kopeerimine ja kleepimine asub meetodis actionPerformed, mis käivitub menüüst valiku tegemisel. Vastavalt menüürea nimele käivitatakse tegevus. Meetodi algul küsitakse juurdepääs operatsioonisüsteemi mälupuhvrile. Clipboard clipboard = getToolkit().getSystemClipboard(); Kui antakse korraldus Copy, siis võetakse tekstiväljast tekst ning muudetakse ta StringSelection'iks. Viimatinimetatud klassis on tekst kujul, mida saab mälupuhvrisse panna ning mida teised programmid lugeda mõistavad. StringSelection data = new StringSelection(tf.getText()); Seejärel öeldakse, et mingu see tekst mälupuhvrisse. Meetodi teiseks parameetriks on ClipboardOwner, kellele saadetakse teade puhvri sisu vahetumisest. clipboard.setContents(data, data); Kleepimise puhul võetakse teade mälupuhvrist välja ning pannakse ta tekstialasse. Puhvrist saadakse andmed kätte esialgu tüübina Transferable, mis tuleb seejärel sobivaks tüübiks muundada. Transferable käest on võimalik küsida millisel kujul ta andmeid kannab. Siin aga eeldame, et tegemist on sõnega ning palume tal sellisena need andmed ka välja anda. Transferable clipData = clipboard.getContents(this); String s = (String)(clipData.getTransferData(DataFlavor.stringFlavor)); Tulemuseks on programm, mille abil saab andmeid tekstina programmide vahel vahetada. Selgitust vajab ka ehk menüü loomine. Algul luuakse menüüriba (MenuBar), sinna külge pannakse menüü(d) (Menu) ning viimasesse menüüread (MenuItem). Menüüridadele öeldakse, kellele nende peale vajutamisel teateid saata. import java.io.*; import java.awt.*; import java.awt.datatransfer.*; import java.awt.event.*; public class ClipMe extends Frame implements ActionListener { TextField tf; TextArea ta; public static void main (String args[]) { new ClipMe().show(); } public ClipMe() { super("Clipping Example"); add(tf = new TextField("Welcome"), "North"); add(ta = new TextArea(), "Center"); MenuBar mb = new MenuBar(); mb.add(makeEditMenu()); setMenuBar(mb); setSize(250, 250); } Menu makeEditMenu() { Menu editMenu = new Menu("Edit"); MenuItem mi = new MenuItem("Cut"); mi.addActionListener(this); editMenu.add(mi); mi = new MenuItem("Copy"); mi.addActionListener(this); editMenu.add(mi); mi = new MenuItem("Paste"); mi.addActionListener(this); editMenu.add(mi); mi = new MenuItem("Clear"); mi.addActionListener(this); editMenu.add(mi); return editMenu; } public void actionPerformed (ActionEvent evt) { Clipboard clipboard = getToolkit().getSystemClipboard(); String cmd = evt.getActionCommand(); if (cmd.equalsIgnoreCase("copy")) { StringSelection data = new StringSelection(tf.getText()); clipboard.setContents(data, data); } else if (cmd.equalsIgnoreCase("clear")) { tf.setText(""); } else if (cmd.equalsIgnoreCase("paste")) { Transferable clipData = clipboard.getContents(this); String s; try { s = (String)(clipData.getTransferData(DataFlavor.stringFlavor)); } catch (Exception e) { s = e.toString(); } ta.setText(s); } else if (cmd.equalsIgnoreCase("cut")) { StringSelection data = new StringSelection(tf.getText()); clipboard.setContents(data, data); tf.setText(""); } } } Andmete vedamine (Drag and Drop) Lisaks mälupuhvri abil kopeerimisele püütakse andmete ülekannet ka hiirega vedamise abil kasutajale intuitiivsemaks muuta. Enamik meist on tõenäoliselt hiirega Word'i redaktoris sõnu lauses ringi tõstnud või Windows Exploreri aknas faile ühest kataloogist teise lohistanud. Andmete allikaks või suudmeks saab määrata ükskõik millise komponendi, kes on võimeline hiire teateid vastu võtma. Komponendile tuleb määrata sündmus, mille peale ta end andmete allikaks loeb. Sageli on selleks näiteks hiire vajutus ning lohisemine tema peal vähemalt viie punkti ulatuses. Kui andmed on kord liikuma pandud, saab nende "käekäigu" üle teateid andmeveo kuulari abil, kes teatab hiire sattumisest võimaliku vastuvõtja alasse. Andmete vastuvõtjalgi on kuular. Tema saab teateid enesele sattunud andmetega varustatud hiirest ning on võimeline vastavalt nendele teadetele käituma. Ta saab võrrelda pakutavat andmete tüüpi enese poolt vastu võtta suudetavate andmetüüpidega ning sellest kasutajale teadma andma. Kui hiire klahv lastakse vastuvõtja kohal lahti, siis saabub teade drop ning andmed võib vastu võtta. Siin näites luuakse raam kolme sildiga. Ülemised kaks on andmete allikaks ning nende siltide pealt vedama hakkamisel kaasneb andmetena sildi peal olev kiri. Kolmas silt on vastuvõtja. Kui selle peal vabastakse andmeid kandva kursoriga hiire klahv, siis jääb saabunud tekst sildi sisse. Nii allika kui suudme olen loonud sildi alamklassina. AndmeveoAlguseKuularis on kirjas, mida tuleb teha, kui DragSource poolt loodud DefaultDragGestureRecognizer on märganud, et sildi pealt hakatakse andmeid vedama. Sel puhul võetakse sildi tekst, muutetakse ta Transferable tingimustele vastavaks StringSelection'iks, et teda saaks üle kanda ning siis käivitatakse vedu käsuga startDrag. Parameetriteks on vedamise ajal näidatav kursor, kantavad andmed ning kuular, kellele saadetakse teated andmetega teel toimuva kohta. Suudmel on isend DropTarget, kelle poolt loodud AndmeteSaabumiseKuular saabuvate andmetega tegeleb. Kui suudme kohal lastakse andmehulk, saab ta selle tüüpide sobivuse korral vastu võtta. Esialgu küsitakse meetodi parameetrilt Transferable-tüüpi andmed, sealt oodatud kujul Objectina ning lõpuks tuleb nad kasutatavale kujule muudada. Siis võib nendega edasi toimida, siin näites andmete sees paiknev tekst oma sildile paigutada. import java.awt.*; import java.awt.dnd.*; import java.awt.datatransfer.*; public class Allikas extends Label { private DragSource dragSource; public Allikas(String s) { setText(s); dragSource = DragSource.getDefaultDragSource(); dragSource.createDefaultDragGestureRecognizer( this, DnDConstants.ACTION_COPY, new AndmeveoAlguseKuular()); } class AndmeveoAlguseKuular implements DragGestureListener { public void dragGestureRecognized(DragGestureEvent e) { Transferable andmed = new StringSelection( getText() ); e.startDrag(DragSource.DefaultCopyDrop, andmed, new AndmeveoKuular()); } } class AndmeveoKuular implements DragSourceListener { public void dragDropEnd(DragSourceDropEvent e) { } public void dragEnter(DragSourceDragEvent e) { } public void dragOver(DragSourceDragEvent e) { } public void dragExit(DragSourceEvent e) { } public void dropActionChanged (DragSourceDragEvent e) { } } } import java.awt.*; import java.awt.dnd.*; import java.awt.datatransfer.*; import java.io.*; public class Suue extends Label { private DropTarget dropTarget; public Suue(String s) { setText(s); dropTarget = new DropTarget(this, DnDConstants.ACTION_COPY, new AndmeteSaabumiseKuular(), true); } class AndmeteSaabumiseKuular implements DropTargetListener { public void dragOver(DropTargetDragEvent e) { } public void dropActionChanged(DropTargetDragEvent e) { } public void dragExit(DropTargetEvent e) { } public void dragEnter(DropTargetDragEvent e) { } public void drop(DropTargetDropEvent e) { try{ e.acceptDrop(DnDConstants.ACTION_COPY); Object data = e.getTransferable(). getTransferData(DataFlavor.stringFlavor); setText(data.toString()); }catch(Exception ex){ ex.printStackTrace(); } } } } import java.awt.*; public class Vedamine{ public static void main(String argumendid[]){ Frame f=new Frame("Andmeveo raam"); f.setLayout(new GridLayout(3, 1)); f.add(new Allikas("Karu")); f.add(new Allikas("Rebane")); f.add(new Suue("Vea siia!")); f.setSize(200, 100); f.setVisible(true); } } Swing Lisaks kümnekonnale paketis java.awt asuvale komponendile saab kasutajaga suhtlemiseks kasutada ka paketi javax.swing graafilisi komponente. Nagu eelpool graafikakomponentide peatükis kirjeldatud, palutakse awt-komponendid joonistada operatsioonisüsteemil, swing-komponente joonistatakse Java vahenditega. Sellest tulenevalt näevad esimesed välja nii nagu vastavas operatsioonsiüsteemis tavaks, swingi nupp või silt aga on igal pool tavajuhul peaaegu ühesugune. UIManageri abil aga on võimalik panna ka swing-komponente vastavalt operatsioonisüsteemile välja nägema. Swingi graafikakomponendid algavad tähega J. Tõenäoliselt seetõttu, et neid oleks kerge eristada analoogilistest awt komponentidest. Järgnevas näiteks on raamiks JFrame, selle sees on silt JLabel ning nupp JButton. Nii nupule kui sildile (ja ka mitmetele muudele komponentidele) saab tema ilmestamiseks määrata ikooni. ImageIcon loob ikooni kasutades aluseks pildifaili, kuid vajadusel saab ikooni ka käskude abil joonistada. Kõikidele swingi komponentidele saab määrata ToolTipText'i. Seda näidatakse ekraanile juhul, kui kasutaja on hiirega vastava komponendi peale liikunud. Enamasti vastav tekst seletab komponendi otstarvet või annab kasutajale tegutsemissoovitusi. Korraldus setMnemonic lubab klahvikombinatsiooni (Alt + täht) võrdsustada hiirega nupule vajutamisele. Komponentide raami lisamisel tuleb swingi puhul määrata, millisesse kihti ta paigutada. Harilikult kasutatava alumise kihi saab kätte getContentPane() abil. Pealmist kihti nimetatakse GlassPane ning vahepealsetesse kihtidesse paigutamiseks saab kasutada LayeredPane vahendeid. Kihtidega mängides saab komponente mitmesse kihti paigutada. import java.awt.*; import javax.swing.*; public class Pildid{ public static void main(String argumendid[]){ JLabel silt=new JLabel("Maja silt"); Font suurkiri=new Font("Serif", Font.BOLD+Font.ITALIC, 30); Icon majapilt=new ImageIcon("maja.gif"); silt.setFont(suurkiri); silt.setIcon(majapilt); JButton nupp=new JButton("Maja nupp", majapilt); nupp.setToolTipText("Head vajutamist!"); nupp.setMnemonic(java.awt.event.KeyEvent.VK_M); JFrame f=new JFrame("Sildiraam"); Container p=f.getContentPane(); p.setLayout(new GridLayout(2, 1)); p.add(silt); p.add(nupp); f.pack(); f.setVisible(true); } } HTML-kujundus Swingi komponentidel näidatavat teksti saab HTMLi abil kujundada. Täpne väljanägemine võib sõltuda intepretaatorist, kuid selliselt on programmi väljanägemist lihtsam pilkupüüdvaks muuta kui awt vahenditega kujundades. Nagu lihtsat teksti kandva sildi puhul, nii ka siin on võimalik programmi töö käigus sildi sisu muuta. import javax.swing.*; public class HtmlLabel{ public static void main(String argumendid[]){ JFrame f=new JFrame("Kujundatud silt"); JLabel silt=new JLabel( "