package javacodebook.gui.buildcomponent; import java.awt.*; import java.awt.event.*; /** * Der RoundButton ist eine komplett selbst definierte AWT Komponente, die beim * Klicken seine Darstellung ändert und angemeldete ActionListener informiert. * Durch das geschilderte Vorgehen, lassen sich natürlich auch * andere Komponenten selber bauen. Das Beispiel soll die Vorgehensweise * umreissen, im Detail kann es noch ausgebaut werden. */ public class RoundButton extends Component { // Beim Aufruf von addActionListener wird über den EventMulticaster // ein neuer ActionListener aus allen bisher angemeldeten ActionListenern // gebaut, und hier abgelegt private ActionListener actionListener; // Beschriftung vom Button private String buttonLabel; // Zustand vom Button protected boolean pressed = false; /** * Konstruktor vom RoundButton ohne Beschriftung */ public RoundButton() { this(""); } /** * Konstruktor vom RoundButton mit Beschriftung */ public RoundButton(String buttonLabel) { this.buttonLabel = buttonLabel; // MouseEvents werden aktiviert. Wenn also eine Maus über dieser // Komponente geklickt wird, werden Events an diese Komponente // weitergegebene enableEvents(AWTEvent.MOUSE_EVENT_MASK); } /** * Die Darstellung des runden Buttons wird hier programmiert. */ public void paint(Graphics g) { // Radius des Buttons wird anhand der Komponentengroesse bestimmt int s = Math.min(getSize().width - 1, getSize().height - 1); // Das Button-Innnere wird gemalt if(pressed) { g.setColor(getBackground().darker().darker()); } else { g.setColor(getBackground()); } g.fillArc(0, 0, s, s, 0, 360); // Die Umrandung des Buttons wird gemalt g.setColor(getBackground().darker().darker().darker()); g.drawArc(0, 0, s, s, 0, 360); // Das Label wird im Center des Button platziert Font f = getFont(); if(f != null) { FontMetrics fm = getFontMetrics(getFont()); g.setColor(getForeground()); g.drawString(buttonLabel, s/2 - fm.stringWidth(buttonLabel)/2, s/2 + fm.getMaxDescent()); } } /** * Viele Layoutmamager benötigen die "preferred size", daher wird * diese Methode hier überschrieben */ public Dimension getPreferredSize() { Font f = getFont(); if(f != null) { FontMetrics fm = getFontMetrics(getFont()); int max = Math.max(fm.stringWidth(buttonLabel) + 40, fm.getHeight() + 40); return new Dimension(max, max); } else { return new Dimension(100, 100); } } /** * Der ActionListener wird an diesem Button angemeldet */ public void addActionListener(ActionListener listener) { // Der AWTEventMulticaster führt mehrer ActionListener in einen zusammen, // so dass einen Thread-sichere Abarbeitung ermöglicht wird. actionListener = AWTEventMulticaster.add(actionListener, listener); } /** * Der ActionListener wird von diesem Button entfernt */ public void removeActionListener(ActionListener listener) { actionListener = AWTEventMulticaster.remove(actionListener, listener); } /** * Nur wenn innerhalb des Kreises geklickt wird, soll ein Event ausgelöst werden * contains liefert nur dann true zurück wenn die Maus sich innerhalb befindet. */ public boolean contains(int x, int y) { int mx = getSize().width/2; int my = getSize().height/2; // Formel die anhand der geometrischen Getzmäßigkeiten eines Kreises // berechnet, ob eine Koordinate sich innerhalb oder außerhalb befindet. return (((mx-x)*(mx-x) + (my-y)*(my-y)) <= mx*mx); } /** * Wird aufgerufen wenn die Komponente geklickt wurde */ public void processMouseEvent(MouseEvent e) { Graphics g; switch(e.getID()) { case MouseEvent.MOUSE_PRESSED: pressed = true; // Die Komponente wird neu gemalt, intern wird paint aufgerufen, // daher kann das gesetzte Attribut pressed berücksichtigt werden repaint(); break; case MouseEvent.MOUSE_RELEASED: if(actionListener != null) { actionListener.actionPerformed(new ActionEvent( this, ActionEvent.ACTION_PERFORMED, buttonLabel)); } if(pressed == true) { pressed = false; repaint(); } break; case MouseEvent.MOUSE_ENTERED: break; case MouseEvent.MOUSE_EXITED: if(pressed == true) { pressed = false; repaint(); } break; } super.processMouseEvent(e); } } --- Neue Klasse --- package javacodebook.gui.buildcomponent; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * In diesem Frame wird eine selbstgebaute AWT Komponente (ein runder Button) * platziert. Beim 5. Klick wird das Fenster geschlossen. */ public class RoundButtonFrame extends Frame { private RoundButton round = new RoundButton("Runder Button"); /** * Konstruktor von RoundButtonFrame. */ public RoundButtonFrame(String title) { super(title); setLayout(new FlowLayout()); setBackground(Color.lightGray); // Beim Klicken des Schließen-Buttons vom HauptFenster // wird das Programm beendet. this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(0); } }); // Auch ein ActionListener kann an diesem Button angemeldet // werden round.addActionListener(new ActionListener(){ int zaehler=0; public void actionPerformed(ActionEvent ae){ zaehler++; if(zaehler>4) System.exit(0); } }); add(round); } }