Numass control room global update
This commit is contained in:
parent
ad958f8f9c
commit
0c8fe56f78
@ -16,16 +16,24 @@ description = "The control room application for numass slow control"
|
||||
|
||||
compileKotlin.kotlinOptions.jvmTarget = "1.8"
|
||||
|
||||
configurations{
|
||||
devices.extendsFrom(compile)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':numass-core')
|
||||
compile project(':numass-control')
|
||||
compile project(':numass-server')
|
||||
compile project(':numass-control:cryotemp')
|
||||
|
||||
//graphics
|
||||
compile 'org.controlsfx:controlsfx:8.40.12'
|
||||
|
||||
compile "no.tornado:tornadofx:1.7.4"
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8"
|
||||
|
||||
//DataForge dependencies
|
||||
compile project(':numass-control')
|
||||
compile project(':numass-server')
|
||||
|
||||
// optional device classpath
|
||||
devices project(':numass-control:cryotemp')
|
||||
devices project(':numass-control:msp')
|
||||
devices project(':numass-control:vac')
|
||||
}
|
||||
|
||||
shadowJar{
|
||||
@ -33,10 +41,10 @@ shadowJar{
|
||||
}
|
||||
|
||||
|
||||
task debug(dependsOn: classes, type: JavaExec) {
|
||||
task debugWithDevice(dependsOn: classes, type: JavaExec) {
|
||||
main mainClass
|
||||
args "--config.resource=/config/server.xml"
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
classpath = sourceSets.main.runtimeClasspath + configurations.devices
|
||||
description "Start application in debug mode"
|
||||
group "debug"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package inr.numass.control
|
||||
|
||||
import hep.dataforge.control.devices.Device
|
||||
import hep.dataforge.control.devices.PortSensor
|
||||
import hep.dataforge.control.measurements.Sensor
|
||||
import hep.dataforge.fx.fragments.FXFragment
|
||||
import hep.dataforge.fx.fragments.FragmentWindow
|
||||
import hep.dataforge.storage.filestorage.FileStorage
|
||||
@ -88,6 +89,7 @@ class BoardView : View("Numass control board", ImageView(getDFIcon())) {
|
||||
vgrow = Priority.ALWAYS;
|
||||
deviceStateIndicator(connection,Device.INITIALIZED_STATE)
|
||||
deviceStateIndicator(connection, PortSensor.CONNECTED_STATE)
|
||||
deviceStateIndicator(connection, Sensor.MEASURING_STATE)
|
||||
deviceStateIndicator(connection, "storing")
|
||||
pane {
|
||||
hgrow = Priority.ALWAYS
|
||||
|
@ -1,6 +1,7 @@
|
||||
package inr.numass.control
|
||||
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.context.Global
|
||||
import javafx.stage.Stage
|
||||
import tornadofx.*
|
||||
import java.io.File
|
||||
@ -14,11 +15,14 @@ class ServerApp : App(BoardView::class) {
|
||||
|
||||
override fun start(stage: Stage) {
|
||||
NumassControlUtils.getConfig(this).ifPresent {
|
||||
val libPath = parameters.named.getOrDefault("libPath","../lib");
|
||||
context = Context
|
||||
.builder("NUMASS-SERVER")
|
||||
.classPath(File(libPath).toURI().toURL())
|
||||
.build()
|
||||
val libDir = File(parameters.named.getOrDefault("libPath", "../lib"));
|
||||
val contextBuilder = Context
|
||||
.builder("NUMASS-SERVER");
|
||||
if (libDir.exists()) {
|
||||
Global.logger().info("Found library directory {}. Loading it into server context", libDir)
|
||||
contextBuilder.classPath(libDir.listFiles { _, name -> name.endsWith(".jar") }.map { it.toURI().toURL() })
|
||||
}
|
||||
context = contextBuilder.build();
|
||||
controller.load(context, it);
|
||||
}
|
||||
super.start(stage)
|
||||
|
@ -1,12 +1,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
apply plugin: 'application'
|
||||
|
||||
if (!hasProperty('mainClass')) {
|
||||
ext.mainClass = 'inr.numass.cryotemp.PKT8App'
|
||||
ext.mainClass = 'inr.numass.control.cryotemp.PKT8App'
|
||||
}
|
||||
mainClassName = mainClass
|
||||
|
||||
|
@ -28,8 +28,8 @@ import java.util.Objects;
|
||||
*/
|
||||
public class PKT8App extends NumassControlApplication<PKT8Device> {
|
||||
@Override
|
||||
protected DeviceViewConnection<PKT8Device> buildView() {
|
||||
return PKT8View.build();
|
||||
protected DeviceViewConnection<PKT8Device> buildView(PKT8Device device) {
|
||||
return PKT8View.build(device.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,6 +22,6 @@ public class PKT8DeviceFactory implements DeviceViewFactory {
|
||||
|
||||
@Override
|
||||
public DeviceViewConnection buildView(Device device) {
|
||||
return PKT8View.build();
|
||||
return PKT8View.build(device.getContext());
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,8 @@ public class PKT8PlotFragment extends FXFragment {
|
||||
super("PKT8 cryogenic temperature viewer", 600, 400);
|
||||
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PKT8Plot.fxml"));
|
||||
FXMLLoader loader = new FXMLLoader(device.getContext().getClassLoader().getResource("fxml/PKT8Plot.fxml"));
|
||||
loader.setClassLoader(device.getContext().getClassLoader());
|
||||
loader.load();
|
||||
plotController = loader.getController();
|
||||
device.connect(plotController, Roles.VIEW_ROLE);
|
||||
@ -25,16 +26,6 @@ public class PKT8PlotFragment extends FXFragment {
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// showingProperty().addListener((observable, oldValue, newValue) -> {
|
||||
// if (device.isMeasuring()) {
|
||||
// if (newValue) {
|
||||
// device.getMeasurement().addListener(plotController);
|
||||
// } else {
|
||||
// device.getMeasurement().removeListener(plotController);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package inr.numass.control.cryotemp;
|
||||
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.control.measurements.Measurement;
|
||||
import hep.dataforge.control.measurements.MeasurementListener;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
@ -32,9 +33,10 @@ import java.util.ResourceBundle;
|
||||
*/
|
||||
public class PKT8View extends DeviceViewConnection<PKT8Device> implements Initializable, MeasurementListener {
|
||||
|
||||
public static PKT8View build() {
|
||||
public static PKT8View build(Context context) {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(PKT8View.class.getResource("/fxml/PKT8Indicator.fxml"));
|
||||
FXMLLoader loader = new FXMLLoader(context.getClassLoader().getResource("fxml/PKT8Indicator.fxml"));
|
||||
loader.setClassLoader(context.getClassLoader());
|
||||
loader.load();
|
||||
return loader.getController();
|
||||
} catch (IOException e) {
|
||||
@ -77,13 +79,15 @@ public class PKT8View extends DeviceViewConnection<PKT8Device> implements Initia
|
||||
@Override
|
||||
public void open(@NotNull PKT8Device device) throws Exception {
|
||||
super.open(device);
|
||||
|
||||
this.logFragment = new LogFragment();
|
||||
logFragment.addRootLogHandler();
|
||||
new FragmentWindow(logFragment).bindTo(consoleButton);
|
||||
|
||||
|
||||
plotFragment = new PKT8PlotFragment(device);
|
||||
startStopButton.selectedProperty().setValue(getDevice().isMeasuring());
|
||||
|
||||
new FragmentWindow(logFragment).bindTo(consoleButton);
|
||||
new FragmentWindow(plotFragment).bindTo(plotButton);
|
||||
bindBooleanToState("storing", storeButton.selectedProperty());
|
||||
}
|
||||
|
@ -24,6 +24,6 @@ public class MspDeviceFactory implements DeviceViewFactory {
|
||||
|
||||
@Override
|
||||
public DeviceViewConnection buildView(Device device) {
|
||||
return MspView.build();
|
||||
return MspView.build(device.getContext());
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ import java.util.Objects;
|
||||
public class MspApp extends NumassControlApplication<MspDevice> {
|
||||
|
||||
@Override
|
||||
protected DeviceViewConnection<MspDevice> buildView() {
|
||||
return MspView.build();
|
||||
protected DeviceViewConnection<MspDevice> buildView(MspDevice device) {
|
||||
return MspView.build(device.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package inr.numass.control.msp.fx;
|
||||
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.control.NamedValueListener;
|
||||
import hep.dataforge.control.devices.Device;
|
||||
import hep.dataforge.control.devices.DeviceListener;
|
||||
@ -60,9 +61,10 @@ import java.util.ResourceBundle;
|
||||
*/
|
||||
public class MspView extends DeviceViewConnection<MspDevice> implements DeviceListener, Initializable, NamedValueListener {
|
||||
|
||||
public static MspView build() {
|
||||
public static MspView build(Context context) {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(MspView.class.getResource("/fxml/MspView.fxml"));
|
||||
FXMLLoader loader = new FXMLLoader(context.getClassLoader().getResource("fxml/MspView.fxml"));
|
||||
loader.setClassLoader(context.getClassLoader());
|
||||
loader.load();
|
||||
return loader.getController();
|
||||
} catch (IOException e) {
|
||||
|
@ -2,7 +2,6 @@ package inr.numass.control;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.control.connections.DeviceConnection;
|
||||
import hep.dataforge.control.connections.Roles;
|
||||
import hep.dataforge.control.devices.Device;
|
||||
import hep.dataforge.control.devices.DeviceFactory;
|
||||
@ -28,14 +27,18 @@ public abstract class NumassControlApplication<D extends Device> extends Applica
|
||||
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
rootLogger.setLevel(Level.INFO);
|
||||
|
||||
DeviceViewConnection<D> controller = buildView();
|
||||
device = setupDevice();
|
||||
DeviceViewConnection<D> controller = buildView(device);
|
||||
|
||||
Scene scene = new Scene(controller.getPane());
|
||||
|
||||
primaryStage.setScene(scene);
|
||||
Platform.runLater(() -> {
|
||||
device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE);
|
||||
});
|
||||
|
||||
primaryStage.show();
|
||||
|
||||
device = setupDevice(controller);
|
||||
|
||||
setupStage(primaryStage, device);
|
||||
NumassControlUtils.setDFStageIcon(primaryStage);
|
||||
}
|
||||
@ -45,7 +48,7 @@ public abstract class NumassControlApplication<D extends Device> extends Applica
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract DeviceViewConnection<D> buildView();
|
||||
protected abstract DeviceViewConnection<D> buildView(D device);
|
||||
|
||||
/**
|
||||
* Get a device factory for given device
|
||||
@ -58,7 +61,7 @@ public abstract class NumassControlApplication<D extends Device> extends Applica
|
||||
|
||||
protected abstract boolean acceptDevice(Meta meta);
|
||||
|
||||
private D setupDevice(DeviceConnection<D> controller) {
|
||||
private D setupDevice() {
|
||||
Meta config = NumassControlUtils.getConfig(this)
|
||||
.orElseGet(() -> NumassControlUtils.readResourceMeta("/config/devices.xml"));
|
||||
|
||||
@ -68,12 +71,10 @@ public abstract class NumassControlApplication<D extends Device> extends Applica
|
||||
|
||||
|
||||
try {
|
||||
D d = (D) getDeviceFactory().build(ctx, deviceConfig);
|
||||
@SuppressWarnings("unchecked") D d = (D) getDeviceFactory().build(ctx, deviceConfig);
|
||||
d.init();
|
||||
NumassControlUtils.connectStorage(d, config);
|
||||
Platform.runLater(() -> {
|
||||
d.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE);
|
||||
});
|
||||
|
||||
return d;
|
||||
} catch (ControlException e) {
|
||||
throw new RuntimeException("Failed to build device", e);
|
||||
|
@ -3,23 +3,10 @@ apply plugin: 'application'
|
||||
version = "0.5.0"
|
||||
|
||||
if (!hasProperty('mainClass')) {
|
||||
//ext.mainClass = 'inr.numass.readvac.app.ConsoleVac'
|
||||
ext.mainClass = 'inr.numass.readvac.fx.ReadVac'
|
||||
}
|
||||
mainClassName = mainClass
|
||||
|
||||
dependencies {
|
||||
compile project(':numass-control')
|
||||
}
|
||||
|
||||
//task consoleVac(type: CreateStartScripts) {
|
||||
// mainClassName = "inr.numass.readvac.app.ConsoleVac"
|
||||
// applicationName = "vac-console"
|
||||
// outputDir = new File(project.buildDir, 'scripts')
|
||||
// classpath = jar.outputs.files + project.configurations.runtime
|
||||
//}
|
||||
//
|
||||
//applicationDistribution.into("bin") {
|
||||
// from(consoleVac)
|
||||
// fileMode = 0755
|
||||
//}
|
||||
}
|
@ -48,6 +48,6 @@ public class VacDeviceFactory implements DeviceViewFactory {
|
||||
|
||||
@Override
|
||||
public DeviceViewConnection buildView(Device device) {
|
||||
return VacCollectorView.build();
|
||||
return VacCollectorView.build(device.getContext());
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ import java.util.Objects;
|
||||
*/
|
||||
public class ReadVac extends NumassControlApplication<VacCollectorDevice> {
|
||||
@Override
|
||||
protected DeviceViewConnection<VacCollectorDevice> buildView() {
|
||||
return VacCollectorView.build();
|
||||
protected DeviceViewConnection<VacCollectorDevice> buildView(VacCollectorDevice device) {
|
||||
return VacCollectorView.build(device.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
package inr.numass.control.readvac.fx;
|
||||
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.control.connections.Roles;
|
||||
import hep.dataforge.control.devices.Device;
|
||||
import hep.dataforge.control.measurements.Measurement;
|
||||
@ -60,9 +61,10 @@ import java.util.ResourceBundle;
|
||||
*/
|
||||
public class VacCollectorView extends DeviceViewConnection<VacCollectorDevice> implements Initializable, MeasurementListener {
|
||||
|
||||
public static VacCollectorView build() {
|
||||
public static VacCollectorView build(Context context) {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(VacCollectorView.class.getResource("/fxml/VacCollector.fxml"));
|
||||
FXMLLoader loader = new FXMLLoader(context.getClassLoader().getResource("fxml/VacCollector.fxml"));
|
||||
loader.setClassLoader(context.getClassLoader());
|
||||
loader.load();
|
||||
return loader.getController();
|
||||
} catch (IOException e) {
|
||||
@ -137,7 +139,7 @@ public class VacCollectorView extends DeviceViewConnection<VacCollectorDevice> i
|
||||
} else {
|
||||
view = new VacuumeterView();
|
||||
}
|
||||
sensor.connect(view, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE, Roles.MEASUREMENT_CONSUMER_ROLE);
|
||||
sensor.connect(view, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE);
|
||||
return view;
|
||||
}).forEach(views::add);
|
||||
setupView();
|
||||
|
@ -7,45 +7,52 @@
|
||||
<?import java.net.URL?>
|
||||
<AnchorPane styleClass="vacBox" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<stylesheets>
|
||||
<URL value="@/styles/vacstyles.css" />
|
||||
</stylesheets>
|
||||
<URL value="@vacstyles.css"/>
|
||||
</stylesheets>
|
||||
<children>
|
||||
<VBox layoutX="50.0" layoutY="6.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<VBox layoutX="50.0" layoutY="6.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<AnchorPane styleClass="namePane">
|
||||
<children>
|
||||
<Label id="name" fx:id="deviceNameLabel" alignment="CENTER" prefHeight="40.0" text="device Name" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="50.0" AnchorPane.topAnchor="0.0" />
|
||||
<ToggleSwitch fx:id="disableButton" alignment="CENTER" layoutX="130.0" layoutY="10.0" prefWidth="40.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0" />
|
||||
</children>
|
||||
<Label id="name" fx:id="deviceNameLabel" alignment="CENTER" prefHeight="40.0" text="device Name"
|
||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="50.0"
|
||||
AnchorPane.topAnchor="0.0"/>
|
||||
<ToggleSwitch fx:id="disableButton" alignment="CENTER" layoutX="130.0" layoutY="10.0"
|
||||
prefWidth="40.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0"
|
||||
AnchorPane.topAnchor="10.0"/>
|
||||
</AnchorPane>
|
||||
<Separator />
|
||||
<Separator/>
|
||||
<BorderPane>
|
||||
<left>
|
||||
<Label id="pressure" fx:id="valueLabel" alignment="CENTER_RIGHT" minWidth="110.0" prefHeight="60.0" text="---" BorderPane.alignment="CENTER">
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding></Label>
|
||||
<Label id="pressure" fx:id="valueLabel" alignment="CENTER_RIGHT" minWidth="110.0"
|
||||
prefHeight="60.0" text="---" BorderPane.alignment="CENTER">
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
</left>
|
||||
<right>
|
||||
<Label id="units" fx:id="unitLabel" prefHeight="60.0" prefWidth="75.0" text="mbar" BorderPane.alignment="CENTER">
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
</padding></Label>
|
||||
<Label id="units" fx:id="unitLabel" prefHeight="60.0" prefWidth="75.0" text="mbar"
|
||||
BorderPane.alignment="CENTER">
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
</right>
|
||||
</BorderPane>
|
||||
<Separator />
|
||||
<Separator/>
|
||||
<Pane minHeight="30.0" prefHeight="30.0" VBox.vgrow="ALWAYS">
|
||||
<children>
|
||||
<ToggleSwitch fx:id="powerSwitch" layoutX="58.0" layoutY="5.0" text="Power" />
|
||||
</children>
|
||||
<ToggleSwitch fx:id="powerSwitch" layoutX="58.0" layoutY="5.0" text="Power"/>
|
||||
</Pane>
|
||||
<Separator />
|
||||
<Separator/>
|
||||
<AnchorPane styleClass="statusPane">
|
||||
<children>
|
||||
<Label fx:id="status" maxWidth="200.0" text="Initializing" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
<Label fx:id="status" maxWidth="200.0" text="Initializing" wrapText="true"
|
||||
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
|
||||
AnchorPane.topAnchor="0.0"/>
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
</AnchorPane>
|
||||
</children>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import org.controlsfx.control.ToggleSwitch?>
|
||||
@ -8,7 +8,7 @@
|
||||
<BorderPane fx:id="root" styleClass="vacBox" xmlns="http://javafx.com/javafx/8.0.40"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<stylesheets>
|
||||
<URL value="@/styles/vacstyles.css"/>
|
||||
<URL value="@vacstyles.css"/>
|
||||
</stylesheets>
|
||||
<center>
|
||||
<VBox>
|
||||
@ -25,9 +25,6 @@
|
||||
<left>
|
||||
<Label id="pressure" fx:id="valueLabel" alignment="CENTER_RIGHT" minWidth="110.0" prefHeight="60.0"
|
||||
text="---" BorderPane.alignment="CENTER">
|
||||
<BorderPane.margin>
|
||||
<Insets/>
|
||||
</BorderPane.margin>
|
||||
<padding>
|
||||
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
|
||||
</padding>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<?import java.net.URL?>
|
||||
<BorderPane fx:id="root" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.control.readvac.fx.VacCollectorView">
|
||||
<stylesheets>
|
||||
<URL value="@/styles/vacstyles.css" />
|
||||
<URL value="@/fxml/vacstyles.css" />
|
||||
</stylesheets>
|
||||
<right>
|
||||
<ScrollPane fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER" minWidth="250.0" BorderPane.alignment="CENTER">
|
||||
|
Loading…
Reference in New Issue
Block a user