JavaFX AreaChart als DB Monitor implementieren

ralfb1105

Bekanntes Mitglied
Hallo Zusammen,

ich stehe mal wieder auf dem Schlauch und bräuchte Eure Hilfe bei folgendem Problem. Hier kurz zu dem was ich machen möchte.
Ich möchte, nachdem ich über mein Programm die Datenbank Verbindung erfolgreich getestet habe, einen Button anbieren der einen s.g. Database Monitor Window startet, in dem es nur ein AreaChart gibt der fortlaufend die TPS (Transaction per second) Values der DB anzeigt.
Ich habe mir viel angeschaut und rum probiert, bin dann schließlich bei den Oracle JvaFX Beispielen in "Ensemble" - eine coole Beispiel Sammlung, auf das Beispiel "StockLineChartApp" gestoßen. Ich habe dieses Beispiel dann so gut wie ich kann und ich es vesrtanden habe auf meine Anwendung umzuschreiben, und dabei ist dann folgende Applikation rausgekommen:
Java:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
*
* A Database Monitor with TPS values.
*
*/

public class DBMonitor extends Application {

    // Fields
    private AreaChart<Number, Number> chart;
    private Series<Number, Number> xAxisDataSeries;
    private NumberAxis xAxis;
    private Timeline animation;
    private double xTock = 0;
    private double xTick = 0;
    private double xTockValue = 0;
    private int valueY = 0;
    private String dbSysUser = "sys as sysdba";
    private String dbSysUserPassword = "****";
    private String dbHost = "****";
    private String tnsPort = "6506";
    private String dbSID = "ORCL51";
    private String connectString = "jdbc:oracle:thin:@" + dbHost + ":" + tnsPort + "/" + dbSID;
    private Connection connSys;
    private int valueSqlTPS;
    private int vorWertTPS = 0;
    private int savedValueSqlTPS;
    private boolean firstInTPS = true;

    // Constructor
    public DBMonitor() {

        // Create Database connection
        try {
            connSys = DriverManager.getConnection(connectString, dbSysUser, dbSysUserPassword);
        } catch (Exception ex) {
            System.out.println(ex);
        }

        // 6 "minutes" data per frame

        final KeyFrame frame = new KeyFrame(Duration.millis(1000 / 10), (ActionEvent actionEvent) -> {
            for (int count = 0; count < 6; count++) {
                nextTime();
                plotTime();
            }
        });

        // create timeline to add new data every 10th (1000 / 10 in frame) of second --> 100ms
        animation = new Timeline();
        animation.getKeyFrames().add(frame);
        animation.setCycleCount(Animation.INDEFINITE);
    }

    public Parent createContent() {
        xAxis = new NumberAxis(0, 50, 5);
        final NumberAxis yAxis = new NumberAxis(0, 100, 10);
        chart = new AreaChart<>(xAxis, yAxis);
        // setup AreaChart
        final String dbMonitorCss = getClass().getResource("DBMonitor.css").toExternalForm();
        chart.getStylesheets().add(dbMonitorCss);
        chart.setCreateSymbols(true);
        chart.setAnimated(false);
        chart.setLegendVisible(true);
        chart.setTitle("DB Monitor " + dbSID);
        //xAxis.setLabel("Seconds since Start");
        xAxis.setForceZeroInRange(false);
        xAxis.setAutoRanging(false);
        yAxis.setAutoRanging(true);
        yAxis.setLabel("TPS");
        //yAxis.setTickLabelFormatter(new DefaultFormatter(yAxis, "TPS ", null));

        // add starting data
        xAxisDataSeries = new Series<>();
        xAxisDataSeries.setName("Transactions per Second");
        // create some starting data
        xAxisDataSeries.getData().add(new Data<Number, Number>(xTockValue, valueY));

        chart.getData().add(xAxisDataSeries);
        return chart;
    }

    private void nextTime() {
        if (xTick == 59) {
            xTock++;
            xTick = 0;
        } else {
            xTick++;
        }

        xTockValue = xTock + ((1d / 60d) * xTick);
    }

    private void plotTime() {

        if ((xTockValue % 1) == 0) {
            // get TPS values from DB
            try {
                String queryTPS = "SELECT VALUE from v$sysstat where name in ('user commits')";
                Statement stmt = connSys.createStatement();
                ResultSet rset = stmt.executeQuery(queryTPS);
                while (rset.next()) {
                    String tps = rset.getString("VALUE");
                    valueSqlTPS = Integer.parseInt(tps);
                }
                stmt.close();
            } catch (Exception ex) {
                System.out.println(ex);
            }

            savedValueSqlTPS = valueSqlTPS;
            valueSqlTPS = valueSqlTPS - vorWertTPS;
            vorWertTPS = savedValueSqlTPS;

            // In the 1st execution we don't have a savedValue, so don't print anything and
            // wait for the 2nd execution
            if (!firstInTPS) {
                // updateMessage(String.valueOf(valueSqlTPS));
                valueY = valueSqlTPS;
            } else {
                valueY = 0;
                firstInTPS = false;
            }

            xAxisDataSeries.getData().add(new Data<Number, Number>(xTockValue, valueY));

            // every xTockValue (second xAxis) after 50 (initial xAxis = new NumberAxis(0, 50, 5)) move range 1 xTock
            if (xTockValue > 50) {
                xAxis.setLowerBound(xAxis.getLowerBound() + 1);
                xAxis.setUpperBound(xAxis.getUpperBound() + 1);
            }
        }
    }

    public void play() {
        animation.play();
    }

    @Override

    public void stop() {
        animation.pause();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(createContent()));
        primaryStage.show();
        play();
    }

    /**
     *
     * Java main for when running without JavaFX launcher
     *
     */

    public static void main(String[] args) {
        launch(args);

    }

}
Das funktioniert auch sehr gut.

Ohne Licht kein Schatten - nun zu meinem Problem - eigentlich klingt es einfach - doch irgendwie bin ich zu blöd um es zu verstehen wie das geht ...

Wie oben geschrieben habe ich ja bereits eine Applikation die DB Verbindungen testet, und die mit der Hilfe hier aus dem Forum auch schon so etwas wie ControllerInjectable etc. hat.
Das View erstelle ich in dem Programm mit SceneBuilder. Ich habe also einen Button, und mit der Methode die dem Button zugeordnet ist würde ich jetzt gerne ein neues Fenster starten was mein DBMonitor.java "enthält".

Mir ist jetzt nicht klar wie ich das in Zusamenhang mit SceneBuilder bewerkstelligen soll.
Hier mal was ich gemacht habe um es zu verdeutlichen. Ich habe wie gesagt die Controller Klasse, diese enthält nur einen Button welcher dann den DB Monitor startet.
Java:
package application;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class Controller implements ExceptionListener, ModelInjectable, DBInjectable {

    // Fields
    private Model model;
    private DB db;

    // Constructor
    public Controller() {
        super();
    }

    /*
     * @Override Methods
     */

    @Override
    public void setModel(Model model) {
        this.model = model;
    }

    @Override
    public void setDB(DB db) {
        this.db = db;

    }

    @Override
    public void exceptionOccurred(Throwable th) {
        String msg = String.valueOf(th);
        System.out.println(msg);
    }

    /*
     * FXML Nodes (fx:id)
     */

    @FXML
    Button dbMonitor;

    @FXML
    Button exit;

    /*
     * Methods
     */

    // Method initialize() will be executed after all FXML Nodes are ready. This is
    // the place for Initialization of Nodes.
    @FXML
    public void initialize() {
        this.db = new DB();
        this.model = new Model();

        // Register ExceptionListener with DB(Model) class to get Exceptions from DB
        // class in Controller for showing in the View
        db.registerExceptionListener(th -> {
            String msg = String.valueOf(th);
            System.out.println(msg);
//            messageTextArea.appendText(msg + "\n");
//            LOGGER.severe(msg);
        });

        model.registerExceptionListener(th -> {
            String msg = String.valueOf(th);
            System.out.println(msg);
//            messageTextArea.appendText(msg + "\n");
//            LOGGER.severe(msg);
        });

    }

    public void exitButtonTapped(ActionEvent event) {
        // Cast the Window of UI Control Button exit to Stage
        ((Stage) exit.getScene().getWindow())
                .fireEvent(new WindowEvent(((Stage) exit.getScene().getWindow()), WindowEvent.WINDOW_CLOSE_REQUEST));

    }

    // Method for DB Monitor Button
    public void dbMonitorButtonTapped() {
        Parent rootDBMonitor = ViewLoader.load("DBMonitorView.fxml",
                clazz -> ControllerFactory.controllerForClass(clazz, model, db, this));
        Stage stageDBMonitor = new Stage();
        stageDBMonitor.initModality(Modality.APPLICATION_MODAL);
        stageDBMonitor.setOpacity(1);
        stageDBMonitor.setTitle("DB Monitor View");
        Scene sceneDBMonitor = new Scene(rootDBMonitor);
        sceneDBMonitor.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        stageDBMonitor.setScene(sceneDBMonitor);
        stageDBMonitor.show();
    }
  
  

}
Hier dann das zugehörige "DBMonitorView.fxml":
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ControllerDBMonitor">
   <children>
      <HBox alignment="CENTER" prefHeight="40.0" prefWidth="600.0">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
         <children>
            <Text strokeType="OUTSIDE" strokeWidth="0.0" text="DB Monitor">
               <font>
                  <Font size="18.0" />
               </font>
            </Text>
         </children>
      </HBox>
      <HBox alignment="CENTER" prefHeight="303.0" prefWidth="600.0">
         <VBox.margin>
            <Insets left="10.0" right="10.0" />
         </VBox.margin>
         <children>
            <AreaChart fx:id="chart">
              <xAxis>
                <CategoryAxis side="BOTTOM" />
              </xAxis>
              <yAxis>
                <NumberAxis side="LEFT" />
              </yAxis>
            </AreaChart>
         </children>
      </HBox>
      <HBox alignment="CENTER_RIGHT" prefHeight="29.0" prefWidth="600.0">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
         <children>
            <Button fx:id="exit" mnemonicParsing="false" onAction="#exitButtonTapped" text="EXIT" />
         </children>
      </HBox>
   </children>
</VBox>

Ich habe dann noch eine Klasse "ControllerDBMonitor" in der ich dann versucht habe den Code aus meinem funktiinierendem eigenständigen Programm "DBMonitor.java" zu implementieren. Hier das Ergebnis als Grundgerüst, ohne den Code aus DBMonitor.java:
Java:
package application;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javafx.animation.Timeline;
import javafx.fxml.FXML;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class ControllerDBMonitor implements ExceptionListener, ModelInjectable, ControllerInjectable, DBInjectable {

    // Fields
    private Controller controller;
    private Model model;
    private DB db;
    private Connection connSys;

    private String dbSysUser = "sys as sysdba";
    private String dbSysUserPassword = "*****";
    private String dbHost = "*****";
    private String tnsPort = "6506";
    private String dbSID = "ORCL51";
    private String connectString = "jdbc:oracle:thin:@" + dbHost + ":" + tnsPort + "/" + dbSID;
    private String dbBanner;
    private int valueSqlTPS;
    private int vorWertTPS = 0;
    private int savedValueSqlTPS;
    private boolean firstInTPS = true;

    private Series<Number, Number> xAxisDataSeries;
    private NumberAxis xAxis;
    private NumberAxis yAxis;
    private Timeline animation;
    private double xTock = 0;
    private double xTick = 0;
    private double xTockValue = 0;
    private int valueY = 0;

    // Constructor
    public ControllerDBMonitor() {
        super();

    }

    // FXML Nodes
    @FXML
    Button exit;

    @FXML
    AreaChart<Number, Number> chart;

    /*
     * Implemented Methods
     */

    @Override
    public void setDB(DB db) {
        this.db = db;

    }

    @Override
    public void setController(Controller controller) {
        this.controller = controller;
    }

    @Override
    public void setModel(Model model) {
        this.model = model;

    }

    @Override
    public void exceptionOccurred(Throwable th) {
        String msg = String.valueOf(th);
        System.out.println(msg);
    }

    // Initialize Method
    public void initialize() throws SQLException {
        connSys = db.dbConnect(connectString, dbSysUser, dbSysUserPassword);
        String queryGetDbVersion = "select banner from v$version where banner like '%Oracle%'";
        Statement stmtQueryGetDbVersion = connSys.createStatement();
        ResultSet rsetGetDbVersion = stmtQueryGetDbVersion.executeQuery(queryGetDbVersion);
        while (rsetGetDbVersion.next()) {
            dbBanner = rsetGetDbVersion.getString("BANNER");
        }
        stmtQueryGetDbVersion.close();
        System.out.println(dbBanner);

    }

    /*
     * Methods
     */

    // Method executed when Exit Button tapped
    public void exitButtonTapped() {
        // Cast the Window of UI Control Button exit to Stage
        animation.pause();
        ((Stage) exit.getScene().getWindow())
                .fireEvent(new WindowEvent(((Stage) exit.getScene().getWindow()), WindowEvent.WINDOW_CLOSE_REQUEST));
    }

    private void nextTime() {
        if (xTick == 59) {
            xTock++;
            xTick = 0;
        } else {
            xTick++;
        }

        xTockValue = xTock + ((1d / 60d) * xTick);
    }

    private void plotTime() {

        if ((xTockValue % 1) == 0) {
            // get TPS values from DB
            try {
                String queryTPS = "SELECT VALUE from v$sysstat where name in ('user commits')";
                Statement stmt = connSys.createStatement();
                ResultSet rset = stmt.executeQuery(queryTPS);
                while (rset.next()) {
                    String tps = rset.getString("VALUE");
                    valueSqlTPS = Integer.parseInt(tps);
                }
                stmt.close();
            } catch (Exception ex) {
                System.out.println(ex);
            }

            savedValueSqlTPS = valueSqlTPS;
            valueSqlTPS = valueSqlTPS - vorWertTPS;
            vorWertTPS = savedValueSqlTPS;

            // In the 1st execution we don't have a savedValue, so don't print anything and
            // wait for the 2nd execution
            if (!firstInTPS) {
                // updateMessage(String.valueOf(valueSqlTPS));
                valueY = valueSqlTPS;
            } else {
                valueY = 0;
                firstInTPS = false;
            }

            xAxisDataSeries.getData().add(new Data<Number, Number>(xTockValue, valueY));

            // every xTockValue (second xAxis) after 50 (initial xAxis = new NumberAxis(0,
            // 50, 5)) move range 1 xTock
            if (xTockValue > 50) {
                xAxis.setLowerBound(xAxis.getLowerBound() + 1);
                xAxis.setUpperBound(xAxis.getUpperBound() + 1);
            }
        }
    }

    public void play() {
        animation.play();
    }

}

Ich habe wie Ihr seht nur die FXML Node AreaChart definiert, wobei im SceneBuilder noch die Children "CategoryAxis" und "NumberAxis" konfiguriert werden. Im meinem Beispiel habe ich aber für x und y eine NumberAxis - kann das aber im SceneBuilder nicht ändern!?

Dann weiß ich auch nicht wo genau ich den Code zum konfigurieren des Chart und der Animation plazieren soll?

Irgendwie habe ich das Gefühl das nicht mehr viel fehlt, aber wie gesagt bin ich wie vernagelt bzw. verstehe vermutlich den Zusammenhang noch nicht gut genug.

Ich hoffe ich habe mich verständlich ausgedrückt - wenn nicht BITTE einfach fragen - bin für jede Diskussion sehr dankbar!

Gruß

Ralf
 

dzim

Top Contributor
Ich bin heute zu fertig, um es mir genau anzuschauen, werde morgen es morgen mal versuchen.
Was mir auffällt:
  • Kudos, dass du schön ModelInjectable u.s.w. aus den anderen Threads verwendest! Das freut einen, dass auch noch andere es wirklich lesen.
  • Was aber fehlt, ist die Start-Klasse, die alles zusammenführt.
  • Es sieht so aus, als wäre dein UI komplett in dem FXML definiert, aber du lädst es in sich selbst noch mal (click auf den Button)
Da du scheinbar schon recht weit mit dem grundsätzlichen Verständnis bist, mute ich dir jetzt mal zu (und ermutige dich auch dazu), dir vielleicht mal ein paar der Beispiele aus meinem GitHub-Repository anzuschauen:
https://github.com/bgmf/poc/tree/master/simple-tests-fx/src/main/java/eu/dzim/tests/fx
  • Im "MainExample.java" mal "Root.fxml" gegen "MultiInstanceTestRoot.fxml" austauschen und probieren...
  • Controller dazu hat den Namen "MultiInstanceTestRootController" im controller package
  • Hintergrund: Ich war zu faul, für jedes FXML auch ein Root zu machen... :)
Das Beispiel würde dir in etwa aufzeigen, wie du dein UI grundsätzlich aufbauen könntest.
 

ralfb1105

Bekanntes Mitglied
Hallo dzim,

Kudos, dass du schön ModelInjectable u.s.w. aus den anderen Threads verwendest! Das freut einen, dass auch noch andere es wirklich lesen.
Das mit den Interfaces etc. habt Ihr mir ja schön beigebracht :D

Ich habe es vermutlich nicht ganz verständlich erklärt bzw. dargestellt. Ich habe eine "Main" Klasse "DBMonitor.java" - sorry, die heisst leider so wie das Besipiel das als eigenständige Klasse funktioniert - werde ich Morgen mal ändern. Die sieht folgendermaßen aus:
Java:
package application;
   
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;

public class DBMonitor extends Application {
   
    //Fields
    private Model model = new Model();
    private DB db = new DB();
   
    //Constructor
    public DBMonitor() {
        super();
    }
   
   
    /*
     * @Override Methods
     */
   
    @Override
    public void init() throws Exception {
       
    }

    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = ViewLoader.load("MainController.fxml", clazz -> ControllerFactory.controllerForClass(clazz, model));
            Scene scene = new Scene(root);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.setTitle("DBMonitor");
            primaryStage.setResizable(false);
            primaryStage.setOnCloseRequest(event -> {
                db.removeExceptionListener();
            });
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
   
    public static void main(String[] args) {
        launch(args);
    }
}
Dazu die "MainController.fxml" - die enthält nur den Button der den DB Monitor starten soll:
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.VBox?>

<VBox prefHeight="188.0" prefWidth="272.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
   <children>
      <HBox alignment="CENTER" prefHeight="56.0" prefWidth="272.0">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
         <children>
            <Button fx:id="dbMonitor" mnemonicParsing="false" onAction="#dbMonitorButtonTapped" text="DB Monitor" />
         </children>
      </HBox>
      <HBox prefHeight="75.0" prefWidth="272.0" />
      <HBox alignment="CENTER_RIGHT" prefHeight="41.0" prefWidth="272.0">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
         <children>
            <Button fx:id="exit" mnemonicParsing="false" onAction="#exitButtonTapped" text="EXIT" />
         </children>
      </HBox>
   </children>
</VBox>

Was mir jetzt fehlt ist das Know-How/Verständnis, wie ich die Methode für den Button definiere/codiere.
Wie oben gezeigt kann ich ein Fenster mit dem ViewLoader Mechnismus starten und darin wird aus das angezeigt was ich im SceneBuilder für das FXML definiert habe --> z.B. das AreaChart. Hier fehlt mir aber jetzt das Verständnis wie ich den Code aus der eigenständigen Test Klasse, die ja mein Chart schon darstellt, in die neu erstellte Controller Klasse mit den FXML Nodes "verbinde" oder besser "implementiere".

Ich weiß, vermutlich zu schwierig zu verstehen ...

Ich mache jetzt erst einmal Feierabend und werde mir auf der Suche nach Anregungen auf jeden Fall Deine Beispiele auf GitHub ansehen - Danke schon mal dafür.

Vielleicht findest Du ja noch ein ppar Minuten um mir auf die Sprünge zu helfen mit einer Idee ;)

Gruß

Ralf
 

ralfb1105

Bekanntes Mitglied
Hallo Daniel,

... vielleicht mal ein paar der Beispiele aus meinem GitHub-Repository anzuschauen:
https://github.com/bgmf/poc/tree/master/simple-tests-fx/src/main/java/eu/dzim/tests/fx
  • Im "MainExample.java" mal "Root.fxml" gegen "MultiInstanceTestRoot.fxml" austauschen und probieren...
  • Controller dazu hat den Namen "MultiInstanceTestRootController" im controller package
Wo finde ich denn die zugehörigen FXML Dateien, oder sind die nicht hier im Repository zu finden und es geht hier rein um die Aufrufe zwischen den Controllern?
Gruß
Ralf
 

ralfb1105

Bekanntes Mitglied
Hallo Daniel, @All,

mein Versuch von gestern das Problem darzustellen war m.E. nicht sehr glücklich bezogen auf die Klassen Namen und die Darstellung. Aus diesem Grunde jetzt hier noch einmal ein neuer "Aufschlag" der meine Frage hoffentlich etwas besser beschreibt ;)

1. Das Programm "OracleDynamicChartExample" zeigt kontinuierlich die TPS Werte aus einer DB Instanz auf der x-Achse eines AreaChart an. Dieses Programm basiert auf dem Oracle JDK 8 Beispiel "StockLineChartApp". Ich habe das Beispiel genutzt weil ich nicht wusste wie ich so einen "Monitor" codieren sollte. Das Programm basiert nicht auf dem MVC Pattern und stellt für mich nur die Basis da - ziel ist es so einen "Monitor" und mein bestehendes Projekt, welches auf dem MVC Pattern basiert einzubauen.
Hier mal ein Screenshot des Prgramms: https://cloud.ralfb-web.de/index.php/s/7top977Ax9DCiyJ
  • OracleDynamicChartExample.java
Java:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
*
* A Database Monitor with TPS values.
*
*/

public class OracleDynamicChartExample extends Application {

    // Fields
    private AreaChart<Number, Number> chart;
    private Series<Number, Number> xAxisDataSeries;
    private NumberAxis xAxis;
    private Timeline animation;
    private double xTock = 0;
    private double xTick = 0;
    private double xTockValue = 0;
    private int valueY = 0;
    private String dbSysUser = "sys as sysdba";
    private String dbSysUserPassword = "*****";
    private String dbHost = "*****";
    private String tnsPort = "6506";
    private String dbSID = "ORCL51";
    private String connectString = "jdbc:oracle:thin:@" + dbHost + ":" + tnsPort + "/" + dbSID;
    private Connection connSys;
    private int valueSqlTPS;
    private int vorWertTPS = 0;
    private int savedValueSqlTPS;
    private boolean firstInTPS = true;

    // Constructor
    public OracleDynamicChartExample() {

        // Create Database connection
        try {
            connSys = DriverManager.getConnection(connectString, dbSysUser, dbSysUserPassword);
        } catch (Exception ex) {
            System.out.println(ex);
        }

        // 6 "minutes" data per frame

        final KeyFrame frame = new KeyFrame(Duration.millis(1000 / 10), (ActionEvent actionEvent) -> {
            for (int count = 0; count < 6; count++) {
                nextTime();
                plotTime();
            }
        });

        // create timeline to add new data every 10th (1000 / 10 in frame) of second --> 100ms
        animation = new Timeline();
        animation.getKeyFrames().add(frame);
        animation.setCycleCount(Animation.INDEFINITE);
    }

    public Parent createContent() {
        xAxis = new NumberAxis(0, 50, 5);
        final NumberAxis yAxis = new NumberAxis(0, 100, 10);
        chart = new AreaChart<>(xAxis, yAxis);
        // setup AreaChart
        final String dbMonitorCss = getClass().getResource("OracleDynamicChartExample.css").toExternalForm();
        chart.getStylesheets().add(dbMonitorCss);
        chart.setCreateSymbols(true);
        chart.setAnimated(false);
        chart.setLegendVisible(true);
        chart.setTitle("DB Monitor " + dbSID);
        //xAxis.setLabel("Seconds since Start");
        xAxis.setForceZeroInRange(false);
        xAxis.setAutoRanging(false);
        yAxis.setAutoRanging(true);
        yAxis.setLabel("TPS");
        //yAxis.setTickLabelFormatter(new DefaultFormatter(yAxis, "TPS ", null));

        // add starting data
        xAxisDataSeries = new Series<>();
        xAxisDataSeries.setName("Transactions per Second");
        // create some starting data
        xAxisDataSeries.getData().add(new Data<Number, Number>(xTockValue, valueY));

        chart.getData().add(xAxisDataSeries);
        return chart;
    }

    private void nextTime() {
        if (xTick == 59) {
            xTock++;
            xTick = 0;
        } else {
            xTick++;
        }

        xTockValue = xTock + ((1d / 60d) * xTick);
    }

    private void plotTime() {

        if ((xTockValue % 1) == 0) {
            // get TPS values from DB
            try {
                String queryTPS = "SELECT VALUE from v$sysstat where name in ('user commits')";
                Statement stmt = connSys.createStatement();
                ResultSet rset = stmt.executeQuery(queryTPS);
                while (rset.next()) {
                    String tps = rset.getString("VALUE");
                    valueSqlTPS = Integer.parseInt(tps);
                }
                stmt.close();
            } catch (Exception ex) {
                System.out.println(ex);
            }

            savedValueSqlTPS = valueSqlTPS;
            valueSqlTPS = valueSqlTPS - vorWertTPS;
            vorWertTPS = savedValueSqlTPS;

            // In the 1st execution we don't have a savedValue, so don't print anything and
            // wait for the 2nd execution
            if (!firstInTPS) {
                // updateMessage(String.valueOf(valueSqlTPS));
                valueY = valueSqlTPS;
            } else {
                valueY = 0;
                firstInTPS = false;
            }

            xAxisDataSeries.getData().add(new Data<Number, Number>(xTockValue, valueY));

            // every xTockValue (second xAxis) after 50 (initial xAxis = new NumberAxis(0, 50, 5)) move range 1 xTock
            if (xTockValue > 50) {
                xAxis.setLowerBound(xAxis.getLowerBound() + 1);
                xAxis.setUpperBound(xAxis.getUpperBound() + 1);
            }
        }
    }

    public void play() {
        animation.play();
    }

    @Override

    public void stop() {
        animation.pause();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(createContent()));
        primaryStage.show();
        play();
    }

    /**
     *
     * Java main for when running without JavaFX launcher
     *
     */

    public static void main(String[] args) {
        launch(args);

    }

}
  • OracleDynamicChartExample.css
Java:
.chart {
    -fx-background-image: url("images/BackgroundSteel1400.png");
}
.chart-content {
    -fx-padding: 15px;
    -fx-background: #fffff0;
}


.axis {
    -fx-font-size: 1.5em;
    -fx-tick-label-fill: #ce5b27;
    -fx-font-family: Tahoma;
    -fx-tick-length: 15;
    -fx-minor-tick-length: 5;
}
.axis-label {
   -fx-text-fill: #444444;
}
.axis-tick-mark {
    -fx-stroke: #444444;
    -fx-stroke-width: 1.5px;
}

.axis-minor-tick-mark {
    -fx-stroke: #444444;
    -fx-stroke-width: 0.5px;
}


.chart-series-area-line {
    -fx-stroke-width: 1.5px;
    -fx-effect: null;
}

Soweit zu dem Beispiel, was so als eigenständies Programm funktioniert. Um den Post nicht zu lang werden zu lassen, beschreibe ich mein Test Programm, in dem der Monitor implementiert werden soll, im nächsten Post.
 
Zuletzt bearbeitet:

ralfb1105

Bekanntes Mitglied
Hallo,

hier nun mein Test Programm mit folgender File Struktur:

Code:
 \_ src
   \__ application
      \__ Main.java  (Main Programm - lädt Main Window über ViewLoader)
      \__ DB.java (Stellt DB Verbindung her)
      \__ Model.java (Dies und das - benötige ich hier nicht, habe ich der Vollständigkeit halber integriert.)
      \__ Controller.java      (Main Controller)
      \__ ControllerDBMonitor.java  (Controller für das Fenster mit dem AreaChart, sprich der DB Monitor)
      \__ ControllerInjectable.java  (Interface)
      \__ ControllerFactory.java (Wird im ViewLoader Aufruf benötigt)
      \__ ExceptionListener.java (Interface)
      \__ DBInjectable.java (Interface)
      \__ ModelInjectable.java (Interface)
      \__ ViewLoader.java (Loader für FXML)
      \__ application.css (für die Schönheit ;-)
      \__ Main.fxml (FXML Definition für Main Window - Eingabe DB Zugangsdaten und DB Monitor Button)
      \__ DBMonitorView.fxml (FXML Definition für DB Monitor Window - hier wird AreaChart definiert)

Hier die meiner Meinung nach für die Findung einer Lösung des Problems notwendigen Klassen:
1. Main.java
Java:
package application;
 
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;

public class Main extends Application {
 
    //Fields
    private Model model = new Model();
    private DB db = new DB();
 
    //Constructor
    public Main() {
        super();
    }
 
 
    /*
     * @Override Methods
     */
 
    @Override
    public void init() throws Exception {
     
    }

    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = ViewLoader.load("Main.fxml", clazz -> ControllerFactory.controllerForClass(clazz, model));
            Scene scene = new Scene(root);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.setTitle("Main");
            primaryStage.setResizable(false);
            primaryStage.setOnCloseRequest(event -> {
                db.removeExceptionListener();
            });
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}
2. Main.fxml
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.VBox?>

<VBox prefHeight="180.0" prefWidth="355.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
   <children>
      <HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="272.0">
         <VBox.margin>
            <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
         </VBox.margin>
         <children>
            <TextField fx:id="dbHost" prefHeight="25.0" prefWidth="184.0" promptText="DB Host" text="172.17.197.93">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </TextField>
            <TextField fx:id="dbPort" promptText="DB Port" text="6506">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </TextField>
         </children>
      </HBox>
      <HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="272.0">
         <VBox.margin>
            <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
         </VBox.margin>
         <children>
            <TextField fx:id="dbUser" prefHeight="25.0" prefWidth="180.0" promptText="DB User" text="sys as sysdba">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </TextField>
            <TextField fx:id="dbPwd" promptText="DB Password" text="Oracle2016!">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </TextField>
         </children></HBox>
      <HBox alignment="CENTER_RIGHT" prefHeight="41.0" prefWidth="272.0">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
         <children>
            <TextField fx:id="dbSID" promptText="DB SID" text="ORCL51">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="36.0" top="5.0" />
               </HBox.margin>
            </TextField>
            <Button fx:id="dbMonitor" mnemonicParsing="false" onAction="#dbMonitorButtonTapped" prefHeight="25.0" prefWidth="83.0" text="DB Monitor">
               <HBox.margin>
                  <Insets right="20.0" />
               </HBox.margin></Button>
            <Button fx:id="exit" mnemonicParsing="false" onAction="#exitButtonTapped" text="EXIT" />
         </children>
      </HBox>
   </children>
</VBox>
3. Controller.java
Java:
package application;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class Controller implements ExceptionListener, ModelInjectable, DBInjectable {

    // Fields
    private Model model;
    private DB db;

    // Constructor
    public Controller() {
        super();
    }

    /*
     * @Override Methods
     */

    @Override
    public void setModel(Model model) {
        this.model = model;
    }

    @Override
    public void setDB(DB db) {
        this.db = db;

    }

    @Override
    public void exceptionOccurred(Throwable th) {
        String msg = String.valueOf(th);
        System.out.println(msg);
    }

    /*
     * FXML Nodes (fx:id)
     */

    @FXML
    Button dbMonitor;

    @FXML
    Button exit;

    @FXML
    TextField dbHost;

    @FXML
    TextField dbPort;

    @FXML
    TextField dbUser;

    @FXML
    TextField dbPwd;

    @FXML
    TextField dbSID;

    /*
     * Getter
     */

    public String getDbHost() {
        return dbHost.getText();
    }

    public String getDbPort() {
        return dbPort.getText();
    }

    public String getDbUser() {
        return dbUser.getText();
    }

    public String getDbPwd() {
        return dbPwd.getText();
    }

    public String getdbSID() {
        return dbSID.getText();
    }

    public String getConnectString() {
        return "jdbc:oracle:thin:@" + getDbHost() + ":" + getDbPort() + "/" + getdbSID();
    }

    /*
     * Methods
     */

    // Method initialize() will be executed after all FXML Nodes are ready. This is
    // the place for Initialization of Nodes.
    @FXML
    public void initialize() {
        this.db = new DB();
        this.model = new Model();

        // Register ExceptionListener with DB(Model) class to get Exceptions from DB
        // class in Controller for showing in the View
        db.registerExceptionListener(th -> {
            String msg = String.valueOf(th);
            System.out.println(msg);

        });

        model.registerExceptionListener(th -> {
            String msg = String.valueOf(th);
            System.out.println(msg);
        });

    }

    public void exitButtonTapped(ActionEvent event) {
        // Cast the Window of UI Control Button exit to Stage
        ((Stage) exit.getScene().getWindow())
                .fireEvent(new WindowEvent(((Stage) exit.getScene().getWindow()), WindowEvent.WINDOW_CLOSE_REQUEST));

    }

    // Method for DB Monitor Button
    public void dbMonitorButtonTapped() {
        Parent rootDBMonitor = ViewLoader.load("DBMonitorView.fxml",
                clazz -> ControllerFactory.controllerForClass(clazz, model, db, this));
        Stage stageDBMonitor = new Stage();
        stageDBMonitor.initModality(Modality.APPLICATION_MODAL);
        stageDBMonitor.setOpacity(1);
        stageDBMonitor.setTitle("DB Monitor View");
        Scene sceneDBMonitor = new Scene(rootDBMonitor);
        sceneDBMonitor.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        stageDBMonitor.setScene(sceneDBMonitor);
        stageDBMonitor.show();
    }

}
4. ControllerDBMonitor.java
Java:
package application;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


import javafx.fxml.FXML;
import javafx.scene.chart.AreaChart;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class ControllerDBMonitor implements ExceptionListener, ModelInjectable, ControllerInjectable, DBInjectable {

    // Fields
    private Controller controller;
    private Model model;
    private DB db;
    private Connection connSys;

    private String dbBanner;

    // Constructor
    public ControllerDBMonitor() {
        super();

    }

    // FXML Nodes
    @FXML
    Button exit;

    @FXML
    AreaChart<Number, Number> chart;

    /*
     * Implemented Methods
     */

    @Override
    public void setDB(DB db) {
        this.db = db;

    }

    @Override
    public void setController(Controller controller) {
        this.controller = controller;
    }

    @Override
    public void setModel(Model model) {
        this.model = model;

    }

    @Override
    public void exceptionOccurred(Throwable th) {
        String msg = String.valueOf(th);
        System.out.println(msg);
    }

    // Initialize Method
    public void initialize() throws SQLException {
        chart.setTitle("DB Monitor " + controller.getdbSID());
        connSys = db.dbConnect(controller.getConnectString(), controller.getDbUser(), controller.getDbPwd());
        String queryGetDbVersion = "select banner from v$version where banner like '%Oracle%'";
        Statement stmtQueryGetDbVersion = connSys.createStatement();
        ResultSet rsetGetDbVersion = stmtQueryGetDbVersion.executeQuery(queryGetDbVersion);
        while (rsetGetDbVersion.next()) {
            dbBanner = rsetGetDbVersion.getString("BANNER");
        }
        stmtQueryGetDbVersion.close();
        System.out.println(dbBanner);

    }

    /*
     * Methods
     */

    // Method executed when Exit Button tapped
    public void exitButtonTapped() {
        // Cast the Window of UI Control Button exit to Stage

        ((Stage) exit.getScene().getWindow())
                .fireEvent(new WindowEvent(((Stage) exit.getScene().getWindow()), WindowEvent.WINDOW_CLOSE_REQUEST));
    }

}
5. DBMonitorView.fxml
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="374.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ControllerDBMonitor">
   <children>
      <HBox alignment="CENTER" prefHeight="303.0" prefWidth="600.0">
         <VBox.margin>
            <Insets left="10.0" right="10.0" top="20.0" />
         </VBox.margin>
         <children>
            <AreaChart fx:id="chart">
              <xAxis>
                <CategoryAxis side="BOTTOM" />
              </xAxis>
              <yAxis>
                <NumberAxis side="LEFT" />
              </yAxis>
            </AreaChart>
         </children>
      </HBox>
      <HBox alignment="CENTER_RIGHT" prefHeight="29.0" prefWidth="600.0">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
         <children>
            <Button fx:id="exit" mnemonicParsing="false" onAction="#exitButtonTapped" text="EXIT" />
         </children>
      </HBox>
   </children>
</VBox>

Ich hoffe bis hierher ist verständlich was ich habe.
Nun noch zu dem was ich plane ... Ich möchte so wie im Beispiel "OracleDynamicChartExample.java" ein AreaChart anzeigen welches die Werte aus der DB dynamisch anzeigt --> dieses Fenster wird angezeigt und die Animation gestartet wenn ich den DB Monitor Button im Main Window drücke.

Bin für jede Idee dankbar :)

Gruß
Ralf
 

ralfb1105

Bekanntes Mitglied
Hallo,

ich habe es nun hin bekommen. Was mich zu Anfang irritiert hat war die AreaChart Implementierung im SceneBuilder und das ich hier die x und y Axis nicht als NumberAxis definieren konnte, oder ich es nicht gesehen habe wie es geht. Ich habe jetzt das FXML File manuell geändert und dann in der initialize() Methode des "ControllerDBMonitor" die notwendigen Definitionen (DataSeries, etc.) durchgeführt.

Hier nun die Klassen die ich im Vergleich zum vorherigen Post geändert habe:
1. ControllerDBMonitor.java
Java:
package application;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Duration;

public class ControllerDBMonitor implements ExceptionListener, ModelInjectable, ControllerInjectable, DBInjectable {

    // Fields
    private Controller controller;
    private Model model;
    private DB db;
    private Connection connSys;
    private Series<Number, Number> xAxisDataSeries;
    private Timeline animation;
    private double xTock = 0;
    private double xTick = 0;
    private double xTockValue = 0;
    private int valueY = 0;
    private int valueSqlTPS;
    private int vorWertTPS = 0;
    private int savedValueSqlTPS;
    private boolean firstInTPS = true;

    // Constructor
    public ControllerDBMonitor() {
        super();

        // 6 "minutes" data per frame

        final KeyFrame frame = new KeyFrame(Duration.millis(1000 / 10), (ActionEvent actionEvent) -> {
            for (int count = 0; count < 6; count++) {
                nextTime();
                plotTime();
            }
        });

        // create timeline to add new data every 10th (1000 / 10 in frame) of second -->
        // 100ms
        animation = new Timeline();
        animation.getKeyFrames().add(frame);
        animation.setCycleCount(Animation.INDEFINITE);
    }

    // FXML Nodes
    @FXML
    Button exit;

    @FXML
    AreaChart<Number, Number> chart;

    @FXML
    NumberAxis xAxis;

    @FXML
    NumberAxis yAxis;

    /*
     * Implemented Methods
     */

    @Override
    public void setDB(DB db) {
        this.db = db;

    }

    @Override
    public void setController(Controller controller) {
        this.controller = controller;
    }

    @Override
    public void setModel(Model model) {
        this.model = model;

    }

    @Override
    public void exceptionOccurred(Throwable th) {
        String msg = String.valueOf(th);
        System.out.println(msg);
    }

    // Initialize Method
    public void initialize() throws SQLException {
        chart.setCreateSymbols(true);
        chart.setAnimated(false);
        chart.setLegendVisible(true);
        chart.setTitle("DB Monitor " + controller.getdbSID());

        xAxisDataSeries = new Series<>();
        xAxisDataSeries.setName("Transactions per Second");
        // create some starting data
        xAxisDataSeries.getData().add(new Data<Number, Number>(xTockValue, valueY));

        chart.getData().add(xAxisDataSeries);

        // Create DB connection
        connSys = db.dbConnect(controller.getConnectString(), controller.getDbUser(), controller.getDbPwd());

        // Start the animation
        play();

    }

    /*
     * Methods
     */

    // Method executed when Exit Button tapped
    public void exitButtonTapped() {
        // Cast the Window of UI Control Button exit to Stage
        animation.stop();
        ((Stage) exit.getScene().getWindow())
                .fireEvent(new WindowEvent(((Stage) exit.getScene().getWindow()), WindowEvent.WINDOW_CLOSE_REQUEST));
    }

    private void nextTime() {
        if (xTick == 59) {
            xTock++;
            xTick = 0;
        } else {
            xTick++;
        }

        xTockValue = xTock + ((1d / 60d) * xTick);
    }

    private void plotTime() {

        if ((xTockValue % 1) == 0) {
            // get TPS values from DB
            try {
                String queryTPS = "SELECT VALUE from v$sysstat where name in ('user commits')";
                Statement stmt = connSys.createStatement();
                ResultSet rset = stmt.executeQuery(queryTPS);
                while (rset.next()) {
                    String tps = rset.getString("VALUE");
                    valueSqlTPS = Integer.parseInt(tps);
                }
                stmt.close();
            } catch (Exception ex) {
                System.out.println(ex);
            }

            savedValueSqlTPS = valueSqlTPS;
            valueSqlTPS = valueSqlTPS - vorWertTPS;
            vorWertTPS = savedValueSqlTPS;

            // In the 1st execution we don't have a savedValue, so don't print anything and
            // wait for the 2nd execution
            if (!firstInTPS) {
                // updateMessage(String.valueOf(valueSqlTPS));
                valueY = valueSqlTPS;
            } else {
                valueY = 0;
                firstInTPS = false;
            }

            xAxisDataSeries.getData().add(new Data<Number, Number>(xTockValue, valueY));

            // every xTockValue (second xAxis) after 50 (initial xAxis = new NumberAxis(0,
            // 50, 5)) move range 1 xTock
            if (xTockValue > 50) {
                xAxis.setLowerBound(xAxis.getLowerBound() + 1);
                xAxis.setUpperBound(xAxis.getUpperBound() + 1);
            }
        }
    }

    public void play() {
        animation.play();
    }
}

2. DBMonitor.fxml
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="374.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ControllerDBMonitor">
   <children>
      <HBox alignment="CENTER" prefHeight="303.0" prefWidth="600.0">
         <VBox.margin>
            <Insets left="10.0" right="10.0" top="20.0" />
         </VBox.margin>
         <children>
            <AreaChart fx:id="chart">
              <xAxis>
                <NumberAxis animated="false" autoRanging="false" forceZeroInRange="false" side="BOTTOM" upperBound="50.0" fx:id="xAxis" />
              </xAxis>
              <yAxis>
                <NumberAxis fx:id="yAxis" animated="false" label="TPS" side="LEFT" tickUnit="10.0" />
              </yAxis>
            </AreaChart>
         </children>
      </HBox>
      <HBox alignment="CENTER_RIGHT" prefHeight="29.0" prefWidth="600.0">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
         <children>
            <Button fx:id="exit" mnemonicParsing="false" onAction="#exitButtonTapped" text="EXIT" />
         </children>
      </HBox>
   </children>
</VBox>

Falls jemanden noch grobe Fehler auffallen, bin wie gesagt für jeden Hinweis sehr(!) dankbar :)

Gruß
Ralf
 

dzim

Top Contributor
Alright. Danke erst mal für die Aufstellung der Klassen etc. Ich habe erst mal nur alles Überflogen. Aber ich muss zugeben, dass ich das konkrete Problem, glaube ich, immer noch nicht ganz nachvollziehen kann.

Geht es um das Laden der Daten ins Chart? Irgendwie komm ich jetzt immer weniger damit klar, was du eigentlich für Hilfe brauchst... ;)
 

ralfb1105

Bekanntes Mitglied
Hallo Daniel,

aktuell, sprich mit meinem letzten Post, funktioniert es wie ich es mir gedacht hatte. Sorry für den etwas unübersichtlichen Thread - genau genommen bitte ALLES VON GESTERN vergessen, es sind nur die beiden Posts von heute im Dezail entscheidend. Mir fehlte einfach der Punkt wie ich die Implementierung aus dem Oracle Beispiel, welches ja ohne FXM implementiert ist, in mein, oder besser Euer, Framework zu implementieren habe. Den Knoten konnte ich lösen als ich mich "getraut" habe manuell die FXM zu editieren und zwei NumberAxis zu definieren. Dann konnte ich den Code aus dem Beispiel fast 1:1 übernehmen - alles aus meiner Sicht gut. Es gibt bestimmt noch vieles an der generellen Implementierung des DB Monitor zu verbessern, aber ich bin schon ein bisschen Stolz das ich es überhaupt geschafft habe einen Monitor mit JavaFX zu implementieren.
Falls es interessiert, hier mal ein ScreenShot: https://cloud.ralfb-web.de/index.php/s/fk8629r84TXQX9L

Gruß
Ralf
 

dzim

Top Contributor
Also eigentlich sollte es kaum einen Unterschied geben (technisch betrachtet). Vorher hast du halt im Code dein UI definiert und gleich die Kontrolle vor Ort übernommen. Jetzt lagerst du das UI aus und erstellst den Controller mit der besprochenen Methode. Dort wo du bisher den Code hattest und nun den FXMLLoader verwendest, erhälst du ja sowohl das Pane (StackPane, ...) als auch den Controller aus dem FXML. Und mehr als das Pane an die Stelle zu fügen, wo du es brauchst, musst du eigentlich nicht.

Ich sehe im Moment einfach das Problem noch nicht...

Da dein Projekt ja auch nicht mehr so klein ist (nehme ich an), wäre es ja vielleicht eine Idee, einen Gist (oder gar ein Projekt) auf GitHub / GitLab / BitBucket anzulegen und andere dort reinschauen zu lassen - vielleicht fällt uns dann eher auf, was das Problem sein könnten. Nur anhand der textuellen Beschreibung oder einiger Code-Schnipsel komme ich im Moment mit meiner Hilfestellung auch nicht mehr weiter... Sorry.
 

ralfb1105

Bekanntes Mitglied
Hallo Daniel,

da dass AreaChart angezeigt wird und mit den Daten versorgt wird würde ich diesen Thread erst einmal als abgeschlossen betrachten. Den Hinweis auf GitHub werde ich mal ins Auge fassen, habe mich mit der Thematik bisher noch nicht im Detail beschäftigt ;) scheint aber in der Tat sinnvoll zu sein um bei größeren Themen besser Probleme und Ansichten austauschen zu können.

Gruß

Ralf
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
X JavaFX AreaChart area höhe wird nicht richtig dargestellt AWT, Swing, JavaFX & SWT 2
I Monitor-Standyby verhindern AWT, Swing, JavaFX & SWT 6
VfL_Freak Swing Zweiter Monitor von Java-Anwendung ansprechbar ?? AWT, Swing, JavaFX & SWT 2
O Swing JFrame auf Monitor platzieren AWT, Swing, JavaFX & SWT 3
L 2 Monitore, Fenster öffnet sich im falschen Monitor AWT, Swing, JavaFX & SWT 3
G Fenster auf zweitem Monitor platzieren AWT, Swing, JavaFX & SWT 5
S Progress Monitor mit einer Methode() verbinden AWT, Swing, JavaFX & SWT 4
R Swing Background Image in JFrame implementieren AWT, Swing, JavaFX & SWT 40
L JavaFX SelectionService selber implementieren AWT, Swing, JavaFX & SWT 7
D JavaFX Google API/OpenStreetMap in GUI implementieren AWT, Swing, JavaFX & SWT 1
Joker4632 JavaFX GridPane richtig implementieren AWT, Swing, JavaFX & SWT 7
Thallius Single Sign On in Java Implementieren AWT, Swing, JavaFX & SWT 6
L JavaFX StackedBar Implementieren? AWT, Swing, JavaFX & SWT 7
B GridLayout - wie am besten implementieren AWT, Swing, JavaFX & SWT 3
U Buttons schräg implementieren AWT, Swing, JavaFX & SWT 4
B mouseOnEntered ( Controller richtig implementieren) AWT, Swing, JavaFX & SWT 4
R AWT QuadratListener implementieren AWT, Swing, JavaFX & SWT 17
C In Hauptfenster Programm-Klassen implementieren AWT, Swing, JavaFX & SWT 9
K Action Listener implementieren über Objekt AWT, Swing, JavaFX & SWT 14
E Swing KeyListener implementieren AWT, Swing, JavaFX & SWT 12
M KeyListener richtig implementieren AWT, Swing, JavaFX & SWT 3
E Swing JTextArea in JFrame, wie nun WindowFocusListener implementieren? AWT, Swing, JavaFX & SWT 2
S Swing Spiel Richtig/Falsch implementieren AWT, Swing, JavaFX & SWT 5
S TextArea ausgabe ohne JFrame zu implementieren AWT, Swing, JavaFX & SWT 2
S Swing JTextArea - Bild auf/ab Tasten implementieren AWT, Swing, JavaFX & SWT 4
H shell in view implementieren; menu mit keystroke unterlegen AWT, Swing, JavaFX & SWT 8
L SWT CLabel als Button implementieren? AWT, Swing, JavaFX & SWT 6
3TageBart Ebenen in Zeichen-Programm implementieren AWT, Swing, JavaFX & SWT 9
GilbertGrape ActionListener implementieren oder Eigenen für jede Komponente? AWT, Swing, JavaFX & SWT 9
R setEnabled bei eigenem Widget implementieren? AWT, Swing, JavaFX & SWT 3
S Methoden implementieren AWT, Swing, JavaFX & SWT 7
B KeyListener implementieren AWT, Swing, JavaFX & SWT 3
F Welchen Listener implementieren? AWT, Swing, JavaFX & SWT 4
S Mehrsprachigkeit in GUI implementieren AWT, Swing, JavaFX & SWT 3
F Größenänderung mittels Maus - selbst implementieren? AWT, Swing, JavaFX & SWT 3
M ActionListener implementieren AWT, Swing, JavaFX & SWT 10
J Scrolling implementieren mit JPanels AWT, Swing, JavaFX & SWT 5

Ähnliche Java Themen


Oben