From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100221.html | 520 +++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100221.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100221.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100221.html b/Master/Reference Architectures and Patterns/hjp5/html/k100221.html new file mode 100644 index 0000000..39e95e3 --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100221.html @@ -0,0 +1,520 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 33 - Eigene Dialogelemente +
+
+ + + + +

33.2 Entwicklung einer 7-Segment-Anzeige +

+
+ +
+ + + + +

33.2.1 Anforderungen

+ +

+In diesem Abschnitt wollen wir uns ein konkretes Beispiel zur Komponentenentwicklung +ansehen. Dazu soll eine einstellige 7-Segment-Anzeige entwickelt werden, +die in der Lage ist, die Ziffern 0 bis 9 darzustellen. Des weiteren +sollen folgende Eigenschaften realisiert werden: +

+ + + + +

33.2.2 Bildschirmanzeige

+ +

+Die Architektur unserer Anzeigekomponente ist denkbar einfach. Wir +definieren dazu eine neue Klasse Segment7, +die aus Canvas +abgeleitet wird. Segment7 +besitzt eine Membervariable digit, +die den aktuellen Anzeigewert speichert. Dieser kann mit den öffentlichen +Methoden getValue und setValue +abgefragt bzw. gesetzt werden. Die Klasse bekommt zwei Konstruktoren, +die es erlauben, den Anzeigewert wahlweise bei der Instanzierung zu +setzen oder die Voreinstellung 0 zu verwenden. + +

+Segment7 +überlagert die Methoden getPreferredSize +und getMinimumSize +der Klasse Component, +um den Layoutmanagern die gewünschte Größe mitzuteilen: +

+ + + + + +
+ +
+public Dimension getPreferredSize()
+
+public Dimension getMinimumSize()
+
+
+
+java.awt.Component
+ +

+Beide Methoden liefern ein Objekt der Klasse Dimension, +also ein rechteckiges Element mit einer Höhe und Breite. getPreferredSize +teilt dem Layoutmanager mit, welches die gewünschte Größe +der Komponente ist, und getMinimumSize +gibt an, welches die kleinste akzeptable Größe ist. Der +Layoutmanager FlowLayout +beispielsweise verwendet getPreferredSize, +um die Größe der Komponente zu bestimmen. GridLayout +gibt die Größe selbst vor und passt sie an die Gitterelemente +an. Durch Aufruf von pack +kann allerdings auch GridLayout +dazu veranlaßt werden, die gewünschte Größe +der Komponenten abzufragen und zur Dimensionierung des Fensters (und +damit letztlich zur Dimensionierung der Einzelkomponenten) zu verwenden. +Seit dem JDK 1.1 gibt es noch eine dritte Methode getMaximumSize, +mit der die Komponente ihre maximale Größe mitteilen kann. +Sie wird in unserem Beispiel nicht benötigt. + +

+Zur Darstellung der Leuchtdiodenanzeige auf dem Bildschirm wird die +Methode paint +überlagert; in ihr befindet sich die Logik zur Darstellung der +sieben Segmente (siehe Abbildung 33.1). +In Segment7 +wurden dazu drei Arrays digits, +polysx und polysy +definiert, die die Belegung der Segmente für jede einzelne Ziffer +darstellen und die Eckpunkte jedes einzelnen Segments vorgeben. + +

+paint +verwendet das Array digits, +um herauszufinden, welche Segmente zur Darstellung der aktuellen Ziffer +verwendet werden. Für jedes der beteiligten Segmente wird dann +aus den Arrays polysx und polysy +das passende Polygon gebildet und mit fillPolygon +angezeigt. Als interne Berechnungseinheit werden zwei Parameter dx +und dy verwendet, die beim Aufruf +von paint +aus dem für die Komponente verfügbaren Platz berechnet werden. +

+ + +

+ +

+Abbildung 33.1: Der Aufbau der 7-Segment-Anzeige

+ + + + +

33.2.3 Ereignisbehandlung

+ +

+Wie in Kapitel 28 +erwähnt, erfolgt die Ereignisbehandlung in selbstdefinierten +Komponenten üblicherweise auf der Basis des vierten vorgestellten +Architekturmodells. Bei diesem werden die Ereignisse nicht durch registrierte +Listener-Klassen bearbeitet, sondern durch Überlagern der Methoden +process...Event der Klasse Component. + +

+Damit die Ereignisse tatsächlich an diese Methoden weitergegeben +werden, müssen sie zuvor durch Aufruf von enableEvents +und Übergabe der zugehörigen Ereignismaske aktiviert werden. +Da wir Component-, Focus-, Key- und Mouse-Ereignisse behandeln wollen, +rufen wir enableEvents +mit den Konstanten AWTEvent.COMPONENT_EVENT_MASK, +AWTEvent.FOCUS_EVENT_MASK, +AWTEvent.MOUSE_EVENT_MASK +und AWTEvent.KEY_EVENT_MASK +auf. Beim Überlagern dieser Methoden sollte in jedem Fall der +entsprechende Ereignishandler der Superklasse aufgerufen werden, um +die korrekte Standard-Ereignisbehandlung sicherzustellen. + +

+Die Reaktion auf Mausklicks wird durch Überlagern der Methode +processMouseEvent +realisiert. Hier wird zunächst überprüft, ob es sich +um ein MOUSE_PRESSED-Ereignis +handelt, also ob eine der Maustasten gedrückt wurde. Ist +dies der Fall, wird dem Anzeigeelement durch Aufruf von requestFocus +der Eingabefokus zugewiesen. + +

+Anschließend wird überprüft, ob die [UMSCHALT]-Taste +gedrückt wurde. Ist das der Fall, wird die Ereignisbehandlung +beendet, andernfalls wird der Anzeigewert hoch- bzw. heruntergezählt, +je nachdem, ob die rechte oder linke Maustaste gedrückt wurde. +Am Ende von processMouseEvent +wird in jedem Fall super.processMouseEvent +aufgerufen, um sicherzustellen, dass die normale Ereignisbehandlung +aufgerufen wird. + +

+Ein selbstdefiniertes Dialogelement bekommt nicht automatisch den +Fokus zugewiesen, wenn mit der Maus darauf geklickt wird. Statt dessen +muss es selbst auf Mausklicks reagieren und sich - wie zuvor beschrieben +- durch Aufruf von requestFocus +selbst den Fokus zuweisen. Bei jeder Fokusänderung wird ein Focus-Event +ausgelöst, das wir durch Überlagern der Methode processFocusEvent +bearbeiten. Hier unterscheiden wir zunächst, ob es sich um ein +FOCUS_GAINED- +oder FOCUS_LOST-Ereignis +handelt, und setzen eine interne Statusvariable hasfocus +entsprechend. Diese wird nach dem anschließenden Aufruf von +repaint +verwendet, um in paint +durch Modifikation der Anzeigefarbe ein visuelles Feedback zu geben. +Hat ein Element den Fokus, so ist die Farbe der Anzeigesegmente gelb, +andernfalls rot. + +

+Seit dem JDK 1.1 gibt es einen Mechanismus, der es erlaubt, mit den +Tasten [TAB] und [UMSCHALT]+[TAB] +zwischen den Eingabefeldern eines Dialogs zu wechseln. Genauer gesagt +wird dadurch der Fokus an das nächste Element weiter- bzw. zum +vorigen zurückgegeben. Da diese Vorgehensweise nicht bei jedem +Dialogelement sinnvoll ist, kann das Dialogelement sie durch Überlagern +der Methode isFocusTraversable +selbst bestimmen. Liefert isFocusTraversable +den Rückgabewert true, +so nimmt das Objekt an der [TAB]-Behandlung +teil, andernfalls nicht. Die Klasse Segment7 +überlagert isFocusTraversable +und gibt true +zurück. So kann mit [TAB] +und [UMSCHALT]+[TAB] +wie besprochen zwischen den 7-Segment-Anzeigen gewechselt werden. +

+ + + + + + + + + + + +
+ +

+Mit der Version 1.4 des JDK wurde isFocusTraversable +als deprecated markiert, und sollte durch isFocusable +ersetzt werden. Wegen der großen Anzahl vorhandener Bugs und +Inkonsistenzen wurde nämlich die Architektur des Fokus-Subsystems +vollständig überarbeitet und mit einem teilweise neuen API +versehen. Programmcode, der mit der Fokussierung von AWT- oder Swing-Komponenten +zu tun hat, muss daher beim Umstieg auf das JDK 1.4 oder neuere Versionen +vermutlich überarbeitet werden.

+ + + + +
 JDK1.1-6.0 
+
+ +

+Ein Dialogelement enthält nur dann Tastatureingaben, wenn es +den Fokus hat. Durch den zuvor beschriebenen Mechanismus des Aufrufs +von requestFocus +stellen wir sicher, dass nach einem Mausklick bzw. nach dem Wechsel +des Fokus mit [TAB] und [UMSCHALT]+[TAB] +Tastaturereignisse an das Element gesendet werden. Diese werden durch +Überlagern der Methode processKeyEvent +behandelt. Wir überprüfen darin zunächst, ob das Ereignis +vom Typ KEY_PRESSED +ist, und besorgen dann mit getKeyChar +den Wert der gedrückten Taste. Ist er '+', so wird der Anzeigewert +um 1 erhöht, bei '-' entsprechend verringert. Wurde eine der +Zifferntasten gedrückt, so erhält das Anzeigeelement diesen +Wert. Anschließend wird durch Aufruf von repaint +die Anzeige neu gezeichnet. + +

+Ein Component-Ereignis brauchen wir in unserem Beispiel nur, damit +wir dem Dialogelement unmittelbar nach der Anzeige auf dem Bildschirm +den Fokus zuweisen können. Dazu überlagern wir die Methode +processComponentEvent +und überprüfen, ob das Ereignis vom Typ COMPONENT_SHOWN +ist. In diesem Fall wird requestFocus +aufgerufen, andernfalls passiert nichts. + +

+Damit ist die Konstruktion der Komponente auch schon abgeschlossen. +Durch die Definition von getPreferredSize +und getMinimumSize +und die automatische Skalierung in der paint-Methode +verhält sich unsere neue Komponente so, wie es die Layoutmanager +von ihr erwarten. Daher kann sie wie eine vordefinierte Komponente +verwendet werden. Hier ist der Quellcode von Segment7: + + +

+ + + + + +
+ +
+001 /* Segment7.java */
+002 
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 
+006 class Segment7
+007 extends Canvas
+008 {
+009   private int digit;
+010   private boolean hasfocus;
+011   private int[][] polysx = {
+012     { 1, 2, 8, 9, 8, 2},    //Segment 0
+013     { 9,10,10, 9, 8, 8},    //Segment 1
+014     { 9,10,10, 9, 8, 8},    //Segment 2
+015     { 1, 2, 8, 9, 8, 2},    //Segment 3
+016     { 1, 2, 2, 1, 0, 0},    //Segment 4
+017     { 1, 2, 2, 1, 0, 0},    //Segment 5
+018     { 1, 2, 8, 9, 8, 2},    //Segment 6
+019   };
+020   private int[][] polysy = {
+021     { 1, 0, 0, 1, 2, 2},    //Segment 0
+022     { 1, 2, 8, 9, 8, 2},    //Segment 1
+023     { 9,10,16,17,16,10},    //Segment 2
+024     {17,16,16,17,18,18},    //Segment 3
+025     { 9,10,16,17,16,10},    //Segment 4
+026     { 1, 2, 8, 9, 8, 2},    //Segment 5
+027     { 9, 8, 8, 9,10,10},    //Segment 6
+028   };
+029   private int[][] digits = {
+030     {1,1,1,1,1,1,0},         //Ziffer 0
+031     {0,1,1,0,0,0,0},         //Ziffer 1
+032     {1,1,0,1,1,0,1},         //Ziffer 2
+033     {1,1,1,1,0,0,1},         //Ziffer 3
+034     {0,1,1,0,0,1,1},         //Ziffer 4
+035     {1,0,1,1,0,1,1},         //Ziffer 5
+036     {1,0,1,1,1,1,1},         //Ziffer 6
+037     {1,1,1,0,0,0,0},         //Ziffer 7
+038     {1,1,1,1,1,1,1},         //Ziffer 8
+039     {1,1,1,1,0,1,1}          //Ziffer 9
+040   };
+041 
+042   public Segment7()
+043   {
+044     this(0);
+045   }
+046 
+047   public Segment7(int digit)
+048   {
+049     super();
+050     this.digit = digit;
+051     this.hasfocus = false;
+052     enableEvents(AWTEvent.COMPONENT_EVENT_MASK);
+053     enableEvents(AWTEvent.FOCUS_EVENT_MASK);
+054     enableEvents(AWTEvent.MOUSE_EVENT_MASK);
+055     enableEvents(AWTEvent.KEY_EVENT_MASK);
+056   }
+057 
+058   public Dimension getPreferredSize()
+059   {
+060     return new Dimension(5*10,5*18);
+061   }
+062 
+063   public Dimension getMinimumSize()
+064   {
+065     return new Dimension(1*10,1*18);
+066   }
+067 
+068   public boolean isFocusTraversable()
+069   {
+070     return true;
+071   }
+072 
+073   public void paint(Graphics g)
+074   {
+075     Color darkred  = new Color(127,0,0);
+076     Color lightred = new Color(255,0,0);
+077     Color yellow   = new Color(255,255,0);
+078     //dx und dy berechnen
+079     int dx = getSize().width / 10;
+080     int dy = getSize().height / 18;
+081     //Hintergrund
+082     g.setColor(darkred);
+083     g.fillRect(0,0,getSize().width,getSize().height);
+084     //Segmente
+085     if (hasfocus) {
+086       g.setColor(yellow);
+087     } else {
+088       g.setColor(lightred);
+089     }
+090     for (int i=0; i < 7; ++i) { //alle Segmente
+091       if (digits[digit][i] == 1) {
+092         Polygon poly = new Polygon();
+093         for (int j = 0; j < 6; ++j) { //alle Eckpunkte
+094           poly.addPoint(dx*polysx[i][j],dy*polysy[i][j]);
+095         }
+096         g.fillPolygon(poly);
+097       }
+098     }
+099     //Trennlinien
+100     g.setColor(darkred);
+101     g.drawLine(0,0,dx*10,dy*10);
+102     g.drawLine(0,8*dy,10*dx,18*dy);
+103     g.drawLine(0,10*dy,10*dx,0);
+104     g.drawLine(0,18*dy,10*dx,8*dy);
+105   }
+106 
+107   public int getValue()
+108   {
+109     return digit;
+110   }
+111 
+112   public void setValue(int value)
+113   {
+114     digit = value % 10;
+115   }
+116 
+117   protected void processComponentEvent(ComponentEvent event)
+118   {
+119     if (event.getID() == ComponentEvent.COMPONENT_SHOWN) {
+120       requestFocus();
+121     }
+122     super.processComponentEvent(event);
+123   }
+124 
+125   protected void processFocusEvent(FocusEvent event)
+126   {
+127     if (event.getID() == FocusEvent.FOCUS_GAINED) {
+128       hasfocus = true;
+129       repaint();
+130     } else if (event.getID() == FocusEvent.FOCUS_LOST) {
+131       hasfocus = false;
+132       repaint();
+133     }
+134     super.processFocusEvent(event);
+135   }
+136 
+137   protected void processMouseEvent(MouseEvent event)
+138   {
+139     if (event.getID() == MouseEvent.MOUSE_PRESSED) {
+140       requestFocus();
+141       if (!event.isShiftDown()) {
+142         if (event.isMetaDown()) {
+143           setValue(getValue() + 1); //increment by 1
+144         } else {
+145           setValue(getValue() + 9); //decrement by 1
+146         }
+147       }
+148       repaint();
+149     }
+150     super.processMouseEvent(event);
+151   }
+152 
+153   protected void processKeyEvent(KeyEvent event)
+154   {
+155     if (event.getID() == KeyEvent.KEY_PRESSED) {
+156       char key = event.getKeyChar();
+157       if (key >= '0' && key <= '9') {
+158         setValue(key - '0');
+159         repaint();
+160       } else if (key == '+') {
+161         setValue(getValue() + 1); //increment by 1
+162         repaint();
+163       } else if (key == '-') {
+164         setValue(getValue() + 9); //decrement by 1
+165         repaint();
+166       }
+167     }
+168     super.processKeyEvent(event);
+169   }
+170 }
+
+
+Segment7.java
+ +Listing 33.1: Eine 7-Segment-Anzeige

+
+ + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3