Tutorial
In diesem Tutorial erstellen wir eine einfache Lösung zur Anzeige des Zeitplans einer Flugzeugflotte. Zur Installation von FlexGanttFX folgen Sie bitte den Anweisungen unter Installation.

View-Modell
Beginnen wir mit der Erstellung eines View-Modells für das Gantt-Diagramm. Unsere Objekte sind Fleet, Aircraft, Crew und
Flight. Instanzen von Flight werden als horizontaler Balken im Grafikbereich des Gantt-Diagramms angezeigt, während die ersten drei in den Zeilen des Tree-Table-Bereichs erscheinen. Fleet, Aircraft und Crew teilen eine gemeinsame Oberklasse namens ModelObject, eine Erweiterung von Row. Die Klasse Row wird mithilfe von drei Typargumenten zur Definition einer hierarchischen Datenstruktur verwendet: Das erste gibt den Typ der übergeordneten Zeile an, das zweite den Typ der untergeordneten Zeilen und das dritte den Typ der Aktivitäten, die auf der rechten Seite des Gantt-Diagramms angezeigt werden.
Modell-Objekt
P extends Row<?,?,?>, // Type of parent row
C extends Row<?,?,?>, // Type of child rows
A extends Activity> extends Row<P, C, A> { }
Wir können nun ModelObject als Typargument beim Erstellen einer Instanz eines GanttChart-Steuerelements übergeben. Damit wird dem
Steuerelement mitgeteilt, dass alle Zeilen diesen gemeinsamen Supertyp aufweisen.
GanttChart<ModelObject<?,?,?> gantt = new GanttChart<>()
Die Modellklasse Aircraft kann wie im folgenden Code-Fragment gezeigt implementiert werden – vorausgesetzt, eine Flotte
besteht aus mehreren Flugzeugen, jedes Flugzeug hat eine Besatzung, und Flüge werden Flugzeugen und Besatzungen zugeordnet.
public class Aircraft extends ModelObject<Fleet, Crew, Flight> {
public Aircraft(String name) {
super(name);
}
}
Die Klasse Flight erweitert MutableActivityBase und könnte wie folgt aussehen:
public class Flight extends MutableActivityBase<FlightData> {
public Flight(FlightData data) {
super(data.getFlightName()); // the activity name
setStartTime(data.getFlightDepartureTime()); // times as java.time.Instant
setEndTime(data.getFlightArrivalTime());
setUserObject(data); // a user object according to the type argument above
}
}
Diese Klasse definiert einen Flug als veränderliche Aktivität, was bedeutet, dass der Benutzer den Flug bearbeiten bzw. ändern kann.
Wir sehen auch, dass die Aktivität ihre Informationen aus einem Domain-Objekt vom Typ FlightData bezieht. Die Unterstützung eines User-Objekts ermöglicht es uns, eine Verbindung zwischen dem Domain-Modell und dem View-Modell herzustellen. Jetzt müssen wir nur noch
die Aktivitäten (die Flüge) zu den Zeilen (den Flugzeugen) hinzufügen. Dazu können wir einfach die Methode Row.addActivity(Layer, Activity) aufrufen.
Activity-Repositories
Zeilen speichern Aktivitäten nicht selbst, sondern delegieren die gesamte aktivitätsbezogene Funktionalität an ein Repository vom Typ ActivityRepository. Das Standard-Repository ist vom Typ IntervalTreeRepository.
Anwendungen können eigene Repositories implementieren und diese durch den Aufruf von Row.setRepository() registrieren.
Layer
Layer werden verwendet, um Gruppen von Aktivitäten zu erstellen, sodass diese gemeinsam ein- oder ausgeblendet werden können. In unserem Beispiel möchten wir Flüge nach ihrem Servicetyp gruppieren (Cargo, Charter, Training usw.).
Layer cargoLayer = new Layer("Cargo");
Layer trainingLayer = new Layer("Training");
Layer charterLayer = new Layer("Charter");
// make layers known to Gantt
gantt.getLayers().addAll(cargoLayer, trainingLayer, charterLayer);
Das Gantt-Diagramm weiß nun, welche Layer es rendern muss, und wir können die Verbindung zwischen Layern und Aktivitäten herstellen. Dies geschieht, wenn wir die Aktivitäten zu den Zeilen hinzufügen (hier: Flüge zu Flugzeugen).
Flight flight1 = new Flight(); // a cargo flight
Flight flight2 = new Flight(); // a training flight
Flight flight3 = new Flight(); // a charter flight
aircraft1.addActivity(cargoLayer, flight1);
aircraft1.addActivity(trainingLayer, flight2);
aircraft2.addActivity(charterLayer, flight3);
Im folgenden Code-Beispiel fassen wir alle obigen Schritte zusammen.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import com.flexganttfx.model.Activity;
import com.flexganttfx.model.Layer;
import com.flexganttfx.model.Row;
import com.flexganttfx.model.activity.MutableActivityBase;
import com.flexganttfx.view.GanttChart;
public class MyFirstGanttChart extends Application {
/*
* Common superclass of Fleet, Aircraft, and Crew.
*/
class ModelObject<
P extends Row<?,?,?>, // Type of parent row
C extends Row<?,?,?>, // Type of child rows
A extends Activity> extends Row<P, C, A> { }
class Fleet extends ModelObject<Row<?,?,?>, Aircraft, Activity> { }
class Aircraft extends ModelObject<Fleet, Crew, Flight> { }
class Flight extends MutableActivityBase<Object> { }
@Override
public void start(Stage stage) throws Exception {
// Our root object.
Fleet fleet = new Fleet();
fleet.setExpanded(true);
// Create the control.
GanttChart<ModelObject<?,?,?>> gantt = new GanttChart<>(fleet);
// Layers based on service type.
Layer cargoLayer = new Layer("Cargo");
Layer trainingLayer = new Layer("Training");
Layer charterLayer = new Layer("Charter");
gantt.getLayers().addAll(cargoLayer, trainingLayer, charterLayer);
// Create the aircrafts.
Aircraft aircraft1 = new Aircraft();
Aircraft aircraft2 = new Aircraft();
// Add the aircrafts to the fleet.
fleet.getChildren().addAll(aircraft1, aircraft2);
// Create the flights
Flight flight1 = new Flight(); // a cargo flight
Flight flight2 = new Flight(); // a training flight
Flight flight3 = new Flight(); // a charter flight
aircraft1.addActivity(cargoLayer, flight1);
aircraft1.addActivity(trainingLayer, flight2);
aircraft2.addActivity(charterLayer, flight3);
Scene scene = new Scene(gantt);
stage.setTitle("Fleet Schedule");
stage.setScene(scene);
stage.centerOnScreen();
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Das Bild unten zeigt, was wir sehen, wenn wir diesen Code ausführen.

Activity-Renderer
Dieses Ergebnis ist für wenige Codezeilen nicht schlecht, aber die Darstellung der Flüge ist wenig ansprechend. Wir können ihr Aussehen anpassen, indem wir einen anderen ActivityRenderer für den Aktivitätstyp Flight registrieren. Dies geschieht
durch den Aufruf der Methode GraphicsBase.setActivityRenderer(), wobei die Grafikansicht das Steuerelement auf der rechten Seite
des Gantt-Diagramms ist. Es ist für das Rendern aller Aktivitäten zuständig. Wir können die folgenden Zeilen zu unserem Beispiel von oben hinzufügen.
GraphicsView <ModelObject<?, ?, ?>> graphics = gantt.getGraphics();
graphics.setActivityRenderer(Flight.class,
GanttLayout.class,
new ActivityBarRenderer<>(graphics, "FlightRenderer"));
Dies ersetzt den Standard-Activity-Renderer durch einen Renderer, der einen Balken mit fester Höhe zeichnet. Interessant an diesem Code ist, dass wir nicht nur den Aktivitätstyp und die Renderer-Instanz übergeben, sondern auch einen Layout-Typ. Wir wollen in diesem Schnelleinstieg nicht zu lange auf Layouts eingehen, aber lassen Sie uns festhalten, dass FlexGanttFX in der Lage ist, Aktivitäten auf verschiedene Arten anzuzeigen (als Zeitbalken, als Diagrammeinträge, als Agenda-Einträge). Unser Beispiel sieht nun so aus:

Wir können dem Beispiel nun eine GanttChartToolBar und eine GanttChartStatusBar hinzufügen. Damit können wir Aktionen am Diagramm ausführen und auch überprüfen, ob die Layer korrekt hinzugefügt wurden. Die „extras"-Bibliothek von FlexGanttFX enthält
zusätzliche Steuerelemente wie eine GanttChartStatusBar und eine GanttChartToolBar. Mit dem Standard-BorderPane lassen sich
das Gantt-Diagramm und diese beiden Steuerelemente einfach zu einem einzelnen komplexen Steuerelement kombinieren.
BorderPane borderPane = new BorderPane();
borderPane.setTop(new GanttChartToolBar(gantt));
borderPane.setCenter(gantt);
borderPane.setBottom(new GanttChartStatusBar(gantt));
Scene scene = new Scene(borderPane);
Unser Beispiel sieht nach einem Klick auf den Layer-Button in der Toolbar nun so aus:

Änderungen beobachten
Nachdem wir unsere Daten visualisiert haben, möchten wir natürlich mit ihnen interagieren und über vorgenommene Änderungen informiert werden. Unsere Aktivitäten sind standardmäßig bearbeitbar. Das bedeutet, wir können sie horizontal oder vertikal verschieben. Um Ereignisse zu empfangen, müssen wir lediglich einen ActivityEvent-Handler mit dem Grafikansicht-Steuerelement registrieren, indem wir
GraphicsBase.setOnActivityChanged() aufrufen.
Für dieses Tutorial registrieren wir einfach einen Handler, der das Ereignis auf der Konsole ausgibt. Dies kann so erreicht werden:
graphics.setOnActivityChanged(evt -> System.out.println(evt));
Wenn wir unsere Anwendung erneut starten, sehen wir folgende Ausgabe:
event type: DRAG_STARTED, time interval: 2014-04-17T21:45:00Z - 2014-04-22T21:30:00Z,
value (chart value / percentage complete): 0.0,
activity "null from 2014-04-18T12:15:00Z until 2014-04-23T12:00:00Z,
user object = null",
row = "Default",
layer = "Training"
event type: DRAG_ONGOING, time interval: 2014-04-17T21:45:00Z - 2014-04-22T21:30:00Z,
value (chart value / percentage complete): 0.0,
activity "null from 2014-04-18T12:15:00Z until 2014-04-23T12:00:00Z,
user object = null",
row = "Default",
layer = "Training"
event type: DRAG_FINISHED, time interval: 2014-04-17T21:45:00Z - 2014-04-22T21:30:00Z,
value (chart value / percentage complete): 0.0,
activity "null from 2014-04-18T03:00:00Z until 2014-04-23T02:45:00Z,
user object = null",
row = "Default",
layer = "Training"
Beachten Sie die drei verschiedenen Ereignistypen DRAG_STARTED, DRAG_ONGOING und DRAG_FINISHED. Der erste wird ausgelöst, wenn der Benutzer einen Drag-Vorgang startet, der zweite während der Drag noch läuft, und der dritte, wenn der Drag abgeschlossen ist. Dieses Muster ist auch in JavaFX selbst zu finden und wurde durchgängig in FlexGanttFX
umgesetzt. Schauen Sie sich unbedingt die verschiedenen in der Klasse ActivityEvent definierten Ereignistypen an, um zu erfahren, wie viele
Informationen Sie erhalten können, wenn der Benutzer Bearbeitungsoperationen durchführt.