Применение CSS для составления диаграмм в FXML - PullRequest
0 голосов
/ 10 октября 2018

Я пытаюсь реализовать набор суммированных диаграмм в FXML, аналогично в этом примере .Я довольно неопытен и не смог найти полных примеров настройки CSS в FXML Controller.Попытка самостоятельно адаптировать код привела либо к исключению java.lang.NullPointerException, либо к сообщению `loadStylesheetUnPrivileged ', либо к обоим, и код либо не запускается, либо выполняется без каких-либо изменений в CSS.SceneBuilder может показывать прозрачный предварительный просмотр, но он не работает при запуске программы.

FXML:

<AnchorPane fx:id="graphpane" 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.Graph1Controller">
<children>
  <StackPane fx:id="stackpane" prefHeight="150.0" prefWidth="200.0" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
     <children>
        <LineChart fx:id="M1chart" legendVisible="false" prefHeight="388.0" prefWidth="573.0" style=".chart-plot-background{-fx-background-color: transparent;} .default-color0.chart-series-line{-fx-stroke: #006564;}" stylesheets="@..css/M1chart.css" title="Recent Lap Times">
          <xAxis>
            <NumberAxis fx:id="M1xAxis" forceZeroInRange="false" minorTickVisible="false" side="BOTTOM" tickLabelsVisible="false" tickMarkVisible="false" />
          </xAxis>
          <yAxis>
            <NumberAxis fx:id="M1yAxis" autoRanging="false" label="Laptime (s)" side="LEFT" upperBound="240.0" />
          </yAxis>
        </LineChart>
        <LineChart fx:id="M2chart" legendVisible="false" prefHeight="388.0" prefWidth="573.0" style=".chart-plot-background{-fx-background-color: transparent;} .default-color0.chart-series-line{-fx-stroke: #FFCE44;}" stylesheets="@..css/M2chart.css" title="Recent Lap Times">
           <xAxis>
              <NumberAxis fx:id="M2xAxis" forceZeroInRange="false" minorTickVisible="false" side="BOTTOM" tickLabelsVisible="false" tickMarkVisible="false" />
           </xAxis>
           <yAxis>
              <NumberAxis fx:id="M2yAxis" autoRanging="false" label="Laptime (s)" side="LEFT" upperBound="240.0" />
           </yAxis>
        </LineChart>
        <LineChart fx:id="L1chart" legendVisible="false" prefHeight="388.0" prefWidth="573.0" style=".chart-plot-background{-fx-background-color: transparent;} .default-color0.chart-series-line{-fx-stroke: #832C40;}" stylesheets="@..css/L1chart.css" title="Recent Lap Times">
           <xAxis>
              <NumberAxis fx:id="L1xAxis" forceZeroInRange="false" minorTickVisible="false" side="BOTTOM" tickLabelsVisible="false" tickMarkVisible="false" />
           </xAxis>
           <yAxis>
              <NumberAxis fx:id="L1yAxis" autoRanging="false" label="Laptime (s)" side="LEFT" upperBound="240.0" />
           </yAxis>
        </LineChart>
     </children>
  </StackPane>
</children>   
</AnchorPane>

Есть 3 листа CSS, которые я хочу загрузить, каждый из которыхнаходится в той же папке (css), папка находится в том же каталоге, что и исходные файлы Java, и каждый структурирован следующим образом:

CSS:

.chart-plot-background{
-fx-background-color: transparent;
}

.default-color0.chart-series-line{
-fx-stroke: #832C40;
}

В основнойкласс, за которым я пытался следовать ответ Роланда в этой теме , но, похоже, он не работает.

Main:

public void start(Stage primaryStage) throws IOException {

//First FXML Controller code omitted

//Second FXML Controller code starts here
Stage stage2 = new Stage();
FXMLLoader loader2 = new FXMLLoader();
String fxmlDocPath2 = "(filepath)\\Graph1.fxml"; //actual filepath replaced with placeholder for this post
FileInputStream fxmlStream2 = new FileInputStream(fxmlDocPath2);
AnchorPane root2 = (AnchorPane) loader2.load(fxmlStream2);
Scene scene2 = new Scene(root2);
scene2.getStylesheets().add(getClass().getResource("css/M1chart.css").toExternalForm());
scene2.getStylesheets().add(getClass().getResource("css/M2chart.css").toExternalForm());
scene2.getStylesheets().add(getClass().getResource("css/L1chart.css").toExternalForm());
stage2.setScene(scene2);
stage2.setTitle("TEST");
stage2.setX(primaryStage.getX() + 550);
stage2.setY(primaryStage.getY());
stage2.show();
//Second FXML Controller code ends
}

Запуск этого кода дает мнеошибки ниже:

null/..css/M1chart.css
null/..css/M2chart.css
null/..css/L1chart.css
Oct 10, 2018 10:45:22 PM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
WARNING: Resource "..css/M1chart.css" not found.
Oct 10, 2018 10:45:22 PM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
WARNING: Resource "..css/M2chart.css" not found.
Oct 10, 2018 10:45:22 PM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
WARNING: Resource "..css/L1chart.css" not found.
Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
    at application.Core.start(Core.java:71)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
    ... 1 more
Exception running application application.Core

Я не уверен, что я пропустил, чтобы вызвать появление нулевого значения в пути css и сбой кода, может кто-нибудь помочь?

1 Ответ

0 голосов
/ 11 октября 2018

Я хочу загрузить 3 листа CSS, каждый из которых находится в одной папке (css), папка находится в том же каталоге, что и исходные файлы Java

Youследует переместить ваши файлы css / fxml в отдельную папку ресурсов - некоторые инструменты сборки даже не скопируют ваши ресурсы в выходной каталог, если они находятся в той же папке, что и исходные файлы.

Скажем, структура вашего проектаthis:

YourApplicationRoot
 |--res   //resource root
 |  |-fxml
 |  | |-Main.fxml
 |  |-css
 |    |-styles.css
 |--src   //source root
    |-application
      |-Core.java //main class is here

Во-первых, не используйте встроенные стили в FXML (style="some rules here") - это сложно поддерживать.

Далее вам не нужно 3 отдельных файла CSS, вы можете поместить все свои стили CSS в один файл (styles.css) и использовать классы пользовательских стилей для их разделения:

/* These styles will only be applied to a chart with class `m1chart` */ 
.m1chart .chart-plot-background{
  -fx-background-color: transparent;
}
.m1chart .default-color0.chart-series-line{
  -fx-stroke: red;
}

/* These styles will only be applied to a chart with class `m2chart` */
.m2chart .chart-plot-background{
  -fx-background-color: transparent;
}
.m2chart .default-color0.chart-series-line{
  -fx-stroke: blue;
}

/* These styles will only be applied to a chart with class `l1chart` */
.l1chart .chart-plot-background{
  -fx-background-color: transparent;
}
.l1chart .default-color0.chart-series-line{
  -fx-stroke: green;
}

Теперь у вас есть два способа применить css к вашему приложению - от fxml и из кода:

Чтобы применить styles.css из fxml, просто добавьте атрибут stylesheets к корневому узлу и добавьтеstyleClass атрибут для каждого LineChart, который вы хотите стилизовать:

/* Main.fxml, irrelevant parts are omitted */
<AnchorPane stylesheets="@../css/styles.css">
   ...
   <LineChart styleClass="m1chart">
      ...
   </LineChart>
   <LineChart styleClass="m2chart">
      ...
   </LineChart>
   <LineChart styleClass="l1chart">
      ...
   </LineChart> 
   ...   
</AnchorPane>

Не забудьте удалить атрибуты style и stylesheets из LineChart узлов.

Дляприменить styles.css непосредственно из кода (обратите внимание, что ваши стили CSS не будут видны в SceneBuilder, если вы используете этот метод):

//in Core.java start() method
yourScene.getStylesheets().add(getClass().getResource("/css/styles.css").toExternalForm());

//in your fxml controller
M1chart.getStyleClass().add("m1chart");
M2chart.getStyleClass().add("m2chart");
L1chart.getStyleClass().add("l1chart");
...