kramann.info
© Guido Kramann

Login: Passwort:










Informatik3
1 Vom_struct_zur_Klasse
..1.1 Vom_struct_zur_Klasse
..1.2 struct_Programm
..1.3 Klassen_Programm
..1.4 Offene_Fragen
..1.5 Historie
..1.6 Objektabstraktion
..1.7 OO_Kundenverwaltung
..1.8 Objektfaehigkeiten
..1.9 Formatierung
..1.10 Motivation
..1.11 Uebung1
..1.12 Uebung2
2 UML
..2.1 Volumenberechnung
..2.2 UML_Klassendiagramm
..2.3 Konstruktor
..2.4 Statische_Variable
3 Strings
..3.1 Klassenbibliotheken
..3.2 stringUML
..3.3 Uebung3
4 Initialisierungen
4 bluej
5 Zeiger_und_Arrays
..5.1 Zeiger
..5.2 Zeiger_und_Funktion
..5.3 Uebung4
6 Vererbung
..6.1 MesswerteUML
..6.2 MesswerteProgramm
..6.3 VererbungsProgramm
..6.4 Vector
..6.5 Uebung
7 Modifikatoren
..7.1 public_Vererbung
..7.2 protected_Vererbung
8 Listen_und_Templates
..8.1 Containertypen
....8.1.1 ListeUML
....8.1.2 ListeProgramm
..8.2 Templates
....8.2.1 Listentemplate
....8.2.2 STLvectorTemplate
..8.3 Uebung5
..8.4 Uebung6
..8.5 Uebung7
9 Java
..9.1 Uebung
..9.2 GettingStarted
..9.3 Animation
..9.4 Hybrid
..9.5 Threads
10 Delegation
11 LayoutProjekt
12 Fenster
13 Uebung
14 Zwischenprojekt
..14.1 Befehle
..14.2 Planung
..14.3 JNI
..14.4 JNIumsetzen
..14.5 Anwendungsklasse
..14.6 GUI01
..14.7 GUI02
15 Rasterlayout
..15.1 Bilder_Packages
..15.2 interfaces
..15.3 ArrayList
..15.4 clone
..15.5 Uebung
16 Nuetzliches
..16.1 Threads
..16.2 Animation
..16.3 RungeKutta
..16.4 Loesungsansatz
..16.5 Internetprogrammierung
....16.5.1 Codegenerierung
....16.5.2 PHP_Programmierung
....16.5.3 PHP_OOP
....16.5.4 Java
17 Algorithmen
..17.1 RungeKutta
..17.2 Loesungsansatz
..17.3 Evoopt
..17.4 Uebung12
..17.5 Uebung8_2014
..17.6 Ausdruecke
18 Uebung10
19 UML_ALT
..19.1 Flaechenberechnung
..19.2 UML_Flaechenberechnung
..19.3 Implementierung
..19.4 ListeUML
..19.5 ListenImplementierung
..19.6 Anwendung
kramann.info
© Guido Kramann

Login: Passwort:




Entwicklung und Verwendung eigener Interfaces

(EN google-translate)

(PL google-translate)

rl002_bauteile.zip - Zweite Entwicklungsstufe zu Rasterlayout.

Die einzelnen Bauteile sollen entgegen dem ursprünglichen Konzept durch einzelne Klassen repräsentiert werden.

Die ersten Bauteile werden sein: Widerstand und Bruecke. Dabei stellt Bruecke nur eine Drahtbrücke dar.

Die Grundidee dabei ist, dass alle diese Klassen eine Methode zeichnen(Graphics2D g2d) besitzen, der das Graphics2D-Objekt aus paint(..) von Rasterlayout übergeben wird und die sich dann selber in g2d einzeichnen, indem sie Methoden von g2d benutzen.

Ein Codefragment könnte so aussehen:

    protected void zeichneBeschriftung(Graphics2D g2d, Color farbe,
                                       int xraster, int yraster)
    {
        g2d.setColor(farbe);
        g2d.setFont(Style.FONT_BESCHRIFTUNG);
        g2d.drawString(
                        beschriftung,
                        Style.XOFF_BESCHRIFTUNG + 
                        (int)Math.round( (double)xraster*Style.rastermass ),
                        Style.YOFF_BESCHRIFTUNG + 
                        (int)Math.round( (double)yraster*Style.rastermass  )                        
                    );
    }

Code 0-1: So kann ein Objekt "sich selber" zeichnen.

Interfaces (Schnittstellen)

Später sollen alle sich selber zeichnenden Objekte in einer Container-Klasse vom Typ ArrayList abgelegt werden. Dies bietet den Vorteil, dass ein einer Schleife alle gesammelten Objekte durchgegangen und jeweils die Methode "zeichnen()" aufgerufen werden kann. Dies setzt voraus, dass alle diese Objekte die Methode zeichnen() besitzen und ArrayList das weiss. Dies kann gewährleistet werden, indem für alle Bauteil-Klassen eine gemeinsame Schnittstelle hier: "BauteilInterface" vereinbart wird.

Damit ausserdem redundante Methoden und Attribute nicht in jedem Bauteilobjekt implementiert werden müssen, wird in die Vererbungshierarchie noch eine allgemeine Klasse Bauteil zwischengeschoben. In UML dargestellt, ergibt. Interfaces werden mit dem Zusatz <<interface >> dargestellt.

Abstrakte Methoden und Klassen

Abstrakte Methoden werden in UML kursiv dargestellt und in Java mit dem Schlüsselwort abstract versehen. Abtrakte Methode werden an der Stelle wo sie erscheinen nicht implementiert. D.h. nur der Methodenkopf erscheint dort. In einer erbenden, bzw. implementierenden Klasse müssen sie dann noch implementiert werden, damit sie aufgerufen werden können.

Klassen, die mindestens eine Methode abstrakte Methode besitzen sind so genannte abstrakte Klassen und müssen in Java dann auch mit diesem Zusatz im Kopf der Klasse ausgezeichnet werden, also public abstract class MeineKlasse.

In unserem Beispiel werden fast alle Methoden, die in BauteilInterface vereinbart werden bereits in der Klasse Bauteil implementiert. Jedoch die Methode zeichnen(..) wird erst in den von Bauteil erbenden Klassen implementiert, weil die Implementierung von zeichnen(..) stark von dem jeweils zu zeichnenden Bauteil abhängt.

Dagegen sind setRotation(..) und setTranslation(..) für alle Bauteile gleich und werden deshalb in der gemeinsamen Oberklasse Bauteil schon implementiert.

In UML ergibt sich deshalb folgende Implementierungs- bzw. Vererbungsstruktur: (Implementierung: Pfeil wie bei Vererbung, aber gestrichelt.)

Vererbungs- bzw. Implementierungsstruktur der Bauteil-Klassen.

Bild 0-1: Vererbungs- bzw. Implementierungsstruktur der Bauteil-Klassen.

Im folgenden sind die entsprechenden Java-Implementierungen dargestellt.

package bauteile;

import java.awt.Graphics2D;

public interface BauteilInterface
{
    public abstract void zeichnen(Graphics2D g2d);
    public abstract void setRotation(int rotation);
    public abstract void setTranslation(int xpos, int ypos);
}

Code 0-2: Quelltext zu BauteilInterface.java

package bauteile;

import java.awt.Graphics2D;
import java.awt.Color;

import konstanten.Style;

public abstract class Bauteil implements BauteilInterface
{
    protected String beschriftung = "";
    protected int xpos=0,ypos=0,rotation=0;

    //wird erst in den erbenden Klassen implementiert:
    public abstract void zeichnen(Graphics2D g2d); 

    public void setBeschriftung(String beschriftung)
    {
        this.beschriftung = beschriftung;
    }

    public void setRotation(int rotation)
    {
        this.rotation = rotation;
    }

    public void setTranslation(int xpos, int ypos)
    {
        this.xpos = xpos;
        this.ypos = ypos;
    }

    protected void setTransformation(Graphics2D g2d)
    {
         g2d.translate(Style.xoff + (int)Math.round( (double)xpos*Style.rastermass ),
                       Style.yoff + (int)Math.round( (double)ypos*Style.rastermass ));      
         g2d.rotate(0.5*Math.PI*(double)rotation);           
    }

    protected void unsetTransformation(Graphics2D g2d)
    {
         g2d.rotate(-0.5*Math.PI*(double)rotation);           
         g2d.translate(-Style.xoff - (int)Math.round( (double)xpos*Style.rastermass ),
                       -Style.yoff - (int)Math.round( (double)ypos*Style.rastermass ));      
    }

    protected void zeichnePad(Graphics2D g2d, Color farbe, int xraster, int yraster)
    {
        g2d.setColor(farbe);
        g2d.fillOval(
                        (int)Math.round( (double)xraster*Style.rastermass -0.5*Style.bohrung*Style.rastermass ),
                        (int)Math.round( (double)yraster*Style.rastermass -0.5*Style.bohrung*Style.rastermass ),                        
                        (int)Math.round( Style.bohrung*Style.rastermass ),
                        (int)Math.round( Style.bohrung*Style.rastermass )
                    );
    }

    protected void zeichneLinie(Graphics2D g2d, Color farbe, int xraster1, int yraster1,
                                                             int xraster2, int yraster2)
    {
        g2d.setColor(farbe);
        g2d.drawLine(
                        (int)Math.round( (double)xraster1*Style.rastermass ),
                        (int)Math.round( (double)yraster1*Style.rastermass ),                        
                        (int)Math.round( (double)xraster2*Style.rastermass ),
                        (int)Math.round( (double)yraster2*Style.rastermass )                        
                    );
    }

    protected void zeichneBox(Graphics2D g2d, Color farbe, int xraster1, int xraster2,
                                                           int yraster)
    {
        g2d.setColor(farbe);
        g2d.fillRect(
                        (int)Math.round( (double)xraster1*Style.rastermass ),
                        (int)Math.round( (double)yraster*Style.rastermass  -0.6*Style.rastermass),                        
                        (int)Math.round( (double)(xraster2-xraster1)*Style.rastermass ),                        
                        (int)Math.round( 1.2*Style.rastermass )
                    );

        g2d.setColor(Color.BLACK);
        g2d.drawRect(
                        (int)Math.round( (double)xraster1*Style.rastermass ),
                        (int)Math.round( (double)yraster*Style.rastermass  -0.6*Style.rastermass),                        
                        (int)Math.round( (double)(xraster2-xraster1)*Style.rastermass ),                        
                        (int)Math.round( 1.2*Style.rastermass )
                    );
    }


    protected void zeichneBeschriftung(Graphics2D g2d, Color farbe,
                                       int xraster, int yraster)
    {
        g2d.setColor(farbe);
        g2d.setFont(Style.FONT_BESCHRIFTUNG);
        g2d.drawString(
                        beschriftung,
                        Style.XOFF_BESCHRIFTUNG + 
                        (int)Math.round( (double)xraster*Style.rastermass ),
                        Style.YOFF_BESCHRIFTUNG + 
                        (int)Math.round( (double)yraster*Style.rastermass  )                        
                    );
    }

}

Code 0-3: Quelltext zu Bauteil.java

Die Methoden zeichnePad(..), zeichneLinie(..), zeichneBox(..) und zeichneBeschriftung(..) sind Hilfsmethoden, die von der Methode zeichnen(..) der erbenden Klassen aufgerufen werden (g2d wird hier weitergereicht), um gwisse Grundelemente, wie eine Linie zwischen zwei Rasterpunkten, eine Beschriftung usw. zu zeichnen.

Bestimmte Konstanten sind in der Klasse Style als statische public-Attribute vermerkt, um sie in jeder Klasse leicht benutzen zu können und sie an zentraler Stelle anpassen zu können. So kann es ja leicht sein, dass der obere linke Rasterpunkt in einem anderen Rasterhintergrundbild etwas anders liegt und die Rasterabstände anders sind. Es wäre sehr Fehler anfällig, unübersichtlch und schwer zu merken, müßte man diese Parameter an verschiedenen Stellen im Programm bei Bedarf nachziehen. Statt dessen sind sie in konstanten.Style als xoff, yoff und rastermass neben weiteren Konstanten gespeichert.

Durch die Vorarbeit, die im Interface BauteilInterface und in der Basisklasse Bauteil geleistet wurde, fällt nun die Implementierung von Widerstand kurz aus. Dies ist auch gut, da damit gerechnet werden muss, dass neben Widerstand eine Vielzahl weiterer Bauteile realisiert werden muss. Es wäre mühsam, wenn man sich in die elementaren Grundgrafikelemente, wie eine Linie zwischen zwei Rasterpunkten ziehen, jedesmal neu hineindenken müßte. So muss man lediglich sagen, wieviele Rasterpunkte z.B. eine Linie lang ist, bzw. um wieviele Rasterpunkte in x- und y-Richtung eine Beschriftung versetzt ist.

Da zudem die Transformationen die hier möglich sind engumgrenzt sind, werden sie mit einfachen Integer-Parametern kodiert: xpos,ypos,rotation. Dabei ist bei xpos und ypos eine Einheit ein Schritt im Rastermass. Als Rotation sind die Werte 0,1,2 und 3 möglich, was Drehungen um 0, 90, 180 und 270 Grad entspricht.

Mit den weiteren Hilfsmethoden setTransformation(..) und ansetTransformation(..) läßt sich die notwendige Transformation für das aktuelle Bauteil setzen, bzw. rückgängig machen, bevor das nächste Bauteil mit seiner eigenen Transformation (Lage auf dem Raster und Drehung) gezeichnet wird.

package bauteile;

import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.BasicStroke;

import konstanten.Style;



public class Widerstand extends Bauteil implements BauteilInterface
{
    public void zeichnen(Graphics2D g2d)
    {
        setTransformation(g2d);

         g2d.setStroke(new BasicStroke(
                                       2.0f,                  // Liniendicke
                                       BasicStroke.CAP_ROUND, // Form des Linienendes
                                       BasicStroke.JOIN_ROUND // Verbindung von Polygonlinien
                                      )   
                      ); 

        zeichnePad(g2d, Color.BLACK, 0, 0);
        zeichnePad(g2d, Color.BLACK, 4, 0);
        
        zeichneLinie(g2d, Color.BLACK, 0, 0, 1, 0);
        zeichneLinie(g2d, Color.BLACK, 3, 0, 4, 0);

        zeichneBox(g2d, Style.FARBE_BAUTEIL, 1, 3, 0);
        
        zeichneBeschriftung(g2d, Color.BLUE, 1, 0);

        unsetTransformation(g2d);
    }
}

Code 0-4: Quelltext Widerstand.java

In der paint-Methode von Rasterlayout können nun testweise Bauteile dargestellt werden, bzw. können sich selber zeichnen:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

import hilfsklassen.Bilder;

import bauteile.*;

public class Rasterlayout extends Canvas
{
     private Image rasterbild = null;

     private Widerstand r1,r2,r3;

     public Rasterlayout()
     {
         rasterbild = Bilder.holeBild("raster.png");

         JFrame frame = new JFrame();
         frame.setBounds(10,10,900,700);
         frame.getContentPane().add(this);
         frame.setVisible(true); 

         r1 = new Widerstand();
         r1.setTranslation(8,1);         
         r1.setRotation(0);         
         r1.setBeschriftung("100");

         r2 = new Widerstand();
         r2.setTranslation(16,1);         
         r2.setRotation(0);         

         r3 = new Widerstand();
         r3.setTranslation(16,1);         
         r3.setRotation(1);         
         r3.setBeschriftung("2k2");
     }

     public void paint(Graphics g)
     {         
         if(rasterbild!=null)
         {
             g.drawImage(rasterbild,0,0,Color.WHITE,this); 
         }

         Graphics2D g2d = (Graphics2D)g;

         r1.zeichnen(g2d);         
         r2.zeichnen(g2d);         
         r3.zeichnen(g2d);         
     }

     public static void main(String[] args)
     {
         Rasterlayout rasterlayout = new Rasterlayout();
     }
}

Code 0-5: Quelltext von Rasterlayout.java

Darstellung nach Start des Programms.

Bild 0-2: Darstellung nach Start des Programms.