# Verschiedene Zeichenwerkzeuge



## fat32 (29. Nov 2009)

Hi,

ich stehe gerade vor dem Problem, dass es in meinem geplanten Programm mehrere Zeichenwerkzeuge geben soll (so wie bei Paint: Stift, Kreis, Rechteck, ...)

Diese Werkzeuge müssen in der Lage sein, das Bild zu manipulieren. Das erste Problem:
Jedes Werkzeug braucht andere Informationen. Manche brauchen die Mausposition, andere die gerade gewählte Farbe, wieder andere brauchen nur das Bild, usw.

Wie mache ich das am besten? Mir fällt nichts besseres ein, als dass ich eine Klasse mache, deren Objekte alle möglichen Informationen aufnehmen kann (Registry) und sich dann die Werkzeuge die benötigten Infos holen. Diese Möglichkeit kommt mir ziemlich unsauber vor.

Dann habe ich noch das Problem, dass bei manchen Funktionen (insb. Kreis und Rechteck) erst entgültig auf das Bild gezeichnet werden soll, wenn ein Dragvorgang beendet ist.
Solange die Maustaste gedrückt ist und die Maus bewegt wird, soll eine "Vorschau" angezeigt werden. 

Das letzte Problem ist die Rückgängig-Funktion. Ich könnte das Command-Pattern implementieren und vor jeder Änderung am Bild eine aktuelle version als Kopie ablegen. Das ist aber sehr speicherintensiv. Dafür wäre es realtiv einfach zu realisieren.
Eine andere Möglichkeit wäre es, jeweils nur die geänderten Pixel zu speichern. Aber wie mache ich das bei einem Kreis, den ich per drawArc() gezeichnet habe? 

Fragen, Fragen, Fragen...

Ich hoffe, ihr könnt mir ein paar Ideen geben 

MfG
Simon


----------



## Gast2 (29. Nov 2009)

fat32 hat gesagt.:


> Das erste Problem:
> Jedes Werkzeug braucht andere Informationen. Manche brauchen die Mausposition, andere die gerade gewählte Farbe, wieder andere brauchen nur das Bild, usw.


kein Problem 

```
public abstract class Werkzeug {
    public abstract paintVorschau( [...] );
    public abstract paintReal( [...] );
}
```



> Wie mache ich das am besten? Mir fällt nichts besseres ein, als dass ich eine Klasse mache, deren Objekte alle möglichen Informationen aufnehmen kann (Registry) und sich dann die Werkzeuge die benötigten Infos holen. Diese Möglichkeit kommt mir ziemlich unsauber vor.


mit Vererbung und Polymorphie



> Das letzte Problem ist die Rückgängig-Funktion.


Reihenfolge merken wie die Werkzeuge verwendet wurden -> Stack


----------



## Marco13 (29. Nov 2009)

Das schreibt sich so leicht hin. Kann aber tricky sein, wenn man es wirklich mal _implementieren_ will. Besonders das Rückgängigmachen ist schwierig, wenn _nach_ der Operation alles zu einem Haufen Pixeln zusammenfällt...


----------



## Gast2 (30. Nov 2009)

Moin,

wenn Du einen Schritt zurück gehst zeichnest Du eben das gesammte Bild nochmal ... bis auf den obersten Pinsel ... dann kannst Du das Ganze mit Pixeln machen ... ich sehe da nicht das Problem ... wobei ich nicht weis ob man durch einen Stack iterieren kann ... evt. wäre da eine andere Datenstruktur besser geeignet


----------



## fat32 (30. Nov 2009)

Danke!

Bin schon recht weit gekommen.

Momentan seht es so aus:

*DrawingController*
Dieser Controller beinhaltet einen Stack (ArrayList), der alle Befehle (Linie, Kreis, Stift, ...) beinhaltet. Der wird dann später für die Rückgängig-Funktion verwendet.

Der DrawingController gibt alle Mausbewegungen an den letzten DrawingCommand (Linie, Kreis, Stift, ...) weiter. Dort wird dann individuell entschieden, was passieren soll.

*DrawingCommand*
Ein DrawingCommand erhält das aktuelle Bild und bekommt vom DrawingController Mausbewegungen und Klicks mitgeteilt. Bei Bedarf manipuliert er dann das Bild.
Ist der Command beendet, ruft er eine Methode im DrawingController auf, die diesen Controller dazu veranlasst, einen neuen Command desselben Typs zu erstellen.
Dadurch erreiche ich, dass beim Rückgängig-Machen Einzelschritte rückgängig gemacht werden können.

Wie ist diese Vorgehensweise? Gut/Schlecht? Warum?

*Kreis zeichnen*
Mein Problem ist jetzt aber, dass es manche Funktionen gibt, die erst beim Loslassen der Maus das Bild "entgültig" manipulieren sollen. Ein Beispiel hierfür wäre die Kreismalfunktion. Bei dieser Funktion bestimmt man durch den ersten Klick den Mittelpunkt des Kreises und kann die Maus dann bewegen. Dadurch ändert man den Radius. Lässt man die Maus jetzt los, wird der Kreis erst aufs Bild gemalt.

Aber wie mache ich das? Ich möchte ja, dass man während der Mausbewegung schon sieht, wie groß der Kreis später mal wird.

Ich habe mir überlegt, ein transparentes Bild über mein Hauptbild zu legen und dann darauf zu zeichnen, solange die Maus gedrück ist. Erst wenn die Maus losgelassen wird, soll der Kreis dann vom Transparenten Bild ins richtige Bild kopiert werden.
Nur wie lege ich ein transparentes Bild über ein BufferedImage? Konnte beim Googeln nix finden...

Eine andere Möglichkeit wäre, dass ich am Beginn des Kreis-Zeichnens eine Kopie des aktuellen Zustands anfertige. Diesen Zustand lade ich dann immer wieder, bevor ich die "neue" Vorschau darstelle.
Dürfte aber ziemlich rechenaufwändig sein, oder?

Ich freue mich auf eure Antworten!


----------



## Grey_M (3. Dez 2009)

Ich habe mal ein ganz simples Malprogramm gemacht.
http://ma-tech.de/site/index.php?option=com_wrapper&view=wrapper&Itemid=6

Sourcecode
http://ma-tech.de/services/mapaintboard/MA Paintboard.zip

Würde ich es nochmal machen, dann würde ich die Zeichenoperationen (z.B: Kreis malen), in einer Liste speichern. Damit kann man dann das mit dem Rückgängig realisieren. Einfach die Operation aus der Liste löschen, die Zeichenfläche zurück setzen und die restlichen Operationen der Liste nacheinander durchführen.

Zumindest siehst du in dem Programm, wie man das mit dem Zeichnen von Rechtecken und Kreisen hinkriegt, denn das funktioniert so wie du es willst.


----------



## fat32 (3. Dez 2009)

Jo, danke

mein Programm habe ich mittlerweile fertig und abgegeben. (Mit rückgängig)
Sobald es bewertet, stelle ich es auf meinen Blog und hier rein... Würde mich dann freuen, wenn ihr meinen Programmierstil bewerten würdet 

Ich stelle es jetzt noch nicht rein, weil mein Lehrer das nicht unbedingt im Internet finden sollte ---> 0 Punkte 

MfG
Simon

EDIT: Das Programm ist klein, aber fein  Nur der Downloadlink ist wohl in die Hose gegangen. Kannst du den Link korrigieren? Mich würde der Code sehr interessieren


----------



## Grey_M (4. Dez 2009)

Der Downloadlink hat am Ende ein Leerzeichen und das mag das Forum wohl nicht....

http://ma-tech.de/services/mapaintboard/MA Paintboard.zip

Edit: Wie hast du nun das mit dem Rückgängig gelöst?


----------



## fat32 (4. Dez 2009)

Hi,

das mit dem Rückgängig hab ich so gelöst:

Immer, wenn etwas gezeichnet wird, wird ein Objekt einer bestimmten Klasse erstellt. Diese Klassen sind alle von DrawingCommand abgeleitet.

So kann ich die Zeichenschritte bequem in einem Stack ablegen.

Wird nun etwas rückgängig gemacht, entferne ich das letzte Elements des Stacks und lege es auf den redoStack (um es später wiederholen zu können)
Jetzt werden alle verbleibenden Elemente neu gezeichnet, indem die execute-Methode aufgerufen wird.

MfG
Simon


----------

