Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Linie zeichnen mit Vorschau (wie in Paint)
Wolle92 - So 25.05.08 13:36
Titel: Linie zeichnen mit Vorschau (wie in Paint)
Hallo,
ich bin grad etwas am rumexperimentieren, mit nem Zeichenprogramm...
Einfach wild draufloszeichnen geht schon, gibts auch keine Probleme...
Allerdings gibts nen Problem, wenn ich ne Linie zeichnen lassen will, wie bei Paint, also Maus gedrückt halten, ziehen, Maus loslassen...
Und zwar hab ich dann ja immer ne Vorschau wolang meine Linie geht...
Diese Vorschau übermale ich im MouseMove immer wieder mit einer weißen Linie, das Problem ist jetzt, das bereits existierende Linien dadurch dann auch wieder weiß werden an einigen Stellen...
Wie kann ich das Problem lösen? Hat jemand ne Idee?
nagel - So 25.05.08 14:06
Du musst die alte Linie mit Pen.Mode := pmNotXor übermalen.
Wolle92 - So 25.05.08 14:28
dann kommt da irgendwas komisches bei raus...
da wird nicht alles gelöscht, wenn der hintergrund weiß ist...
nagel - So 25.05.08 14:41
Komisch, dachte das geht so.
Hast du die Stiftfarbe geändert?
Wolle92 - So 25.05.08 14:57
äh, ja...
Hab das aber grad mal ohne ändern der Farbe gemacht, bringt auch nix...
Narses - So 25.05.08 15:29
Moin!
nagel hat folgendes geschrieben: |
| Du musst die alte Linie mit Pen.Mode := pmNotXor übermalen. |
Du musst beide Linien mit XOR malen, sonst hebt sich das ja nicht wieder auf. :idea: ;)
cu
Narses
Wolle92 - So 25.05.08 16:01
jetzt wird aber noch der schnittpunkt von zwei linien weiß...
einfach nochmal ne schwarze Linie mit pmCopy drüber?
Narses - So 25.05.08 16:17
Moin!
Wolle92 hat folgendes geschrieben: |
| jetzt wird aber noch der schnittpunkt von zwei linien weiß... |
Was willst du denn machen? Eine Vorschau, so wie die Linie nachher auch gezeichnet aussehen würde? Oder nur eine Visualisierung, wo es lang geht... :nixweiss:
Im ersten Fall musst du halt das Bitmap vor dem Zeichnen kopieren und dann dazu verwenden, deine Vorschau-Linie wieder zu entfernen (betreffenden Bereich zurück kopieren - oder einfach das ganze Bitmap wiederherstellen).
cu
Narses
Hidden - So 25.05.08 16:36
Ich würde die bisherigen Zeichnungen auf eine Bitmap zeichnen, die du im OnPaint auf deine PaintBox(du verwendest doch TPaintBox?) zeichnest. Deine Vorschau zeichnest du dann einfach außerhalb des OnPaint auf die PaintBox, ist also nichts permanentes.
Wolle92 - So 25.05.08 17:49
Nein, ich benutze TImage, steht auch im Titel...
Ich will einfach sowas machen wie bei Paint...
Also MouseDown, Linie ziehen, MouseUp -> Linie...
Und wenn sich dann zwei Linien schneiden, auch während des Ziehens, dann sollen die trotzdem durchgezogen werden und sich nicht stören...
ub60 - So 25.05.08 17:54
So geht es:
MouseMove:
-Zeichnen der Vorschau: pmNotXor
-Löschen: pmNotXor
MouseUp:
-abschließendes Zeichnen: pmCopy
ub60
Wolle92 - So 25.05.08 19:50
so hab ichs auch gemacht...
Hidden - So 25.05.08 20:44
Hi,
die PaintBox ist ja sowieso besser und kannst du a leicht austauschen. Da du so eine "reserveBitmap" sparst, empfehle ich den Umstieg.
mfG,
Wolle92 - So 25.05.08 21:12
Irgendwie gefällt mir die Lösung bei farbig gefüllten Rechtecken nicht, da alles was dahinter ist immer weiß, schwarz, gelb, rot oder sonstwie wird...
Vielleicht nehm ich doch die PaintBox?
Hidden - So 25.05.08 21:28
Hi,
IMHO hast du drei Möglichkeiten:
- Du lässt es mit XOR und akzeptierst die Auswirkungen
- eine Funktion, die "XOR für nicht-Schwarz" macht, gibt es IMHO nicht. So etwas müsstest du selbst schreiben, wäre aber unperformant, du müsstest die Pixel einzeln betrachten
- Du nimmst eine "Backup"-Bitmap. IMHO dann gleich die(imho sauberere) PaintBox
mfG,
Wolle92 - Mo 26.05.08 13:15
Irgendwie mag mich die Bitmap aber nicht... Ich kann egal was ich mache immer nur direkt aufs Image / auf die PaintBox zeichen, mit der Bitmap geht gar nix...
Hidden - Mo 26.05.08 17:05
Hi,
Deine Frage war nicht ganz präzise. Insofern umreiße ich einfach mal, wie es klappen müsste:
- (Create;)
- SetSize(paintBox.Width, PaintBox.Height);
- ganz normal draufzeichnen, bei jeder Änderung der Bitmap PaintBox.Repaint
- ins Paint-Ereignis der PaintBox: PaintBox.Canvas.Stretchdraw(PaintBox.ClientRect, Bitmap)
- (am Ende freigeben)
Wenn das so nicht klappt, lass mal ein bisschen Code sehen.
mfG,
Wolle92 - Mo 26.05.08 17:18
jetzt versteh ich gar nix mehr...
Wie kann ich denn dann das MouseMove und so mit der Bitmap verbinden?
Hidden - Mo 26.05.08 17:22
Hi,
Du musst das MouseMove der PaintBox verwenden.
Eine PaintBox ist eine Zeichenfläche, die nach jedem neuen Zeichnen wieder grau ist: der Inhalt wird nicht gespeichert.
Die PaintBox hat ein OnPaint-Ereignis, in dem du das Bild auf ihr erneuern musst. In diesem zeichnest du nun die Bitmap auf die PaintBox.
Den nichtpermanenten Strich zeichnest du im OnMouseMove direkt auf die PaintBox, er wird also beim nächsten Repaint weg sein. Am Ende, wenn die Maus abgesetzt wird, zeichnest du den Strich dann auf die Bitmap und machst ihn so permanent.
Noch ein PaintBox.Repaint und alles ist zu sehen.
mfG,
Wolle92 - Mo 26.05.08 17:33
das flimmert aber wie sonstwas...
und trotzdem ich eigentlich beim onmouseup die linie dann direkt in die Bitmap zeichne wirs die nicht gespeichert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53:
| procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin mouseDown := true; startX := X; startY := Y; oldX := X; oldY := Y; Bitmap1.Canvas.MoveTo(X, Y); end;
procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin StatusBar1.Panels[1].Text := IntToStr(X) + ', ' + IntToStr(Y); PaintBox1.Repaint; if not mouseDown then Exit; case drawMode of dmFree: begin Bitmap1.Canvas.LineTo(X, Y); end; dmLine: begin with PaintBox1.Canvas do begin MoveTo(startX, startY); LineTo(X, Y); oldX := X; oldY := Y; end; end; dmBorderRect: begin with PaintBox1.Canvas do begin Rectangle(startX, startY, X, Y); oldX := X; oldY := Y; end; end; end; end;
procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin mouseDown := false; case drawMode of dmLine: Bitmap1.Canvas.LineTo(startX, startY); dmBorderRect: Bitmap1.Canvas.Rectangle(startX, startY, oldX, oldY); end; end; |
Hidden - Mo 26.05.08 17:57
Wolle92 hat folgendes geschrieben: |
das flimmert aber wie sonstwas...
und trotzdem ich eigentlich beim onmouseup die linie dann direkt in die Bitmap zeichne wirs die nicht gespeichert:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50:
| procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin mouseDown := true; startX := X; startY := Y; oldX := X; oldY := Y; Bitmap1.Canvas.MoveTo(X, Y); end;
procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin StatusBar1.Panels[1].Text := IntToStr(X) + ', ' + IntToStr(Y); PaintBox1.Repaint; if not mouseDown then Exit; PaintBox1.Repaint; case drawMode of dmFree: Bitmap1.Canvas.LineTo(X, Y); dmLine: begin PaintBox1.Canvas.MoveTo(startX, startY); PaintBox1.Canvas.LineTo(X, Y); oldX := X; oldY := Y; end; dmBorderRect: begin PaintBox1.Canvas.Rectangle(startX, startY, X, Y); oldX := X; oldY := Y; end; end; end;
procedure TForm1.PaintBox1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin mouseDown := false; case drawMode of dmLine: begin Bitmap1.Canvas.MoveTo(oldX, oldY); Bitmap1.Canvas.LineTo(startX, startY); end; dmBorderRect: Bitmap1.Canvas.Rectangle(startX, startY, oldX, oldY); end; PaintBox1.Repaint; end; | |
Hast du ins OnPaint reingeschrieben "PaintBox1.Canvas.Stretchdraw(PaintBox1.ClientRect, Bitmap1)"?
G-S - Mo 26.05.08 18:10
Wie wärs, wenn du 2 TIMages verwendest?
Auf der unteren ist das eigentlich Bild, auf der oberen die Linie und diese wird erst bei OnMouseClick auf die untere übertragen, somit brauchst du das obere Image-Objekt nur zu "leeren".
Wolle92 - Mo 26.05.08 18:25
daran hatte ich auch est gedacht, jetzt bin ich aber auf die PaintBox umgestiegen...
Ja, ich habs ins OnPaint reingepackt
Hidden - Mo 26.05.08 19:19
G-S hat folgendes geschrieben: |
Wie wärs, wenn du 2 TIMages verwendest?
Auf der unteren ist das eigentlich Bild, auf der oberen die Linie und diese wird erst bei OnMouseClick auf die untere übertragen, somit brauchst du das obere Image-Objekt nur zu "leeren". |
Hi,
Das ist genau der falsche Ansatz. Man braucht stets maximal eine Bildausgabe.
mfG,
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!