Scrollbox-Scrollposition/Zeichnen u. Löschen direkt auf Imag

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Antworten
GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

Scrollbox-Scrollposition/Zeichnen u. Löschen direkt auf Imag

Beitrag von GU_Meyer »

Hallo,

das hier http://www.lazarusforum.de/viewtopic.php?f=25&t=8844 angefangene Kartenprojekt geht weiter und ich stehe vor einem größeren Problem: Das mit den Shapes ist eine gute Lösung, aber die Karte, um die es mir geht, muss größer sein können. Um nun den Ausschnitt verschieben zu können, denke ich an eine Scrollbox - soweit so einfach. Aber jetzt brauche ich eure Hilfe:
1. Gibt es eine Möglichkeit, die aktuelle Position (den sichtbaren Bildausschnitt) eines TImages in einer TScrollbox zu ermitteln? EIne Abfrage von ScrollBox.VertScrollBar.Position (hier nur als Beispiel) funktioniert nicht. Damit weiß ich nicht, welcher Teil des TImage (und damit auch der Karte) sichtbar ist und kann die darübergelegten Shapes nicht mit verschieben.
2. Wenn ich auf die Scrollbox verzichte und statt der Shapes direkt auf das TImage zeichne, umgehe ich das Verschiebeproblem. Aber: Die gezeichneten Kreise (für meine Anwendung brauche ich Kreise) lassen sich nicht wieder entfernen - oder geht das? Und außerdem brauche ich eine Möglichkeit, zu ermitteln, welcher Kreis angeklickt wird (die Kreise liefern einen Index, den ich für die Abfrage weiterer Daten brauche). Oder gibt es für diesen Punkt auch eine Lösung?

Mir wäre eine Lösung für den ersten Weg (mit der Scrollbox) lieber - es sei denn, eine Lösung für den zweiten Weg ist viel eleganter. Falls es gar keine Lösung gibt, müsste ich das ganze ins 3D umbauen (GLScene - eine grundsätzliche Lösung dafür hätte ich, aber das muss doch auch so gehen).

Vielen DAnk schon mal fürs Lesen und auch fürs Helfen.
Gruss
GU_Meyer

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Scrollbox-Scrollposition/Zeichnen u. Löschen direkt auf

Beitrag von Michl »

GU_Meyer hat geschrieben:EIne Abfrage von ScrollBox.VertScrollBar.Position (hier nur als Beispiel) funktioniert nicht.
Doch, das geht. Ein einfaches Bsp. anbei (nur schnell zusammengeschustert, mit Feststellung, welches TShape geklickt wurde):

Code: Alles auswählen

procedure TForm1.Image1Click(Sender: TObject);
var
  aShape: TShape;
  MousePoint: TPoint;
begin
  aShape := TShape.Create(Self);
  aShape.Caption := 'Shape Nummer ' + IntToStr(FShapeCounter);
  aShape.OnClick := @ShapeClick;
  aShape.Shape := stCircle;
  aShape.Width := 21;
  aShape.Height := 21;
  aShape.Brush.Color := clRed;
  MousePoint := Mouse.CursorPos;
  MousePoint := ScrollBox1.ScreenToClient(MousePoint);
  aShape.Left := MousePoint.x - 10;
  aShape.Top  := MousePoint.y - 10;
  aShape.Parent := ScrollBox1;
  aShape.BringToFront;
 
  Caption := 'Position Vertical: ' + IntToStr(ScrollBox1.VertScrollBar.Position) +
             ' - Horizontal: ' + IntToStr(ScrollBox1.HorzScrollBar.Position);
 
  Inc(FShapeCounter);
end;


Zu 2.: Wenn du immer im Event OnPaint vom TImage zeichnest, wird das Image selbst nie überzeichnet, da immer nur auf das aktuell dargestellte Canvas gezeichnet wird (das Original bleibt unverändert). Du bräuchtest dann ein Array oder eine TList, welche deine Punktkoordinaten hält. OnClick müsstest du selbst auswerten, ob der Klick innerhalb eines Punktkoordinatenradiuses liegt.

Ich weiss nicht wie groß deine Karten werden. Ein TImage stößt irgendwann an seine Grenzen. Wahrscheinlich würde ich in so einem Fall die Karte teilen und immer nur die benötigten Teile in Bitmaps laden und auf irgend einem Control zusammengesetzt darstellen. Das bedeutet zwar einiges an Programmieraufwand, macht sich aber sicher in der Performance bemerkbar.
Dateianhänge
ScrollImage.zip
(355.53 KiB) 99-mal heruntergeladen

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

GU_Meyer
Beiträge: 66
Registriert: Mo 21. Apr 2014, 10:22

Re: Scrollbox-Scrollposition/Zeichnen u. Löschen direkt auf

Beitrag von GU_Meyer »

Hallo,
Michl hat geschrieben:
GU_Meyer hat geschrieben:EIne Abfrage von ScrollBox.VertScrollBar.Position (hier nur als Beispiel) funktioniert nicht.
Doch, das geht. Ein einfaches Bsp. anbei (nur schnell zusammengeschustert, mit Feststellung, welches TShape geklickt wurde):

Code: Alles auswählen

procedure TForm1.Image1Click(Sender: TObject);
var
  aShape: TShape;
  MousePoint: TPoint;
begin
  aShape := TShape.Create(Self);
  aShape.Caption := 'Shape Nummer ' + IntToStr(FShapeCounter);
  aShape.OnClick := @ShapeClick;
  aShape.Shape := stCircle;
  aShape.Width := 21;
  aShape.Height := 21;
  aShape.Brush.Color := clRed;
  MousePoint := Mouse.CursorPos;
  MousePoint := ScrollBox1.ScreenToClient(MousePoint);
  aShape.Left := MousePoint.x - 10;
  aShape.Top  := MousePoint.y - 10;
  aShape.Parent := ScrollBox1;
  aShape.BringToFront;
 
  Caption := 'Position Vertical: ' + IntToStr(ScrollBox1.VertScrollBar.Position) +
             ' - Horizontal: ' + IntToStr(ScrollBox1.HorzScrollBar.Position);
 
  Inc(FShapeCounter);
end;


Das ist genau das, was ich wollte! Ganz vielen Dank! Jetzt muss ich das noch genau studieren, um es in meinem Quelltext zu integrieren...aber das kann ich :D

Michl hat geschrieben:Zu 2.: Wenn du immer im Event OnPaint vom TImage zeichnest, wird das Image selbst nie überzeichnet, da immer nur auf das aktuell dargestellte Canvas gezeichnet wird (das Original bleibt unverändert). Du bräuchtest dann ein Array oder eine TList, welche deine Punktkoordinaten hält. OnClick müsstest du selbst auswerten, ob der Klick innerhalb eines Punktkoordinatenradiuses liegt.

Das ist dann das nächste Problem. Wobei ich so eine Punkteliste sowieso führen muss, da es im Programm eine Anbindung an eine Datenbank gibt und ich eine Zuordnung von Punkt zu Datenbankeintrag habe.
Michl hat geschrieben:Ich weiss nicht wie groß deine Karten werden. Ein TImage stößt irgendwann an seine Grenzen. Wahrscheinlich würde ich in so einem Fall die Karte teilen und immer nur die benötigten Teile in Bitmaps laden und auf irgend einem Control zusammengesetzt darstellen. Das bedeutet zwar einiges an Programmieraufwand, macht sich aber sicher in der Performance bemerkbar.


Ich hab bisher zum Testen eine 2000x2000 Pixel-Karte gehabt, die war noch kein Problem. Viel größere Karten machen bei meinem Anwendungsfall auch kaum Sinn, da es immer nur um begrenzte Bereiche geht. Im Moment fange ich schon ab, dass die Karte nicht zu klein wird, da kann ich dann auch gleich noch prüfen, ob sie zu groß ist. Danke für den Hinweis.

Vielen Dank für die ausführliche Unterstützung....ich hatte nicht gedacht, dass es so vergleichsweise elegant geht.
DAnke und Gruss

GU_Meyer

Antworten