Sign in Join
Wiki copytemporary

TAChart Tutorial: Chart Tools/de: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Einführung
22
33![](/wiki-images/c/c6/ZoomPan06.png)
44
55Charts sind leistungsfähige Werkzeuge, um Beziehungen zwischen Daten darzustellen. Sie sind besonders mächtig, wenn der Benutzer mit ihnen interaktiv arbeiten kann, zum Beispiel:
66
77- in eine Datenreihe mit sehr, sehr vielen Datenpunkten **hineinzoomen**, um mehr Details zu sehen,
88- den sichtbaren Ausschnitt **verschieben**,
99- **Anzeigen von Datenwerten** für die Datenreihen, oder Bestimmen von charakterischen Parametern aus dem Plot.
1010
1111Das [[TAChart]] Package ist mit einer leistungsfähigen Sammlung von Werkzeugen ausgestattet, die hilfreich sind für die Erstellung interaktiver Charts. In diesem Tutorial wollen wir zeigen, wie man diese Werkzeuge anwenden kann.
1212
1313Wenn du nicht mit TAChart vertraut bist, empfehlen wir dir, einen Blick auf das [[TAChart Tutorial: Getting started|"Getting started"-Tutorial]] zu werfen. Natürlich musst du grundlegende Erfahrung im Umgang mit Lazarus und FPC haben.
1414
1515## Vorbereitung
1616
1717Zunächst brauchen wir einen Chart, mit dem wir spielen können. Statt einen Chart neu zu erzeugen, verwenden wir den im Tutorial [[TAChart Tutorial: Getting started|Getting started]] erzeugten einfachen Chart. In diesem Projekt hatten wir mit Hilfe von `TLineSeries`-Komponenten mathematischen Funktionen für x zwischen -10 and 10 graphisch dargestellt. Die Datenwerte wurden in der internen `ListChartSource` jeder Datenreihe gespeichert. Kopiere die Projekt-Dateien (`project1.lpi, project1.lpr, unit1.pas, unit1.lfm`) in einen separaten Ordner für das neue Tutorial.
1818
1919![](/wiki-images/2/2f/Tachart_getting_started_step6.png)
2020
2121## Zoomen und Verschieben - der leichte Weg
2222
2323### Zoomen
2424
2525Das Erzeugen einer Ausschnittsvergrößerung eines Charts wollen wird mit dem englischen Wort "Zoomen" bezeichnen. Das ist ein ganz einfacher Vorgang -- man muss dafür keine einzige Zeile Code schreiben, denn diese Möglichkeit ist schon intern in der `TChart`-Komponente eingebaut. Der Benutzer muss nur mit gedrückter **linker** Maus-Taste um das zu vergrößernde Detail herum ein Rechteck aufziehen. Wichtig ist, dass die Maus von der Ecke links/oben zur Ecke rechts/unten gezogen werden muss, um den Zoom-Effekt zu erhalten. Wenn die Maustaste losgelassen wird, wird der Inhalt des Rechtecks vergrößert und füllt dann den kompletten Chart aus. Einfach.
2626
2727![](/wiki-images/3/34/ZoomPan01.png) ![](/wiki-images/f/f8/ZoomPan02.png)
2828
2929Man kann diesen Vorgang wiederholen, um tiefer und tiefer in den Chart hineinzuzoomen.
3030
3131Um zur originalen, unvergrößerten Ansicht zurückzukehren, klickt man einfach mit der linken Maustaste irgendwo in den Chart oder zieht die Maus mit gedrückter linker Taste in beliebige Richtung - natürlich nicht von links/oben nach rechts/unten, denn das würde weiter hineinzoomen.
3232
3333Falls du aus irgendeinem Grund das Zoomen verbieten möchtest, kannst du die `TChart`-Eigenschaft `AllowZoom` auf `False` schalten. Darüber hinaus gibt es es keine Möglichkeit, das eingebaute Zoom-Verhalten zu beeinflussen. Aber nicht verzagen: etwas weiter unten diskutieren wir die *Chart-Tools*, und damit hat man fast unbegrenzte Möglichkeiten, mit dem Chart zu interagieren.
3434
3535### Verschieben
3636
3737Nachdem du in den Chart hineingezoomt hast, willst du vielleicht den Ausschnitt etwas verschieben, um eine bessere Ansicht zu finden. Dieses Verschieben wird auf Englisch als "Panning" bezeichnet. Auch hier gibt es in `TChart`-Komponente schon eine eingebaute Methode: Verschiebe die Maus mit gedrückter **rechter** Maustaste, und der sichtbare Ausschnitt folgt der Bewegung der Maus. Weitere Kontrollmöglichkeiten hat man mit Hilfe der *Chart-Tools*.
3838
3939![](/wiki-images/8/8b/ZoomPan03.png)
4040
4141Genauso wie beim Zoomen kann man auch hier den Originalausschnitt wiederherstellen, indem man mit der Maus irgendwo in den Chart klickt, oder die Maus mit gedrückter linker Taste in beliebige Richtung zieht (außer von links/oben nach rechts/unten). Bitte beachte, dass man hier die linke Maustaste verwendet, obwohl das Verschieben mit der rechten Maustaste erfolgt ist.
4242
4343Seit Lazarus v2.1+ hat `TChart` eine Eigenschaft `AllowPanning` mit der man das eingebaute Verschieben unterbinden kann. Wie wir aber gleich sehen werden, kann man das Verschieben auch mit Hilfe der *Chart-Tools* ausschalten, so dass ältere Lazarus-Versionen hier keinen Nachteil haben.
4444
4545## Grundlegendes über die Chart-Tools
4646
4747### Was sind die Chart-Tools?
4848
4949Wie du gesehen hast, kann die Programmierung der Zoom- und Panning-Möglichkeiten nicht einfacher sein -- man muss gar nichts tun, diese Möglichkeiten sind schon vorhanden. Aber andererseits sind die eingebauten Routinen recht eingeschränkt: Zoomen funktioniert nur mit Hilfe der linken Maustaste, Verschieben nur mit Hilfe der rechten, es gibt keine Unterstützung des Mausrades, das Zoomen/Verschieben kann nicht auf die horizontale oder vertikale Richtung beschränkt werden, Datenwerte könnten nicht ausgelesen werden, usw, usf.
5050
5151Für vielseitige Möglichkeiten der Benutzerinteraktion wurden mehrere [[TAChart documentation|Chart-Tools]] der `TAChart`-Bibliothek hinzugefügt. Jedes Werkzeug ist für eine bestimmte Aufgabe spezialisiert. Aus Benutzersicht gibt es zwei Typen von Werkzeugen: [[TAChart documentation|Wertebereichs-Tools]] und [[TAChart documentation|Daten-Tools]].
5252
5353- [[TAChart documentation|Wertebereichs-Tools]] verändern den **Wertebereich** des Chart -- das ist das durch die Achsen definierte Sichtfenster auf die Daten. Sie sind zuständig für das Zoomen und Verschieben. Für das Zoomen kann man wählen zwischen [[TAChart documentation|TZoomDragTool]], [[TAChart documentation|TZoomClickTool]] uder [[TAChart documentation|TZoomMouseWheelTool]]. Für das Verschieben gibt es das [[TAChart documentation|TPanDragTool]], [[TAChart documentation|TPanClickTool]] und das [[TAChart documentation|TPanMouseWheelTool]]. Beachte, dass es keine speziellen Werkzeuge gibt, um das Zoomen/Verschieben rückgängig zu machen - diese Möglichkeit ist schon eingebaut.
5454- [[TAChart documentation|Daten-Tools]] ermöglichen interaktiven Zugang auf die Daten, die in den Datenreihen dargestellt sind, oder ermöglichen es sogar, die Daten zu bearbeiten: es gibt ein [[TAChart documentation|TDataPointClickTool]], [[TAChart documentation|TDataPointDragTool]], [[TAChart documentation|TDataPointHintTool]], [[TAChart documentation|TDataPointCrosshairTool]] und ein [[TAChart documentation|TDataPointDistanceTool]].
5555- Falls keines dieser Werkzeuge für den gewünschten Zweck in Frage kommt, gibt es noch das [[TAChart documentation|TUserDefinedTool]], mit dessen Hilfe man sich das erforderliche Verhalten selbst programmieren kann.
5656
5757### Eigenschaften der Chart-Tools
5858
5959All diese Werkzeuge haben eine Eigenschaft namens **`Shift`**, die eine Menge von "Tasten-Codes" enthält, mit denen das Tool aktiviert werden kann. Dies sind die in der LCL standardmäßig vorhandenen Elemente der Aufzählung `TShiftState`.
6060
6161Ein Beispiel: Wenn die `Shift`-Eigenschaft des Tools die Elemente `ssCtrl` und `ssLeft` enthält, dann wird das Tool aktiv, wenn der Benutzer die `Ctrl`-Taste *und* die linke Maustaste drückt. Beachte, dass alle Bedingungen erfüllt sein müssen, das Werkzeug wird nicht aktiv, falls nur die linke Maustaste allein gedückt wird. Jedes Werkzeug muss seine eigene, eindeutige Kombination von `Shift`-Kombinationen haben.
6262
6363Eine Bemerkung über die `Shift`-Werte, die der Tastatur zugeordnet sind: Um Nachrichten über Tastaturereignisse erhalten zu können, muss der Chart fokussiert sind. Falls Werkzeuge nicht wie erwartet funktionieren, versuche, `Chart.SetFocus` aufzurufen; dadurch wird der Chart automatisch fokussiert, wenn der Benutzer die Maus in den Chart bewegt. Der Nachteil der `AutoFocus`-Methode darf aber nicht unerwähnt bleiben: wenn der Benutzer gerade Text z.B. in ein Memo eintippt, die Maus über den Chart bewegt und dann weitertippen möchte, hat das Memo den Fokus verloren, und nachfolgende Tastendrücke werden ignoriert...
6464
6565Es gibt eine weitere Bedingung, die erfüllt sein muss, damit ein Tool aktiv wird: Seine Eigenschaft **`Enabled`** muss auf `true` gesetzt sein (aber das ist die Default-Einstellung). Diese Eigenschaft ist nützlich, wenn mehrere Tools sich dieselben `Shift`-Kombinationen teilen und durch anderen Code aktiviert werden sollen, z.B. durch Klicken auf Buttons auf einer Toolbar.
6666
6767Alle Werkzeuge haben verschiedene **Ereignisse** gemeinsam, die erzeugt werden, bevor oder nachdem eine Taste oder eine Maus-Taste gedrückt oder losgelassen wurde. Bei der Maus werden auch Ereignisse ausgelöst, bevor und nachdem die Maus bewegt wurde. Normalerweise funktionieren die Chart-Tools, ohne dass diese Ereignisse behandelt werden. Aber sie sind nötig, wenn zusätzliche Funktionalität bereitgestellt werden soll. Wir werden dazu weiter unten in diesem Tutorial ein Beispiel finden.
6868
6969### TChartToolset
7070
7171![](/wiki-images/9/9c/TChartToolset-Icon2.png)
7272
7373Alle Chart-Tools sind einer speziellen Komponenten zusammengeführt, `TChartToolset`. Sie befindet sich auf der Komponentenpalette irgendwo in der Mitte der *Chart*-Seite und hat das Icon mit dem roten Schraubenzieher.
7474
7575Die `TChartToolset`-Komponente ermöglicht die Kommunikation zwischen den einzelnen Tools und derm Chart. Aus diesem Grund hat der Chart eine Eigenschaft `Toolset`, die man mit der `TChartToolset`-Instanz verbinden muss. Beachte, dass das eine 1:n-Beziehung ist, d.h. ein Toolset kann von mehreren Charts verwendet werden - ein schönes Feature! Ich sollte auch erwähnen, dass ich häufig vergesse, diese Verbindung herzustellen -- und als Folge einige Zeit aufwenden muss, um herauszufinden, warum die Werkzeuge nicht funktionieren...
7676
7777## Zoomen mit dem Mausrad
7878
7979Aber jetzt genug mit der Theorie! Es ist Zeit für ein praktisches Beispiel.
8080
8181Zunächst sollten wir die Werkzeuge zu unserem Demo-Chart hinzufügen. Zu diesem Zweck benötigen wir ein `TChartToolset` ![](/wiki-images/4/40/TChartToolset-Icon.png). Setze diese Komponente auf das Formular und verbinde sie mit der Eigenschaft `Toolset` des Chart.
8282
8383Obwohl wir noch gar keine Workzeuge im `Toolset` angelegt haben, ist jetzt vielleicht ganz lehrreich, das Programm zu kompilieren und laufen zu lassen. Versuche, so wie eingangs erwähnt, in den Chart zu zoomen oder den Ausschnitt zu verschieben. Oh -- funktioniert nicht mehr! Das ist eine wichtige Beobachtung: Dadurch dass wir ein `TChartToolset` mit dem Chart verbunden haben, wurde das im Chart eingebaute Toolset ersetzt. Aus diesem Grund funktionieren die eingebauten Werkzeuge für Zoomen und Panning nicht mehr.
8484
8585Um diese Funktionen wieder zu ermöglichen, müssen wir ein oder mehrere Tools für Zoomen und Verschieben in die `Toolset`-Komponente einbauen.
8686
8787Was wollen wir erreichen? Vielleicht könnten wir statt der linken und rechten Maustaste das Mausrad für Zoomen/Verschieben verwenden? Und wir könnten mit der nun freigewordenen linken Maustaste ein Tool aktivieren, mit dem man durch Klicken auf einen Datenpunkt dessen Werte auslesen und anzeigen kann.
8888
8989Um für das Zoomen ein Mausrad-Tool zu verwenden, musst du auf dem `ChartToolset1` auf dem Formular oder im Objekt-Baum des Objekt-Inspektores doppelklicken, oder mache jeweils dort einen Rechtsklick und wähle den Eintrag "Werkzeuge bearbeiten" - genauso wie man bei allen Collection-Editoren von TAChart vorgeht. Drücke auf den *"+ Hinzuf"*-Schalter und wähle *"Zoomen mit Mausrad"* aus der heruntergeklappten Liste. Damit erscheint ein neues Element `ChartToolset1ZoomMousewheelTool1` im Objekt-Baum als Kind-Knoten des `ChartToolset1`.
9090
9191![](/wiki-images/2/29/ChartToolset_Editor.png)
9292
9393Wenn man jetzt das Programm laufen lassen würde, dann würde das Zommen immer noch nicht funktionieren, denn das Werkzeug hat Eigenschaften `ZoomFactor` and `ZoomRatio`, die die Zoomstufen pro Mausrad-Raste definieren. Und diese Eigenschaften stehen immer noch auf ihrem Default-Wert `1`. Also: Setze `ZoomFactor` auf den Wert `1.1` und starte des Programm: Jetzt funktioniert das Zoomen.
9494
9595Wenn die das Mausrad zu dir herdrehst, wird der Chart vergrößert, genauso wie wenn du den Bildschirm zu dir heranziehen würdest. Viele Programme arbeiten anders herum: bei der genannten Drehung wird der Chart immer kleiner, wie wenn du dich vom Chart wegbewegen würdest. Wenn du dieses Verhalten bevorzugst, dann musst du den `ZoomFactor` auf eine Zahl kleiner als `1` setzen, zum Beispiel auf `0.9`. (Für den Rest des Tutorials werden wir aber beim Wert 1.1. bleiben).
9696
9797#### Einige Eigenschaften
9898
9999Sehen wir uns nun einige Properties des Mausrad-Zoom-Werkzeugs an: Es gibt ein `AnimationInterval` und `AnimationsSteps` - mit denen kann man eine Animation des Zoom-Effekts erzeugen.
100100
101101Was ist `FixedPoint`? Wenn dieser Wert `true` ist, geht das Zoomen von der Position des Maus-Cursors aus. Wenn man also eine bestimmte Struktur im Chart vergrößern will, kann man hier die Maus auf diese Struktur bewegen und dann das Mausrad drehen. Bei `false` ist das Zoomen immer auf das Zentrum des Chart bezogen; die Position des Maus-Cursors spielt dann keine Rolle. In diesem Fall muss man aber sehr sorgfältig sein, denn man kann auf diese Weise leicht die Orientierung im Chart verlieren.
102102
103103#### Verwendung von ExtentSizeLimit
104104
105105![](/wiki-images/a/a3/ZoomPan04.png)
106106
107107Wenn man aus einem Chart herauszoomt, wird der Chart immer kleiner, und es werden Bereiche sichtbar, die keine Daten mehr enthalten. Da der Benutzer beliebig weit herauszoomen kann, ist irgendwann der eigentliche Datenbereich des Charts nicht mehr erkennbar. Um das zu verhindern, sollten wir den Achsenbereich so begrenzen, dass auf jeden Fall immer Daten angezeigt werden.
108108
109109Zu diesem Zweck hat TAChart die Eigenschaft **`ExtentSizeLimit`**. Unser Chart erstreckt sich in der *x*-Richtung zwischen `-10` und `10`. Daher setzen wir `ExtentSizeLimit.XMax` auf die Differenz `20` und aktivieren diese Einstellung mit `ExtentSizeLimit.UseXMax = true`. Jetzt können wir nicht mehr aus dem ursprünglichen *x* Bereich herauszoomen. Analog sollten wir auch den Bereich der *y*-Achse auf `2` begrenzen.
110110
111111Auf dieselbe Weise könnten wir verhindern, dass zu tief in den Chart hineingezoomt wird und die *x*-Achse einen Bereich von weniger als z.B. `0.01` umfasst. Dafür würden wir entsprechend die Eigenschaften `ExentSizeLimit.XMin` und `ExtentSizeLimit.UseXMin` verwenden.
112112
113113#### Horizontales und vertikales Zoomen
114114
115115Warum eigentlich gibt es zwei Parameter für die Kontrolle des Zoomens, **`ZoomFactor`** und **`ZoomRatio`**? Der Grund dafür ist, dass man auf diese Weise einen nicht-proportionalen Zoom-Effekt erzeugen kann, so dass sich z.B. der Chart nur in der horizontalen Richtung verkleinert, ohne sich in der vertikalen Dimension zu verändern. Um das zu verstehen, betrachten wir die *x* und *y* Richtungen getrennt. Der Zoom-Faktor für die *x*-Richtung wird durch den Wert von `ZoomFactor` allein definiert, während der Zoom-Faktor für die *y*-Richtung durch das Produkt `ZoomFactor*ZoomRatio` bestimmt wird. Solange `ZoomRatio=1` ist, geschieht das Zoomen isotrop in alle Richtungen. Wenn wir `ZoomFaktor=1` und `ZoomRatio=1.1` setzen, lassen wir die *x*-Richtung unverändert, aber zoomen nur in *y*-Richtung. Oder umgekehrt, wenn wir `ZoomRatio = 1/ZoomFactor` setzen, erfolgt das Zoomen nur entlang der *x*-Richtung.
116116
117117Hey -- das wäre eine schöne Bereicherung für unser Programm! Wenn wir uns auf der Tastatur die Lage der Tasten `SHIFT`, `Ctrl` and `Alt` ansehen, dann erinnern diese an die Achsen eines Koordinatensystems: `Ctrl` ist der Ursprung, `SHIFT` stellt die *y*- und `Alt` die *x*-Richtung dar. Daher könnten wir der `SHIFT`-Taste das vertikale Zoomen und der `Alt`-Taste das horizontale Zoomen zuordnen; und "keine Taste" würde dem Fall des isotropen Zoomens entsprechen -- das wäre eine gute "Eselsbrücke", um sich die Tastenkombinationen merken zu können.
118118
119119Wie kann man das implementieren? Setze zwei ZoomMouseWheelTools auf das Formular. Das erste ist für das vertikale Zoomen zuständig. Daher nenne es `ChartToolset1ZoomMousewheelTool_vert`, weise ihm dem `Shift`-Wert `ssShift` zu und setze `ZoomRatio = 1.1` (lasse `ZoomFactor` auf `1`). Das andere Tool soll für das horizontale Zoomen sorgen. Nenne es `ChartToolset1ZoomMousewheelTool_hor`, setze `Shift` auf `ssAlt` und `ZoomFactor = 1.1` und `ZoomRatio = 0.90909090909` ((das ist ungefähr gleich `1/1.1`).
120120
121121Wenn du das Programm laufen lässt, bemerkst du vielleicht, dass das Zoomen nicht mehr funktioniert, nachdem du die `Alt`-Taste gedrückt hast. Das liegt daran, dass diese Taste auch für die Behandlung von Menü-Tasten verwendet wird. Klicke einfach in den Chart, um das Zoom-Tool zu reaktivieren. Oder wähle eine andere Aktivierungstaste für das horizontale Zoom-Tool.
122122
123123## Verschieben mit dem Mausrad
124124
125125Machen wir weiter mit den Verschieben ("Panning"). Warum eigentlich verwenden wir nicht das Mausrad auch für diesen Zweck? Das Verschieben soll nur entlang der Achsenrichtungen möglich sein, also entweder in *x*- oder in *y*-Richtung. Daher fügen wir zwei `TPanMouseWheel`-Komponenten zum `ChartToolset` hinzu und ersetzen im Komponenten-Namen die automatisch angehängten Nummern durch "_hor" und "_vert". Das Tool für das vertikale Verschieben soll wieder mit der `Umsch` Taste, das für das horizontale Veschieben mit der `Alt` Taste aktiviert werden.
126126
127127Zur Festlegung der Verschiebungsrichtung gibt es eine Eigenschaft `WheelUpDirection` mit Default-Wert `pdUp`. Das bedeutet, dass die Drehung am Mausrad in vertikales Verschieben übersetzt wird. Diese Einstellung muss beim Werkzeug für die horizontale Verschiebung auf `pdRight` or `pdLeft` geändert werden.
128128
129129Starte des Programm. Wenn du am Mausrad mit gedrückter `Umsch` oder `Alt` Taste drehst, verschiebt sich der Chart aber nicht, sondern verändert sein Größe wie beim Zoomen... Was ist falsch?
130130
131131Das liegt daran, dass wir für die Zoom- und Verschiebungstools dieselben `Shift`-Einstellungen verwenden. Als Ausweg könnten wir bei den Verschiebungstools zusätzlich auch noch die Einstellung `Strg` zu den `Shift`-Einstellungen hinzufügen. Damit würde das vertikale Verschieben zum Beispiel mit der Tastenkombination `Strg`+`Umsch` aktiviert, das vertikale Zoomen dagegen würde nur `Umsch` allein benötigen.
132132
133133Das ist in der Bedienung aber etwas umständlich. Daher zeigen wir hier einen anderen Ansatz, auch um die Verwendung der Eigenschaft `Enabled` zu demonstrieren. Füge dem Formular eine `Toolbar` mit zwei `ToolButtons` hinzu, die entweder das Zoomen oder das Verschieben einschalten sollen. Nenne den ersten Button `ZoomToolbutton` und setze sein `Down`-Eigenschaft auf `true`. Nenne den zweiten Button entsprechend `PanToolbutton`, aber lasse sein `Down` auf `false`. Außerdem setze bei beiden Schaltern die folgenden Eigenschaften:
134134
135135- `Grouped = true`
136136- `Style = tbsCheck`
137137
138138und weise ihrem `OnClick`-Ereignis den folgenden Code zu:
139139
140140``` pascal
141141procedure TForm1.ZoomPanToolbuttonClick(Sender: TObject);
142142begin
143143 ChartToolset1ZoomMouseWheelTool_iso.Enabled := ZoomToolbutton.Down;
144144 ChartToolset1ZoomMouseWheelTool_vert.Enabled := ZoomToolbutton.Down;
145145 ChartToolset1ZoomMouseWheelTool_hor.Enabled := ZoomToolbutton.Down;
146146
147147 ChartToolset1PanMouseWheelTool_vert.Enabled := PanToolbutton.Down;
148148 ChartToolset1PanMouseWheelTool_hor.Enabled := PanToolbutton.Down;
149149end;
150150```
151151
152152Das schaltet entweder die Zoom- oder die Verschiebungs-Tools ein, je nachdem welcher `ToolButton` gedrückt ist. Damit die `Enabled`-Einstellungen sich in den `Down`-Eigenschaften der `ToolButtons` widerspiegeln, sollten wir noch die beiden Verschiebungs-Tools ausschalten (`Enabled = false`) -- oder die Methode `ZoomPanToolbuttonClick(nil)` im `OnCreate` Ereignis des Formulars aufrufen.
153153
154154Einige Beobachtungen, wenn das Programm läuft:
155155
156156- Es ist Geschmackssache, aber vielleicht bist du auch der Meinung, dass sich der gezoomte Chart-Ausschnitt entgegengesetzt zu der Richtung verschiebt, in der das Mausrad gedreht wird? Das kann man ändern, indem die Eigenschaft `WheelUpDirection` des vertikalen Zoom-Tools auf `pdDown` umgestellt wird.
157157- Chart-Bereiche ohne Daten können wieder sichtbar werden. Das liegt daran, dass die `ExtentSizeLimit`-Eigenschaft nur für die Prüfung der Breite und/oder Höhe des Charts zuständig ist. Das kann mit Hilfe der Eigenschaften `LimitToExtent` des `PanMouseWheelTool` geändert werden: Aktiviere alle Optionen, um vertikales und horizontales Verschieben über den ursprünglichen Datenbereich hinaus zu verbieten.
158158- Vielleicht möchtest du die Geschwindigkeit des Verschiebens verändern? Passe hierzu den Wert der Eigenschaft `Step` an.
159159- Du findest wahrscheinlich auch, dass es recht umständiglich ist, den ursprünglichen, nicht verschobenen Chart-Bereich wiederherzustellen. Das könnte man mit einem Schalter *"Reset"* in der Toolbar vereinfachen, der jede Zoom-/Verschiebungs-Operation rückgängig macht. Das ist leicht: Platziere einen dritten Button auf die `Toolbar`, nenne ihn `RestoreToolbutton`, schreibe als seine `Caption` den Text *"Reset"* und weise seinem `OnClick`-Ereignis den folgenden Code zu:
160160
161161``` pascal
162162procedure TForm1.ResetToolButtonClick(Sender: TObject);
163163begin
164164 Chart1.ZoomFull;
165165end;
166166```
167167
168168Der Aufruf von `ZoomFull` setzt die Achsen wieder auf die ursprünglichen Grenzen zurück. Hier ist nun, wie unser Programm aktuell aussieht:
169169
170170![](/wiki-images/1/18/ZoomPan04a.png)
171171
172172## Datenwerte aus der Datenreihe auslesen
173173
174174Man könnte noch weitere Zoom- und Verschiebungs-Werkzeuge ins Toolset aufnehmen und so eine praktische Benutzeroberfläche aufbauen. Aber das wollen wir hier nicht weiter vertiefen, sondern uns nun den Daten-Tools zuwenden.
175175
176176### Ein TDataPointClickTool verwenden
177177
178178Stellen wir uns die Aufgabe, die `x,y`-Koordinaten von Datenpunkten unter dem Maus-Cursor auszulesen. Ein dafür geeignetes Werkzeug ist das `TDatapointClickTool`. Füge es zum Toolset hinzu. Setze `Shift` auf `ssLeft`, um es durch einen Klick mit der linken Maustaste zu aktivieren. Und füge dem Formular eine `TStatusbar` hinzu, auf der wir die erhaltenen Daten anzeigen wollen.
179179
180180Immer wenn ein Mausklick auf einem Datenpunkt erfolgt (oder ausreichend nahe), werden die relevanten Daten über den Datenpunkt im Tool gespeichert. Zum Beispiel gibt es eine Eigenschaft `Series`, die festhält, auf welcher Datenreihe der Klick erfolgt ist. Entsprechend gibt es auch eine Eigenschaft `PointIndex`, über die man den Index des angeklickten Punktes innerhalb der Datenreihe erfährt. Weiterhin stellt das Werkzeug ein Ereignis `OnPointClick` zur Verfügung; es wird ausgelöst, wenn auf einen Datenpunkt geklickt wurde, und wir können damit die gewünschte Information auslesen. Der folgende Ereignis-Behandlungscode stellt die ausgelesene Information in der Statuszeile dar:
181181
182182``` pascal
183183procedure TForm1.ChartToolset1DataPointClickTool1PointClick(
184184 ATool: TChartTool; APoint: TPoint);
185185var
186186 x, y: Double;
187187begin
188188 with ATool as TDatapointClickTool do
189189 if (Series is TLineSeries) then
190190 with TLineSeries(Series) do begin
191191 x := GetXValue(PointIndex);
192192 y := GetYValue(PointIndex);
193193 Statusbar1.SimpleText := Format('%s: x = %f, y = %f', [Title, x, y]);
194194 end
195195 else
196196 Statusbar1.SimpleText := '';
197197end;
198198```
199199
200200Der Parameter `ATool`, der dem Ereignis mitgegeben wird, hat einen sehr allgemeinen Typ. Daher müssen wir eine Typ-Umwandlung in ein `TDatapointClickTool` vornehmen, um an die gewünschte Information zu gelangen. Genauso hat die vom Tool gespeicherte Eigenschaft `Series` einen sehr allgemeinen Typ, so dass auch hier eine Typumwandlung erforderlich ist. Aber sei vorsichtig bei Typumwandlungen, versichere dich immer mit Hilfe des Operators `is`, ob die Typen richtig sind.
201201
202202Wenn wir nun das Programm starten und auf einem Datenpunkt klicken, bekommen wir die Koordinaten des Punktes zusammen mit dem Titel der Datenreihe in der Statuszeile angezeigt.
203203
204204![](/wiki-images/4/49/ZoomPan05.png)
205205
206206### Anzeigen von permanenten Labels
207207
208208Leider kann man nicht feststellen, wo genau der Klick erfolgt ist. Es wäre besser, wenn wir über dem angeklickten Datenpunkt eine Markierung ("Label") mit der gewünschten Information anzeigen könnten.
209209
210210Hierzu verwenden wir die Tatsache, dass die Datenreihen im Chart ihre Daten jeweils aus einer `TListChartSource` beziehen. Auf dem Formular gibt es dafür keine spezielle Komponente, weil der Datenreihentyp `TChartSeries`, von dem sich `TLineSeries` ableitet, diese als eingebautet Datenquelle enthält und über die öffentliche Eigenschaft `ListSource` zugänglich macht.
211211
212212Warum ist das wichtig? Weil die in der `ListSource` gespeicherten Einträge vom Typ `TChartDateItem` im Feld `Text` Speicherplatz für zusätzlichen Text vorhalten:
213213
214214``` pascal
215215type
216216 TChartDataItem = object
217217 X, Y: Double;
218218 Text: String;
219219 // ...
220220 end;
221221```
222222
223223Um den Inhalt des `Text`-Feldes zu verändern, der einem Datenpunkt mit vorgegebenem `Index` zugewiesen ist, verwenden wir folgenden Code:
224224
225225``` pascal
226226ListSource.Item[index]^.Text := 'some text';
227227```
228228
229229In neueren Lazarus-Versionen gibt es dafür zur Vereinfachtung auch die Methode `SetText`:
230230
231231``` pascal
232232ListSource.SetText(index, 'some text');
233233```
234234
235235(Du kannst mehr über `TChartListSource` in dem [[TAChart Tutorial: ListChartSource, Logarithmic Axis, Fitting|betreffenden Tutorial]] erfahren.)
236236
237237Zu Beginn sind alle `Text` Einträge leer. Aber wenn wir auf einen Datenpunkt geklickt haben, transferieren wir die Koordinaten-Information in das `Text`-Feld des zugehörigen `ChartDataItem`, indem wir die obige Code-Zeile in die die `OnPointClick`-Ereignisbehandlungsroutine des `DataPointClickTool`s einbauen. Die Statuszeile, übrigens, benötigen wird nicht mehr - lösche sie und entferne den entsprechenden Code aus der Ereignisbehandlungs-Routine:
238238
239239``` pascal
240240procedure TForm1.ChartToolset1DataPointClickTool1PointClick(
241241 ATool: TChartTool; APoint: TPoint);
242242var
243243 x, y: Double;
244244begin
245245 with ATool as TDatapointClickTool do
246246 if (Series <> nil) then
247247 with (Series as TLineSeries) do begin
248248 x := GetXValue(PointIndex);
249249 y := GetYValue(PointIndex);
250250 { --- die nächste Zeile wurde entferne --- }
251251// Statusbar1.SimpleText := Format('%s: x = %f, y = %f', [Title, x, y]);
252252 { --- die nächste Zeile wirde hinzugefügt --- }
253253 ListSource.Item[PointIndex]^.Text := Format('x = %f'#13#10'y = %f', [x,y]);
254254 ParentChart.Repaint;
255255 // in neueren Lazarus-Versionen kann man stattdessen auch die folgende Zeile verwenden (die schon das Repaint enthält):
256256 // ListSource.SetText(PointIndex, Format('x = %f'#13#10'y = %f', [x,y]));
257257 end;
258258end;
259259```
260260
261261Nun müssen wir uns darum kümmern, dass die Labels auch angezeigt werden. Zu diesem Zweck hat `TChartSeries`, der Vorfahr von `TLineSeries`, die Eigenschaft `Marks`. In deren Unter-Eigenschaften findet sich die Option `Style`, die standardmäßig auf `smsNone` gesetzt ist -- das bedeutet, dass Labels in der Grundeinstellung gar nicht dargestellt werden. Im Objekt-Inspektor sieht man, dass `Style` eine Vielzahl von Einstellmöglichkeiten bietet. Wir brauchen hier die Option `smsLabel`, die die Ausgabe des `Text`-Labels bewirkt. Eine weitere sinnvolle Änderung wäre, `LinkPen.Color` auf eine dunklere Farbe zu setzen, andernfalls ist die Verbindungslinie zwischen Label und Datenpunkt auf dem weißen Untergrund nicht zu erkennen. Vielleicht spielst du auch mit den anderen Einstellmöglichkeiten, wie `CalloutAngle` oder `Shape`.
262262
263263Dieselben Änderungen müssen an allen drei Datenreihen des Chart vorgenommen werden.
264264
265265Wenn du nun das Projekt startest und auf Datenpunkten klickst, bekommst du schöne permantente Labels. Beachte, dass die Markierungen erhalten bleiben, selbst wenn man den sichtbaren Chart-Ausschnitt durch Zoomen oder Verschieben verändert.
266266
267267![](/wiki-images/c/c6/ZoomPan06.png)
268268
269269### Permanente Labels entfernen
270270
271271Gelegentlich wirst du feststellen, dass du einen falschen Datenpunkt angeklickt hast, und willst deshalb das Label entfernen.
272272
273273Die grundlegende Idee dafür ist folgendermaßen: füge ein weiteres `TDatapointClickTool` hinzu, weise es der rechten Maustaste zu und entferne in der `OnDatapointClick`-Ereignisbehandlung den Text von dem `ChartDataItem`. Versuche selbst, den Code zu schreiben -- du solltest jetzt alle nötigen Schritte kennen.
274274
275275## Ähnliche Tutorials
276276
277277- [[TAChart Tutorial: Getting started]]: erklärt, wie der hier verwendete Chart erzeugt wurde.
278278- [[TAChart Tutorial: ListChartSource, Logarithmic Axis, Fitting]]: diskutiert die Verwendung der `Marks` von Datenreihen.
279279- [[TAChart Tutorial: ColorMapSeries, Zooming]]: demonstriert weitere Aspekte des Zoomens und Verschiebens wie die Verwendung des ZoomDrag- und PanDrag-Tools, sowie die Erstellung eines Zoom-Verlaufs.
280280
281281## Quell-Code
282282
283283### project.lpr
284284
285285``` pascal
286286program project1;
287287
288288{$mode objfpc}{$H+}
289289
290290uses
291291 {$IFDEF UNIX}{$IFDEF UseCThreads}
292292 cthreads,
293293 {$ENDIF}{$ENDIF}
294294 Interfaces, // this includes the LCL widgetset
295295 Forms, Unit1, tachartlazaruspkg
296296 { you can add units after this };
297297
298298{$R *.res}
299299
300300begin
301301 RequireDerivedFormResource := True;
302302 Application.Initialize;
303303 Application.CreateForm(TForm1, Form1);
304304 Application.Run;
305305end.
306306```
307307
308308### unit1.pas
309309
310310``` pascal
311311unit Unit1;
312312
313313{$mode objfpc}{$H+}
314314
315315interface
316316
317317uses
318318 Classes, SysUtils, FileUtil, TAGraph, TASeries, TATools, Forms, Controls,
319319 Graphics, Dialogs, ComCtrls, types;
320320
321321type
322322
323323 { TForm1 }
324324
325325 TForm1 = class(TForm)
326326 Chart1: TChart;
327327 ChartToolset1: TChartToolset;
328328 ChartToolset1DataPointClickTool1: TDataPointClickTool;
329329 ChartToolset1DataPointClickTool2: TDataPointClickTool;
330330 ChartToolset1PanMouseWheelTool_Hor: TPanMouseWheelTool;
331331 ChartToolset1PanMouseWheelTool_Vert: TPanMouseWheelTool;
332332 ChartToolset1ZoomMouseWheelTool_iso: TZoomMouseWheelTool;
333333 ChartToolset1ZoomMouseWheelTool_Hor: TZoomMouseWheelTool;
334334 ChartToolset1ZoomMouseWheelTool_Vert: TZoomMouseWheelTool;
335335 SinSeries: TLineSeries;
336336 CosSeries: TLineSeries;
337337 SinCosSeries: TLineSeries;
338338 ToolBar1: TToolBar;
339339 ResetToolButton: TToolButton;
340340 ZoomToolbutton: TToolButton;
341341 PanToolbutton: TToolButton;
342342 procedure ChartToolset1DataPointClickTool1PointClick(
343343 ATool: TChartTool; APoint: TPoint);
344344 procedure ChartToolset1DataPointClickTool2PointClick(
345345 ATool: TChartTool; APoint: TPoint);
346346 procedure FormCreate(Sender: TObject);
347347 procedure ResetToolButtonClick(Sender: TObject);
348348 procedure ZoomPanToolbuttonClick(Sender: TObject);
349349 private
350350 { private declarations }
351351 public
352352 { public declarations }
353353 end;
354354
355355var
356356 Form1: TForm1;
357357
358358implementation
359359
360360{$R *.lfm}
361361
362362{ TForm1 }
363363
364364procedure TForm1.FormCreate(Sender: TObject);
365365const
366366 N = 100;
367367 MIN = -10;
368368 MAX = 10;
369369var
370370 i: Integer;
371371 x: Double;
372372begin
373373 for i:=0 to N - 1 do begin
374374 x := MIN + (MAX - MIN) * i / (N - 1);
375375 SinSeries.AddXY(x, sin(x));
376376 CosSeries.AddXY(x, cos(x));
377377 SinCosSeries.AddXY(x, sin(x)*cos(x));
378378 end;
379379end;
380380
381381procedure TForm1.ResetToolButtonClick(Sender: TObject);
382382begin
383383 Chart1.ZoomFull;
384384end;
385385
386386procedure TForm1.ChartToolset1DataPointClickTool1PointClick(
387387 ATool: TChartTool; APoint: TPoint);
388388var
389389 x,y: Double;
390390begin
391391 with ATool as TDatapointClickTool do
392392 if (Series <> nil) then
393393 with (Series as TLineSeries) do begin
394394 x := GetXValue(PointIndex);
395395 y := GetYValue(PointIndex);
396396// Statusbar1.SimpleText := Format('%s: x = %f, y = %f', [Title, x, y]);
397397 ListSource.Item[PointIndex]^.Text := Format('x = %f'#13#10'y = %f', [x,y]);
398398 ParentChart.Repaint;
399399 end;
400400end;
401401
402402procedure TForm1.ChartToolset1DataPointClickTool2PointClick(
403403 ATool: TChartTool; APoint: TPoint);
404404begin
405405 with ATool as TDatapointClickTool do
406406 if (Series <> nil) then
407407 with (Series as TLineSeries) do begin
408408 ListSource.Item[PointIndex]^.Text := '';
409409 ParentChart.Repaint;
410410 end;
411411end;
412412
413413procedure TForm1.ZoomPanToolbuttonClick(Sender: TObject);
414414begin
415415 ChartToolset1ZoomMouseWheelTool_iso.Enabled := ZoomToolbutton.Down;
416416 ChartToolset1ZoomMouseWheelTool_vert.Enabled := ZoomToolbutton.Down;
417417 ChartToolset1ZoomMouseWheelTool_hor.Enabled := ZoomToolbutton.Down;
418418
419419 ChartToolset1PanMouseWheelTool_vert.Enabled := PanToolbutton.Down;
420420 ChartToolset1PanMouseWheelTool_hor.Enabled := PanToolbutton.Down;
421421end;
422422
423423end.
424424```
425425
426426### unit1.lfm
427427
428-``` pascal
428+``` lfm
429429object Form1: TForm1
430430 Left = 554
431431 Height = 284
432432 Top = 341
433433 Width = 347
434434 Caption = 'Form1'
435435 ClientHeight = 284
436436 ClientWidth = 347
437437 OnCreate = FormCreate
438438 LCLVersion = '1.1'
439439 object Chart1: TChart
440440 Left = 0
441441 Height = 258
442442 Top = 26
443443 Width = 347
444444 AxisList = <
445445 item
446446 Grid.Color = clSilver
447447 Minors = <>
448448 Title.LabelFont.Orientation = 900
449449 Title.LabelFont.Style = [fsBold]
450450 Title.Visible = True
451451 Title.Caption = 'y axis'
452452 end
453453 item
454454 Grid.Color = clSilver
455455 Alignment = calBottom
456456 Minors = <>
457457 Title.LabelFont.Style = [fsBold]
458458 Title.Visible = True
459459 Title.Caption = 'x axis'
460460 end>
461461 BackColor = clWhite
462462 ExtentSizeLimit.UseXMax = True
463463 ExtentSizeLimit.UseXMin = True
464464 ExtentSizeLimit.UseYMax = True
465465 ExtentSizeLimit.XMax = 20
466466 ExtentSizeLimit.XMin = 0.01
467467 ExtentSizeLimit.YMax = 2
468468 Foot.Brush.Color = clBtnFace
469469 Foot.Font.Color = clBlue
470470 Legend.Alignment = laBottomCenter
471471 Legend.ColumnCount = 3
472472 Legend.Visible = True
473473 Title.Brush.Color = clBtnFace
474474 Title.Font.Color = clBlue
475475 Title.Font.Style = [fsBold]
476476 Title.Text.Strings = (
477477 'My first chart'
478478 )
479479 Title.Visible = True
480480 Toolset = ChartToolset1
481481 Align = alClient
482482 ParentColor = False
483483 object SinSeries: TLineSeries
484484 Marks.Format = '%2:s'
485485 Marks.LinkPen.Color = clGray
486486 Marks.Style = smsLabel
487487 Title = 'y=sin(x)'
488488 LinePen.Color = clRed
489489 end
490490 object CosSeries: TLineSeries
491491 Marks.Format = '%2:s'
492492 Marks.LinkPen.Color = clGray
493493 Marks.Style = smsLabel
494494 Title = 'y=cos(x)'
495495 LinePen.Color = clBlue
496496 end
497497 object SinCosSeries: TLineSeries
498498 Marks.Format = '%2:s'
499499 Marks.LinkPen.Color = clGray
500500 Marks.Style = smsLabel
501501 Title = 'y=sin(x)*cos(x)'
502502 LinePen.Color = clGreen
503503 end
504504 end
505505 object ToolBar1: TToolBar
506506 Left = 0
507507 Height = 26
508508 Top = 0
509509 Width = 347
510510 Caption = 'ToolBar1'
511511 EdgeBorders = [ebBottom]
512512 ShowCaptions = True
513513 TabOrder = 1
514514 object ZoomToolbutton: TToolButton
515515 Left = 1
516516 Top = 0
517517 Caption = 'Zoom'
518518 Down = True
519519 Grouped = True
520520 OnClick = ZoomPanToolbuttonClick
521521 Style = tbsCheck
522522 end
523523 object PanToolbutton: TToolButton
524524 Left = 41
525525 Top = 0
526526 Caption = 'Pan'
527527 Grouped = True
528528 OnClick = ZoomPanToolbuttonClick
529529 Style = tbsCheck
530530 end
531531 object ResetToolButton: TToolButton
532532 Left = 69
533533 Top = 0
534534 Caption = 'Reset'
535535 OnClick = ResetToolButtonClick
536536 end
537537 end
538538 object ChartToolset1: TChartToolset
539539 left = 153
540540 top = 66
541541 object ChartToolset1ZoomMouseWheelTool_iso: TZoomMouseWheelTool
542542 ZoomFactor = 1.1
543543 end
544544 object ChartToolset1ZoomMouseWheelTool_Hor: TZoomMouseWheelTool
545545 Shift = [ssAlt]
546546 ZoomFactor = 1.1
547547 ZoomRatio = 0.90909090909091
548548 end
549549 object ChartToolset1ZoomMouseWheelTool_Vert: TZoomMouseWheelTool
550550 Shift = [ssShift]
551551 ZoomRatio = 1.1
552552 end
553553 object ChartToolset1PanMouseWheelTool_Hor: TPanMouseWheelTool
554554 Shift = [ssAlt]
555555 LimitToExtent = [pdLeft, pdUp, pdRight, pdDown]
556556 WheelUpDirection = pdLeft
557557 end
558558 object ChartToolset1PanMouseWheelTool_Vert: TPanMouseWheelTool
559559 Shift = [ssShift]
560560 LimitToExtent = [pdLeft, pdUp, pdRight, pdDown]
561561 WheelUpDirection = pdDown
562562 end
563563 object ChartToolset1DataPointClickTool1: TDataPointClickTool
564564 Shift = [ssLeft]
565565 OnPointClick = ChartToolset1DataPointClickTool1PointClick
566566 end
567567 object ChartToolset1DataPointClickTool2: TDataPointClickTool
568568 Shift = [ssRight]
569569 OnPointClick = ChartToolset1DataPointClickTool2PointClick
570570 end
571571 end
572572end
573573```
574574
575575---
576576*From the Free Pascal wiki, page "TAChart Tutorial: Chart Tools/de", as it stood on 2022-10-18 after a change by Wp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history