/* Das Plotfenster, in dem der Graph dargestellt wird */ import java.awt.*; import java.awt.event.*; /** PlotFrame - Klasse stellt Ausdruck graphisch dar */ public class altPlotFrame extends Frame { // Variablendeklaration double m_dInitialStartX, m_dInitialEndX, m_dInitialStartY, m_dInitialEndY; // Startwerte der Grenzen double rangeWidth, rangeHeight; // gewählter Range PlotCanvas pCanvas; // die Zeichenfläche PlotFrame dummyThis; // unangenehme Konstrukte... Plotter parent; // Schön verzahnt... MParse parser; // Eine MParse-Referenz // Exportiere Variablen /** minimal darzustellender x-Wert */ public double m_dStartX; /** maximal darzustellender x-Wert */ public double m_dEndX; /** minimal darzustellender y-Wert */ public double m_dStartY; /** maximal darzustellender y-Wert */ public double m_dEndY; /** Referenz auf die nächste Instanz (für Fenster-Liste) */ public PlotFrame next; /** Der geparste Funktionsausdruck */ public String AusdruckString; /** * Der Constructor * @param Plotter Referenz auf Mutterinstanz vom Typ Plotter * @param String Zu parsender Funktionsausdruck * @param dStartX minimal darzustellender x-Wert * @param dEndX maximal darzustellender x-Wert * @param dStartY minimal darzustellender y-Wert * @param dEndY maximal darzustellender y-Wert */ PlotFrame (Plotter parent, String AusdruckString, double dStartX, double dEndX, double dStartY, double dEndY) { super ("Funktion: " + AusdruckString); // Fenstertitel = Funktionsausdruck // Das Parsen des Strings, Anlegen eines neuen MParse-Objekts parser = new MParse(); try { parser.parse( AusdruckString ); // Parsen parser.evaluate( dStartX ); // Einen Wert testen } catch ( MParseException MPEX ) { this.AusdruckString = MPEX.msg; // Das darf nicht sein, daher wird gekillt return; } // Übernehmen der Variablen this.AusdruckString = AusdruckString; this.parent = parent; // Für Call-Back m_dEndX = dEndX; // Werte abspeichern m_dStartX = dStartX; m_dStartY = dStartY; m_dEndY = dEndY; // Initialisierung InitPlotFrame(); } /** Die eigentliche Plot-Klasse -> Erweiterung der Canvas-Klasse */ class PlotCanvas extends Canvas { // Globale Variabeln der PlotCanvas-Klasse int MouseX, MouseY; boolean ShiftPressed; Dimension pSize; /** PlotCanvas - Constructor mit MouseListener für Scrollen/Zoomen */ PlotCanvas () { // Tastatur-Handling KeyListener unserKeyListener = new KeyAdapter() { public void keyPressed(KeyEvent e) { // Taste gedrückt if (e.getKeyCode() == KeyEvent.VK_SHIFT) { ShiftPressed = true; } } public void keyReleased(KeyEvent e) { // Taste losgelassen if (e.getKeyCode() == KeyEvent.VK_SHIFT) { ShiftPressed = false; } } }; // Mouse-Handling MouseListener unserMouseListener = new MouseAdapter() { public void mousePressed(MouseEvent e) { // Mouse gedrückt MouseX = e.getX(); MouseY = e.getY(); } public void mouseClicked(MouseEvent e) { // Zurücksetzen if (e.getClickCount() == 2) { // Bei Doppelklick m_dStartX = m_dInitialStartX; m_dEndX = m_dInitialEndX; m_dStartY = m_dInitialStartY; m_dEndY = m_dInitialEndY; rangeWidth = Math.abs(m_dEndX - m_dStartX); // Breite und... rangeHeight = Math.abs(m_dEndY - m_dStartY); // ... Höhe der Ausgabe ausrechnen repaint(); } } }; // Mousebewegungshandling MouseMotionListener unserMotionListener = new MouseMotionAdapter() { public void mouseDragged(MouseEvent e) { // Doppelklickhandling if (e.getClickCount() == 2) { // Bei Doppelklick m_dStartX = m_dInitialStartX; m_dEndX = m_dInitialEndX; m_dStartY = m_dInitialStartY; m_dEndY = m_dInitialEndY; rangeWidth = Math.abs(m_dEndX - m_dStartX); // Breite und... rangeHeight = Math.abs(m_dEndY - m_dStartY); // ... Höhe der Ausgabe ausrechnen repaint(); return; } // Abmessungen unserer Zeichenfläche holen pSize = getSize (); // .height, .width sind die Maße... // Neue Grenzen berechnen if (!ShiftPressed) { // Wenn Shift nicht gedrückt, dann verschieben m_dStartX += (MouseX - e.getX()) * rangeWidth / pSize.width; m_dEndX += (MouseX - e.getX()) * rangeWidth / pSize.width; m_dStartY -= (MouseY - e.getY()) * rangeHeight / pSize.height; m_dEndY -= (MouseY - e.getY()) * rangeHeight / pSize.height; rangeWidth = Math.abs(m_dEndX - m_dStartX); // Breite und... rangeHeight = Math.abs(m_dEndY - m_dStartY); // ... Höhe der Ausgabe ausrechnen } else { // Wenn Shift gedrückt, dann spezial-zoom if (MouseX - e.getX() > 0) { m_dStartX -= (MouseX - e.getX()) * rangeWidth / pSize.width; m_dEndX += (MouseX - e.getX()) * rangeWidth / pSize.width; } else { m_dStartX -= (MouseX - e.getX()) * rangeWidth / pSize.width; m_dEndX += (MouseX - e.getX()) * rangeWidth / pSize.width; } if (MouseY - e.getY() > 0) { m_dStartY -= (MouseY - e.getY()) * rangeHeight / pSize.height; m_dEndY += (MouseY - e.getY()) * rangeHeight / pSize.height; } else { m_dStartY -= (MouseY - e.getY()) * rangeHeight / pSize.height; m_dEndY += (MouseY - e.getY()) * rangeHeight / pSize.height; } rangeWidth = Math.abs(m_dEndX - m_dStartX); // Breite und... rangeHeight = Math.abs(m_dEndY - m_dStartY); // ... Höhe der Ausgabe ausrechnen } MouseX = e.getX(); // Neue "alte" Werte Zwischenspeichern MouseY = e.getY(); repaint(); } }; addMouseListener(unserMouseListener); // Mouse-Event-Handling aktiv. addMouseMotionListener(unserMotionListener); addKeyListener(unserKeyListener); } public void paint(Graphics g) { /* Der aktuelle X-Wert (Abszisse) */ double dAbszisse; /* Der aktuelle Funktionswert (Ordinate) */ double dFunktionsWert; /* Das Gitternetz wird erzeugt, indem sowohl in horizontaler als auch in vertikaler Richtung der darzustellende Bereich in 10 gleichgroße Intervalle unterteilt wird. Ist z.B. der darzustellende Bereich in x-Richtung von 2 bis 4, und in y-Richtung von -1 bis 7, so wird in x-Richtung (y-Richtung) alle 0,2 Einheiten (0,8 Einheiten) eine Linie dargestellt. Diese Variable hält die Länge dieses Intervalls, das bedeutet, den Abstant zwischen zwei dieser Linien. */ long lRasterAbstand; long addFaktor; // Für Achsenbeschriftung /* Größe des Applets holen */ pSize = getSize (); /* Wenn das Applet-Fenster zu klein ist, versuchen wir die Darstellung gar nicht erst, sondern zeichnen lediglich ein rotes "X". */ if ((pSize.height < 80) || (pSize.width < 80)) { g.setColor(Color.red); g.drawLine (0, 0, pSize.width - 1, pSize.height - 1); g.drawLine (0, pSize.height - 1, pSize.width - 1, 0); return; } /* Eine bestimmte Schriftart für die Achsenbeschriftungen verwenden */ g.setFont ( new Font("SansSerif", Font.PLAIN, 12) ); /* Die aktuelle X-Position in dem Zeichenbereich */ int iScreenX; /* Die aktuelle Y-Position in dem Zeichenbereich */ int iScreenY; /* Der "gemerkte" Wert für die Y-Pixelposition des letzten Durchlaufs. Dieser Wert wird benötigt, um nicht nur den Punkt an (iScreenX,iScreenY) zeichnen zu können, sondern um eine Linie, ausgehend von (iScreenX-1,iOldScreenY) nach (iScreenX,iScreenY) zeichnen zu können; denn das sieht wesentlich schöner aus. */ int iOldScreenY; // Achsen zeichnen, wenn diese im Range liegen if ((m_dStartX <= 0) && (m_dEndX >= 0)) { // Y-Achse g.setColor (Color.black); iScreenX = (int)( (0 - m_dStartX) * pSize.width / rangeWidth); g.drawLine ( iScreenX, 0, iScreenX, pSize.height - 1 ); g.drawString ("y-Achse", iScreenX - 47, 13); // Skala auf Y-Achse einzeichnen lRasterAbstand = Math.round (rangeHeight / 10); // lRasterAbstand berechnen if (lRasterAbstand != 0) { if (m_dStartY > 0) { addFaktor = Math.round(m_dStartY) - 1; } else if (m_dEndY < 0) { addFaktor = -Math.round(m_dEndY) - 1; } else { addFaktor = 0; } // Wenn 0 in der Mitte liegt for (int i = 1; i < 12; i++) { iScreenY = (int)( pSize.height - (i * lRasterAbstand + addFaktor - m_dStartY) * pSize.height / rangeHeight); if ((iScreenY > 0) && (iScreenY < pSize.height - 1)) { g.drawLine ( iScreenX - 2, iScreenY, iScreenX + 2, iScreenY); // horizontales Strichlein rechts von 0 g.drawString ( new Long(i * lRasterAbstand + addFaktor).toString(), iScreenX + 5, iScreenY + 5); } iScreenY = (int)( pSize.height - (0 - m_dStartY - i * lRasterAbstand - addFaktor) * pSize.height / rangeHeight); if ((iScreenY > 0) && (iScreenY < pSize.height - 1)) { g.drawLine ( iScreenX - 2, iScreenY, iScreenX + 2, iScreenY); // horizontales Strichlein links von 0 g.drawString ("-" + new Long(i * lRasterAbstand + addFaktor).toString(), iScreenX + 5, iScreenY + 5); } } } } if ((m_dStartY <= 0) && (m_dEndY >= 0)) { // X-Achse g.setColor (Color.black); iScreenY = pSize.height - (int)( (0 - m_dStartY) * pSize.height / rangeHeight); g.drawLine ( 0, iScreenY, pSize.width - 1, iScreenY); g.drawString ("x-Achse", pSize.width - 47, iScreenY - 4); // Skala auf X-Achse einzeichnen lRasterAbstand = Math.round (rangeWidth / 10); // lRasterAbstand berechnen if (lRasterAbstand != 0) { if (m_dStartX > 0) { addFaktor = Math.round(m_dStartX) - 1; } else if (m_dEndX < 0) { addFaktor = -Math.round(m_dEndX) - 1; } else { addFaktor = 0; } // Wenn 0 in der Mitte liegt for (int i = 1; i < 12; i++) { iScreenX = (int)( (i * lRasterAbstand + addFaktor - m_dStartX) * pSize.width / rangeWidth); if ((iScreenX > 0) && (iScreenX < pSize.width - 1)) { g.drawLine ( iScreenX, iScreenY - 2, iScreenX, iScreenY + 2); // vertikales Strichlein rechts von 0 g.drawString ( new Long(i * lRasterAbstand + addFaktor).toString(), iScreenX - 2, iScreenY + 14); } iScreenX = (int)( (0 - m_dStartX - i * lRasterAbstand - addFaktor) * pSize.width / rangeWidth); if ((iScreenX > 0) && (iScreenX < pSize.width - 1)) { g.drawLine ( iScreenX, iScreenY - 2, iScreenX, iScreenY + 2); // vertikales Strichlein links von 0 g.drawString ("-" + new Long(i * lRasterAbstand + addFaktor).toString(), iScreenX - 6, iScreenY + 14); } } } } /* Zeichenfarbe setzen */ g.setColor (Color.blue); /* ############################################################################### Bitte UNTERHALB dieses Kommentars den Programmcode einfügen ############################################################################### */ int ispalte = 1; int altx int alty //Pixel pro Längeneinheit berechnen double apixel_prolex = pSize.width / (m_dEndX-m_dStartX); double apixel_proley = pSize.height / (m_dEndY-m_dStartY); while (ispalte <= pSize.width) { //x Wert berechnen double x = ispalte / apixel_prolex+m_dStartX; //x Wert an Funktion übergeben, die y berechnet dFunktionsWert = parser.evaluate(x); //zeilennummer berechnen double zeile = (dFunktionsWert - m_dStartY) * apixel_proley; int y = pSize.height - (int) zeile; g.setColor ( Color.red ); g.drawLine( altx, alty, ispalte, y); altx = ispalte alty = y ispalte++; } /* ############################################################################### Bitte OBERHALB dieses Kommentars den Programmcode einfügen ############################################################################### */ } } private void InitPlotFrame() { // Ein paar allgemeinere Inits und Checks if (m_dEndX == Double.NaN) { m_dEndX = 5; } if (m_dStartX == Double.NaN) { m_dStartX = -5; } if (m_dEndY == Double.NaN) { m_dEndY = 5; } if (m_dStartY == Double.NaN) { m_dStartY = -5; } m_dInitialEndX = m_dEndX; // Startwerte der Grenzen speichern m_dInitialStartX = m_dStartX; m_dInitialStartY = m_dStartY; m_dInitialEndY = m_dEndY; rangeWidth = Math.abs(m_dEndX - m_dStartX); // Breite und... rangeHeight = Math.abs(m_dEndY - m_dStartY); // ... Höhe der Ausgabe ausrechnen dummyThis = this; // Ein paar AWT-Inits WindowListener ExitListener = new WindowAdapter() { // Event-Methode die beim Schließen aufgerufen wird public void windowClosing (WindowEvent ThisEvent) { setVisible (false); // Fenster verschwinden lassen parent.KickMe(dummyThis); // Aus Fensterliste kicken... // dispose(); // und killen... } }; addWindowListener(ExitListener); // Event-Handling aktiv. pCanvas = new PlotCanvas(); add (pCanvas); setSize(400, 400); // Größe wie in html-Datei show(); // und anzeigen (visible=true)... } }