Paint - Objektorientiert DVG3 - Paint - Objektorientiert 1 Bisheriger Ansatz DVG3 - Paint - Objektorientiert 2 Alles in einem großen Programm (über 700 Zeilen, 20 KByte). Programm weiß Alles, steuert Alles. Programm wird sehr unübersichtlich. Um die Programmlänge zu begrenzen, wird Programmtext mehrfach verwendet. Es entstehen Abhängigkeiten, die nicht inhaltlich erforderlich sind. Erweiterungen, Modifikationen, Korrekturen sind schwierig und haben oft Auswirkungen auf andere Programmbereiche und funktionen. Weiterentwicklung ist nur mit hohem Aufwand möglich und außerdem sehr fehleranfällig. Bestimmte Funktionen (z.B. Korrekturen auf der Ebene von graphischen Objekten, Vergrößern oder Verkleinern des Bildes) sind kaum oder nur mit sehr hohem Aufwand realisierbar. Objektorientierter Ansatz DVG3 - Paint - Objektorientiert 3 Hauptprogramm ist zuständig für: das Layout (Buttons, Labels, LayoutMenagar u.s.w.) die Programminitialisierung (Einstellen der Standardwerte, Erzeugen des ersten graphischen Objektes u.s.w.) den Programmablauf (Reaktion auf Buttons, Checkboxen u.s.w.) die Programmbeendigung (Abspeichern geänderter Bilder) DVG3 - Paint - Objektorientiert 4 Jedes graphische Teil (Punkt, Linie, Oval, Rechteck u.s.w.) stellt ein Objekt einer speziellen Klasse dar. Graphische Objekte sind zuständig für: die Behandlung von Mausereignissen ihre graphische Darstellung in endgültiger bzw. in grober Form. die Bereitstellung von Hilfetexten ihre Identifizierung im Statusbereich die Erzeugung des Protokolltextes die Bereitstellung eines Nachfolgeobjektes ihre Speicherung in einer Liste alle graphischen Objekte ihre Transformation Alle graphischen Objekte müssen diese Funktionen realisieren. Alle graphischen Objekte realisieren diese Funktionen verschieden. Alle Klassen für graphische Objekte werden von einer Elternklasse abgeleitet. Die Klasse PaintableObject import java.awt.Graphics; import java.io.Serializable; import java.awt.event.MouseEvent; DVG3 - Paint - Objektorientiert 5 public { public public public public public public public public public public public public } abstract class PaintableObject implements Serializable abstract void paint(Graphics g, Paint parent); void raw(Graphics g, Paint parent){ paint(g, parent); } void transform(double x0, double y0, double mx, double my){} String getCommand(){ return toString(); } String help(){ return "No Help available!"; } PaintableObject mouseClicked(MouseEvent e){return this;} PaintableObject mousePressed(MouseEvent e){return this;} PaintableObject mouseDragged(MouseEvent e){return this;} PaintableObject mouseReleased(MouseEvent e){return this;} PaintableObject mouseMoved(MouseEvent e){return this;} PaintableObject mouseEntered(MouseEvent e){return this;} PaintableObject mouseExited(MouseEvent e){return this;} Abstrakte Klasse, da paint nicht implementiert wurde. DVG3 - Paint - Objektorientiert 6 Alle anderen Methode wurden implementiert mit trivialen Methoden, oder als leere Methode. Es sind alle Methoden von MouseListener und MouseMotionListener implementiert. Unterschied: Die Methoden geben ein PaintableObject zurück um: Sich selbst aktiv zu halten, wenn sie noch nicht alle Inforationen zusammenbekommen haben oder Ein neues PaintableObjekt zu erzeugen und an das Hauptprogramm zurückzugeben. Das Interface Serializable ist implementiert, damit die Objekte in einen ObjectOutputStream geschrieben bzw. von einem ObjectInputStream gelesen werden können. Die Klasse PaintPoint DVG3 - Paint - Objektorientiert 7 import import import public { java.awt.Graphics; java.awt.Panel; java.awt.event.MouseEvent; class PaintPoint extends PaintableObject public double x0; // Koordinaten des Punktes public double y0; private transient Paint f; //transient, damit f und p private transient Panel p; //nicht gespeichert werden PaintPoint(Paint f, Panel p) { this.f=f; this.p=p; f.writeMessage(help(0)); f.writeTool("point"); } //Hilfetext ausgeben //Status anzeigen DVG3 - Paint - Objektorientiert 8 public PaintableObject mouseReleased(MouseEvent e) { x0 = e.getX(); //Koordinaten speichern y0 = e.getY(); paint(f.g0, f); //in Bild zeichnen p.paint(p.getGraphics()); //Bild neuzeichnen f.writeProt(getCommand()); //Protokoll schreiben f.appendGraph(this); //Objekt speichern return new PaintPoint(f,p);//neuen Punkt zurückgeben } public void transform (double x0, double y0, double mx, double my) { this.x0=x0+mx*this.x0; //Punkt transformieren this.y0=y0+my*this.y0; } public String toString() { return "PaintPoint : x0 = " //Zeichenkette ausgeben +(int)Math.round(x0)+"; y0 = "+(int)Math.round(y0); } public void paint(Graphics g, Paint parent) { g.fillOval( //Punkt Zeichnen (int)Math.round(x0-1),(int)Math.round(y0-1),3,3); } DVG3 - Paint - Objektorientiert 9 public String getCommand() { return "g.fillOval("+ //Protokoll erzeugen (int)Math.round(x0-1)+","+ (int)Math.round(y0-1)+",3,3);\n"; } public String help(int step) { return "Punkt setzen!"; } } //help-Text ausgeben Die Klasse Paint import java.awt.*; import java.awt.event.*; import java.awt.image.*; DVG3 - Paint - Objektorientiert 10 public class Paint extends Frame implements MouseListener, MouseMotionListener, WindowListener, ActionListener, ItemListener, ComponentListener { public static void main(String[] args) { new Paint("Paint"); } ... // globale Attribute ... // Konstruktor ... // Definition des Layouts, der Buttons u.s.w. ... // Hilfsmethoden ... // WindowListener ... // ActionListener DVG3 - Paint - Objektorientiert 11 public void actionPerformed(ActionEvent e){ char command = e.getActionCommand().charAt(0); switch (command) { case 'e': dispose(); case 'd': pObject=new PaintPoli(this,gPanel,false); break; case 'p': pObject=new PaintPoint(this,gPanel); break; case 'l': pObject=new PaintLine(this,gPanel); break; case 'r': pObject=new PaintRect(this,gPanel); break; case 'o': pObject=new PaintOval(this,gPanel,false); break; case 'c': pObject=new PaintOval(this,gPanel,true); break; case 'n': pObject=new PaintRoundRect(this,gPanel); break; case '3': pObject=new Paint3DRect(this,gPanel); break; case 'a': pObject=new PaintArc(this,gPanel); break; case 'b': pObject=new PaintPoli(this,gPanel,true); break; case 's': graph.writeFile(this); break; case 'm': graph.readFile(this,g0); graph.paint(g0,this); gPanel.paint(gPanel.getGraphics()); break; case 'i': pObject = new PaintImage(this,gPanel,lastPO); break; } if (! (pObject instanceof PaintImage) ) lastPO=pObject; } //MouseListener, MouseMotionListener public void mouseEntered(MouseEvent e){ pObject=pObject.mouseEntered(e);} public void mouseExited(MouseEvent e){ pObject=pObject.mouseExited(e); } DVG3 - Paint - Objektorientiert public void mouseClicked(MouseEvent e){ pObject=pObject.mouseClicked(e);} public void mousePressed(MouseEvent e){ pObject=pObject.mousePressed(e);} public void mouseDragged(MouseEvent e){ pObject=pObject.mouseDragged(e); showStatus(e.getX(),e.getY()); } public void mouseReleased(MouseEvent e){ pObject=pObject.mouseReleased(e);} public void mouseMoved(MouseEvent e){ pObject=pObject.mouseMoved(e); 12 showStatus(e.getX(),e.getY()); } Überarbeitung DVG3 - Paint - Objektorientiert 13 Vereinfachungen: Die Konstruktoren der graphischen Objekte haben zwei Parameter: • Paint parent – Paintobjekt, das das graphische Objekt enthält • Panel gPanel – Panel, in das gezeichnet werden soll gPanel ist aber in parent bekannt, kann also bei geeigneter Wahl der Zugriffsrechte aus parent bestimmt werden. Dieser Parameter kann also eingespart werden. • gPanel.paint(...) parent.gPanel.paint(...) • Graphik-Kontexte von gPanel (onScreen) und offImage (offScreen) werden häufig benötigt friendly Attribute in Paint: Graphics onGraphics Graphics offGraphics Das Attribut PaintableObject pObject (actualObject) zeigt auf das nächste zu bearbeitende Objekt. actualObject friendly Listener-Methoden können actualObject direkt setzen actualObject braucht nicht als Wert zurückgegeben zu werden. DVG3 - Paint - Objektorientiert 14 Konsequente Überprüfung der Zugriffsrechte public, private und "friendly". Realisierung von Funktionen, die in allen von PaintableObject benötigten Funktionen in PaintableObject, z.B.: Definition des Attributes parent Speichern des Attributes parent Ausgabe des Help-Textes Anzeige des Tool-Status public abstract class PaintableObject implements Serializable { transient Paint parent; public PaintableObject(Paint parent) { this.parent = parent; parent.writeMessage(help()); //Hilfetext ausgeben parent.writeTool(tool()); //Status anzeigen } Klassifzierung PaintLine, PaintRect, Paint3DRect, PaintRoundRect und PaintOval sind ähnlich: DVG3 - Paint - Objektorientiert Gemeinsamkeiten: • Zwei charakteristische Punkte • Transformations-Methoden sind gleich • Art des Zeichnens: Maus mit gedrückter Taste vom ersten zum zweiten Punkt ziehen und Taste dann loslassen. • Helptexte z.T. gleich Unterschiede: • PaintLine hat keinen Füllmodus • Paint3DRect hat raised-Modus • PaintOval besitzt Kreis-Modus • Paint-Methoden, Tool-Bezeichnungen, toString-Methoden, getCommand-Methoden sind unterschiedlich Wir definieren eine abstrakte Klasse Paint2Point als Elternklasse für die genannten Klassen. 15 Paint2Point DVG3 - Paint - Objektorientiert 16 import java.awt.event.MouseEvent; public abstract class Paint2Point extends PaintableObject { double x0, y0; double x1, y1; Paint2Point(Paint parent){ super(parent); } public void mousePressed(MouseEvent e) { x0=e.getX(); y0=e.getY(); } public void mouseDragged(MouseEvent e) { x1=e.getX(); y1=e.getY(); parent.gPanel.paint(parent.onGraphics); raw(parent.onGraphics); } DVG3 - Paint - Objektorientiert 17 public void mouseReleased(MouseEvent e) { x1=e.getX(); y1=e.getY(); paint(parent.offGraphics); parent.gPanel.paint(parent.onGraphics); parent.writeProt(getCommand()); parent.appendGraph(this); } public void transform (double x0, double y0, double mx, double my) { this.x0=x0+mx*this.x0; this.x1=x0+mx*this.x1; this.y0=y0+my*this.y0; this.y1=y0+my*this.y1; } public String help() { return "Erste Ecke eingeben und Maus mit gedrueckter" +" Taste zur gegenueberliegende Ecke bewegen!"; } } PaintLine DVG3 - Paint - Objektorientiert 18 import java.awt.Graphics; import java.awt.event.MouseEvent; public class PaintLine extends Paint2Point { PaintLine(Paint parent) { super(parent); } public void mouseReleased(MouseEvent e) { super.mouseReleased(e); parent.actualObject= new PaintLine(parent); } public String toString() { return "PaintLine : x0 = "+(int)Math.round(x0)+ "; y0 = "+(int)Math.round(y0)+"; x1 = "+ (int)Math.round(x1)+"; y1 = "+(int)Math.round(y1); } public void paint(Graphics g) { g.drawLine((int)Math.round(x0),(int)Math.round(y0), (int)Math.round(x1),(int)Math.round(y1)); } DVG3 - Paint - Objektorientiert 19 public String getCommand() { return "g.drawLine("+(int)Math.round(x0)+","+ (int)Math.round(y0)+","+(int)Math.round(x1)+","+ (int)Math.round(y1)+");\n"; } public String help() { return "Anfangspunkt eingeben und Maus mit gedrueckter "+ "Taste zum Endpunkt bewegen!"; } public String tool(){ return "line"; } } Paint3DRect DVG3 - Paint - Objektorientiert 20 import java.awt.Graphics; import java.awt.event.MouseEvent; public class Paint3DRect extends Paint2Point { private boolean fill; private boolean raise; public Paint3DRect (Paint parent){ super(parent); } public void mousePressed(MouseEvent e){ super.mousePressed(e); fill=parent.fillMode; raise=parent.raiseMode; } public void mouseReleased(MouseEvent e){ super.mouseReleased(e); parent.actualObject= new Paint3DRect(parent); } DVG3 - Paint - Objektorientiert 21 public String toString(){...} public void paint(Graphics g){ int x=(int)Math.round(Math.min(x0,x1)); int y=(int)Math.round(Math.min(y0,y1)); int w=(int)Math.round(Math.abs(x0-x1)); int h=(int)Math.round(Math.abs(y0-y1)); if (fill) g.fill3DRect(x,y,w,h,raise); else g.draw3DRect(x,y,w,h,raise); } public void raw(Graphics g){ int x=(int)Math.round(Math.min(x0,x1)); int y=(int)Math.round(Math.min(y0,y1)); int w=(int)Math.round(Math.abs(x0-x1)); int h=(int)Math.round(Math.abs(y0-y1)); g.draw3DRect(x,y,w,h,raise); } public String getCommand(){...} } Kombination von graphischen Objekten DVG3 - Paint - Objektorientiert 22 Das gesamte Bild besteht aus der Kombination von einzelnen graphischen Objekten. Das gesamte Bild ist andererseits ein (komplexes) graphisches Objekt. Es hat die gleichen Eigenschaften wie ein einfaches Objekt. Es kann gezeichnet werden (paint, raw) Es kann transformiert werden. Das gesamte Bild wird als Liste von einfachen graphischen Objekten eingerichtet. Dadurch dass PaintGraph von PaintableObject abgeleitet wird, kann die Gruppierungsfunktion realisiert werden. DVG3 - Paint - Objektorientiert 23 public class PaintGraph extends PaintableObject { private LinkedList list = new LinkedList(); private static String saveDirectory = ""; public PaintGraph(Paint parent){ super(parent); } public void append(PaintableObject po){ list.addLast(po); } public void paint(Graphics g){ Object le; for (int i=0;i<list.size();i++ ) { le = list.get(i); ((PaintableObject)le).paint(g); } } public void raw(Graphics g){ Object le; for (int i=0;i<list.size();i++ ) { le = list.get(i); ((PaintableObject)le).raw(g); } } DVG3 - Paint - Objektorientiert 24 public String toString(){ return list.toString(); } public void transform (double x0, double y0, double mx, double my){ Object le; for (int i=0;i<list.size();i++ ) { ((PaintableObject)(list.get(i))).transform(x0,y0,mx,my); } } DVG3 - Paint - Objektorientiert 25 public void writeFile(){ FileDialog fd = new FileDialog(parent,"Select Output File",FileDialog.SAVE); fd.setDirectory(saveDirectory); fd.setVisible(true); saveDirectory = fd.getDirectory(); String fileName = saveDirectory+fd.getFile(); try { ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(fileName)); out.writeObject(parent.getBounds()); out.writeObject(list); out.close(); } catch(Exception e) { System.err.println(e); } } DVG3 - Paint - Objektorientiert 26 public void readFile(Graphics g) { FileDialog fd = new FileDialog (parent,"Select Input File",FileDialog.LOAD); fd.setDirectory(saveDirectory); fd.setVisible(true); saveDirectory = fd.getDirectory(); String fileName = saveDirectory+fd.getFile(); ObjectInputStream in = null; try { in = new ObjectInputStream( new FileInputStream(fileName)); Rectangle rect = (Rectangle)in.readObject(); list = (LinkedList)in.readObject(); in.close(); parent.resize(rect); PaintableObject le; for (int i=0;i<list.size();i++ ) { le=(PaintableObject)(list.get(i)); le.parent=parent; le.paint(g); } } catch(Exception e) { e.printStackTrace(); } DVG3 - Paint - Objektorientiert 27 } }