package oreilly.beans.yesno; import java.awt.*; import java.util.*; /** * Itse tehty komponentti, jossa näytetään monirivinen teksti tietyissä * marginaaleissa ja tietyllä tapaa tasattuna. Java 1.1-versiossa voitaisiin * periyttää Component-luokastas Canvas-luokan sijasta, jolloin komponentista * tulisi tehokkaampi ja keveämpi. */ public class MultiLineLabel extends Canvas { // Käyttäjän määrittelemät arvot protected String label; // Otsikko, ei vielä pilkottu riveiksi protected int margin_width; // Vasen ja oikea marginaali protected int margin_height; // Ylä- ja alamarginaali protected int alignment; // Tekstin tasaustapa // Tasausvaihtoehdot public static final int LEFT = 0, CENTER = 1, RIGHT = 2; // Lasketut tilamuuttujat protected int num_lines; // Rivien määrä protected String[] lines; // Otsikko, riveiksi pilkottuna protected int[] line_widths; // Rivien leveydet protected int max_width; // Leveimmän rivin leveys protected int line_height; // Fontin korkeus protected int line_ascent; // Fontin korkeus perusviivan // yläpuolella protected boolean measured = false; // Onko rivit mitattu? // Tässä on viisi versiota konstruktorista public MultiLineLabel(String label, int margin_width, int margin_height, int alignment) { // Laitetaan kaikki ominaisuudet muistiin this.label = label; this.margin_width = margin_width; this.margin_height = margin_height; this.alignment = alignment; newLabel(); // Pilkotaan otsikko riveiksi } public MultiLineLabel(String label, int margin_width, int margin_height) { this(label, margin_width, margin_height, LEFT); } public MultiLineLabel(String label, int alignment) { this(label, 10, 10, alignment); } public MultiLineLabel(String label) { this(label, 10, 10, LEFT); } public MultiLineLabel() { this(""); } // Metodit, joilla kysytään ja asetetaan komponentin attribuutit. // Huomaa, että osa kyselymetodeista periytyy yliluokalta. public void setLabel(String label) { this.label = label; newLabel(); // Pilkotaan otsikko riveiksi. measured = false; // Huomaa, että rivit täytyy mitata. repaint(); // Piirretään uudestaan. } public void setFont(Font f) { super.setFont(f); // Kerrotaan yliluokalle uudesta fontista. measured = false; // Huomaa, että rivit täytyy mitata. repaint(); // Piirretään uudestaan. } public void setForeground(Color c) { super.setForeground(c); // Kerrotaan yliluokalle uudestas väristä. repaint(); // Piirretään uudestaan (koko ei muuutu). } public void setAlignment(int a) { alignment = a; repaint(); } public void setMarginWidth(int mw) { margin_width = mw; repaint(); } public void setMarginHeight(int mh) { margin_height = mh; repaint(); } public String getLabel() { return label; } public int getAlignment() { return alignment; } public int getMarginWidth() { return margin_width; } public int getMarginHeight() { return margin_height; } /** * Asettelunhallintaolio kutsuu tätä metodia, kun se haluaa tietää, * kuinka suuri tämä olio on. Java 1.1-versiossa getPreferredSize() on * suositeltu vaihtoehto tälle metodille. Esimerkissä käytetää vanhentuvaa * versiota, jotta tätä komponenttia voisi käyttää yhdessä 1.0- * komponenttien kanssa. */ public Dimension preferredSize() { if (!measured) measure(); return new Dimension(max_width + 2*margin_width, num_lines * line_height + 2*margin_height); } /** * Asettelunhallintaolio kutsuu tätä metodia, kun se haluaa tietää * pienimmän mahdollisen komponentin tarvitseman alueen. Java 1.1- * versiossa käytetään getMinimunSize()-metodia. */ public Dimension minimumSize() { return preferredSize(); } /** * Tässä metodissa piirretään otsikko (sama metodi, jota käytetää * appleteissa). Metodissa otetaan huomioon marginaalit ja tasaus * mutta siinä ei puututa väriin tai fonttiin. Yliluokka asettaa * ne tälle metodille annettuun Graphics-olioon. */ public void paint(Graphics g) { int x, y; Dimension size = this.size(); // Java 1.1-ohjelmissa getSize() if (!measured) measure(); y = line_ascent + (size.height - num_lines * line_height)/2; for(int i = 0; i < num_lines; i++, y += line_height) { switch(alignment) { default: case LEFT: x = margin_width; break; case CENTER: x = (size.width - line_widths[i])/2; break; case RIGHT: x = size.width - margin_width - line_widths[i]; break; } g.drawString(lines[i], x, y); } } /** Tässä sisäisessä metodissa pilkotaan otsikko rivitaulukoksi. Metodissa * käytetään StringTokenizer-apuluokkaa. */ protected synchronized void newLabel() { StringTokenizer t = new StringTokenizer(label, "\n"); num_lines = t.countTokens(); lines = new String[num_lines]; line_widths = new int[num_lines]; for(int i = 0; i < num_lines; i++) lines[i] = t.nextToken(); } /** Tässä sisäisessä metodissa selvitetään fontin korkeus, kuinka * leveitä otsikkorivit ovat ja kuinka leveä on levein rivi. */ protected synchronized void measure() { FontMetrics fm = this.getToolkit().getFontMetrics(this.getFont()); line_height = fm.getHeight(); line_ascent = fm.getAscent(); max_width = 0; for(int i = 0; i < num_lines; i++) { line_widths[i] = fm.stringWidth(lines[i]); if (line_widths[i] > max_width) max_width = line_widths[i]; } measured = true; } }