Forgive me if what I ask is obvious but I can't figure out how to create a binding in a StyleClassedTextArea, using RichTextFx. What I want to do is to have the area and a button (that will trigger text-processing of some kind) and disable the button if the area is empty.
My code is the following
Main.java
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java
package application;
import java.net.URL;
import java.util.ResourceBundle;
import org.fxmisc.richtext.StyleClassedTextArea;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableStringValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
public class Controller implements Initializable {
#FXML private StyleClassedTextArea mainArea;
#FXML private Button processButton;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
processButton.disableProperty().bind(Bindings.isEmpty((ObservableStringValue) mainArea.textProperty()));
}
}
Main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?import org.fxmisc.richtext.StyleClassedTextArea?>
<AnchorPane prefHeight="308.0" prefWidth="291.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="application.Controller">
<children>
<VBox layoutY="6.0" prefHeight="308.0" prefWidth="291.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<StyleClassedTextArea fx:id="mainArea" />
<Button fx:id="processButton" mnemonicParsing="false" text="process" />
</children>
</VBox>
</children>
</AnchorPane>
and this because mainTextArea.textProperty() returns ObservableValue<String> when I cast it throws an exception with the following stack trace
javafx.fxml.LoadException:
/C:/Users/dcg601/workspace/javafx/bin/application/Main.fxml
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at application.Main.start(Main.java:22)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassCastException: org.reactfx.value.SuspendableValWrapper cannot be cast to javafx.beans.value.ObservableStringValue
at application.Controller.initialize(Controller.java:20)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
... 17 more
It's crazy but it works:
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
ObservableValue<String> qwer = mainArea.textProperty();
ObservableStringValue qwerQ = new ObservableStringValue() {
public String get() { return qwer.getValue(); }
public String getValue() { return qwer.getValue(); }
public void addListener( InvalidationListener listener ) {
qwer.addListener( listener );
}
public void removeListener( InvalidationListener listener ) {
qwer.removeListener( listener );
}
public void addListener( ChangeListener<? super String> listener ) {
qwer.addListener( listener );
}
public void removeListener( ChangeListener<? super String> listener ) {
qwer.removeListener( listener );
}
};
processButton.disableProperty().bind(Bindings.isEmpty( qwerQ ) );
}
But probably better to add a simple listeners:
mainArea.textProperty().addListener( ( ov, oldv, newv ) -> {
processButton.setDisable( newv.isEmpty() );
});
Related
Is there any easy way to put into the toHomepage() method the getHostServices().showDocument() command somehow, instead of doing lines and lines of code, so the code should look clean and simple?
package sample;
import javafx.application.HostServices;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
#FXML
private Button facebookButton;
#FXML
void toHomepage(ActionEvent event) {
}
}
If I press the button, it should directly link me to the Facebook URL
You need to pass the HostServices to the Controller.
Key Code: Set the HostServices in the Controller.
HostServices hostServices ;
public void setGetHostController(HostServices hostServices)
{
this.hostServices = hostServices;
}
Key Code: Passing HostServices to the Controller.
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
FXMLDocumentController fXMLDocumentController = loader.getController();
fXMLDocumentController.setGetHostController(getHostServices());
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author sedrick
*/
public class JavaFXApplication7 extends Application {
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
FXMLDocumentController fXMLDocumentController = loader.getController();
fXMLDocumentController.setGetHostController(getHostServices());
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Controller
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.HostServices;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
/**
*
* #author sedri
*/
public class FXMLDocumentController implements Initializable {
HostServices hostServices;
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
hostServices.showDocument("www.google.com");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
public void setGetHostController(HostServices hostServices)
{
this.hostServices = hostServices;
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication7.FXMLDocumentController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children>
</AnchorPane>
In JavaFX 8, I have created a custom TableCell with a TextField to get more control than with a "regular" TextFieldTableCell. What I want to achieve is to have that TextField automatically selected when an Add button is clicked (so the user doesn't have to click on that TextField or Tab to it after the Add-Record button is fired. Unfortunately, I only manage to select the row/cell but not the underlying TextField (and the startEdit() method doesn't seem to be reached).
Here is my code (Main FX Application code, POJO, FXML code created in Scene Builder, Controller code, and CustomTextFieldTableCell class):
Main.java
package test;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
POJO
package test;
import javafx.beans.property.SimpleStringProperty;
class TestObject {
private final SimpleStringProperty field1 = new SimpleStringProperty();
private final SimpleStringProperty field2 = new SimpleStringProperty();
public SimpleStringProperty field1Property() {
return field1;
}
public void setField1(String string) {
field1.set(string);
}
public SimpleStringProperty field2Property() {
return field2;
}
public void setField2(String string) {
field2.set(string);
}
}
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="425.0" prefWidth="517.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171" fx:controller="test.FXMLDocumentController">
<children>
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<TableView fx:id="tableView" layoutX="14.0" layoutY="52.0" prefHeight="359.0" prefWidth="489.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="52.0">
<columns>
<TableColumn fx:id="col1" prefWidth="150.0" text="C1" />
<TableColumn fx:id="col2" minWidth="0.0" prefWidth="141.0" text="C2" />
</columns>
</TableView>
<Button fx:id="btnAdd" layoutX="14.0" layoutY="14.0" onAction="#handleAdd" text="_Add" />
</children>
</AnchorPane>
FXMLDocumentController.java
package test;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class FXMLDocumentController implements Initializable {
#FXML
private Button btnAdd;
#FXML
private TableView<TestObject> tableView;
#FXML
private TableColumn<TestObject, String> col1;
#FXML
private TableColumn<TestObject, String> col2;
#FXML
private void handleAdd(ActionEvent event) {
TestObject testObject = new TestObject();
tableView.getItems().add(testObject);
tableView.edit(tableView.getItems().indexOf(testObject), col1);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
col1.setCellValueFactory(cellData -> cellData.getValue().field1Property());
col1.setCellFactory((final TableColumn<TestObject, String> column) -> new CustomTextFieldTableCell());
col1.setOnEditStart((TableColumn.CellEditEvent<TestObject, String> event) -> {
//Inside code doesn't seem to ever get reached
System.out.println("Edit started");
});
col2.setCellValueFactory(cellData -> cellData.getValue().field2Property());
col2.setCellFactory((final TableColumn<TestObject, String> column) -> new TableCell<>());
}
}
CustomTextFieldTableCell.java
package test;
import javafx.event.ActionEvent;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
public class CustomTextFieldTableCell extends TableCell<TestObject, String> {
private final TextField textField;
public CustomTextFieldTableCell() {
textField = new TextField();
textField.setOnAction((ActionEvent event) -> {
commitEdit(textField.getText());
event.consume();
});
textField.prefWidthProperty().bind(prefWidthProperty().subtract(3));
}
/** {#inheritDoc} */
#Override
public void startEdit() {
if (!isEditable()
|| getTableView() == null
|| getTableColumn() == null
|| getTableView() != null && !getTableView().isEditable()
|| getTableColumn() != null && !getTableColumn().isEditable()) {
return;
}
super.startEdit();
if (isEditing()) {
/*
textField.setText(getItem().trim());
this.setText(textField.getText());
*/
//Platform.runLater(() -> textField.requestFocus());
textField.requestFocus();
}
}
/** {#inheritDoc} */
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (empty) {
setGraphic(null);
} else {
textField.setText(item == null ? "" : item.trim());
setGraphic(textField);
}
}
}
What visually occurs:
What I need my code to do is to have caret placed inside the TextField or TextField focused, but this doesn't occur with my code right now.
Any idea what I am missing out?
This question already has answers here:
JavaFX Error: Controller value already specified
(1 answer)
javafx exception : Controller value already specified
(1 answer)
Closed 4 years ago.
I have looked at the posts for this and Im still stuck - any help please?
I am trying to display a line chart in scenebuilder (IntelliJ) - but keep getting different errors about constructors.The last error was
'JavaFX Error : Controller already specified'but have removed it previously and still get an error.
and have tried different arguments in Main for FXMLLoader with the loader.setController(...) line, and no luck. I keep reading about sometimes factory controllers are needed if arguments are being passed to the constructor - so think it might be this, but dont know how to write one.Any suggestions please? or good links for me to read up?
My last attempt for FXMLLoaderCode from Main below...
FXMLLoader loader = new FXMLLoader(getClass().getResource("/sample/view/graph.fxml"));
loader.setController(new Controller(sortList));
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
If anybody has any useful links so I could read up about factory controllers that would be really good. My full code is below.
My programs are
Main(Main.java)
entry point for program and uses FXML loader
Model(SortList.java)
places numbers in x and y(abscissa ordinate) groups
Controller(Controller.java)
add x,y to graph
View(graph.fxml)
graph xml displays x-y line chart
ReadInData(ReadInData.java)
Reads in and parses numbers
Errors
javafx.fxml.LoadException: Controller value already specified.
/C:/Users/user/IdeaProjects/myjavafx/out/production/myjavafx/sample/view/graph.fxml:18
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2597)
at javafx.fxml.FXMLLoader.access$100(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:914)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
at sample.Main.start(Main.java:32)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
at java.lang.Thread.run(Thread.java:748)
Model (SortList.java)
public class SortList {
private final double abscissa;
private final double ordinate;
public SortList(double abscissa, double ordinate) {
this.abscissa = abscissa;
this.ordinate = ordinate;
}
public double getabscissa() {
return abscissa;
}
public double getordinate() {
return ordinate;
}
}
View (graph.java)
fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.chart.ScatterChart?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.Label?>
<AnchorPane id="AnchorPane"
maxHeight="-Infinity"
maxWidth="-Infinity"
minHeight="-Infinity"
minWidth="-Infinity"
prefHeight="400.0"
prefWidth="600.0"
xmlns="http://javafx.com/javafx/8.0.121"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller = "sample.controller.Controller">
<children>
<ScatterChart layoutX="76.0" layoutY="33.0" prefHeight="335.0" prefWidth="449.0" title="Test Graph">
<xAxis>
<CategoryAxis label="X axis" pickOnBounds="false" side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis label="Y axis" side="LEFT" upperBound="1000.0" />
</yAxis>
</ScatterChart>
</children>
</AnchorPane>
Controller (Controller.java)
package sample.controller;
import javafx.fxml.Initializable;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import sample.model.SortList;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
public class Controller implements Initializable {
public LineChart<Double, Double> lineChart;
private final ArrayList<SortList> sortList;
public LineChart label1;
public Controller(ArrayList<SortList> sortList)
{
this.sortList = sortList;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
XYChart.Series<Double, Double> graphLine = new XYChart.Series<Double, Double>();
for (SortList sortlist : sortList) {
graphLine.getData().add(new XYChart.Data(sortlist.getabscissa(), sortlist.getordinate()));
}
lineChart.getData().add(graphLine);
}
}
Main (Main.java)
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Callback;
import sample.IO.ReadInData;
import sample.controller.Controller;
import sample.model.SortList;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
public class Main extends Application {
#Override
public void start(Stage stage) {
stage.setTitle("Line Chart Sample");
final ArrayList<SortList> sortList = ReadInData.ReadData("C:\\Users\\user\\Desktop\\Java problem\\test.csv");
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/sample/view/graph.fxml"));
loader.setController(new Controller(sortList));
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
loader.setControllerFactory(new Callback<Class<?>, Object>(){
#Override
public Object call(Class<?> param) {
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
public class SortList {
private final double abscissa;
private final double ordinate;
public SortList(double abscissa, double ordinate) {
this.abscissa = abscissa;
this.ordinate = ordinate;
}
public double getabscissa() {
return abscissa;
}
public double getordinate() {
return ordinate;
}
}
Input/Output Read in File (ReadInData.java)
package sample.IO;
import sample.model.SortList;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
public class ReadInData {
private static final String COMMA_DELIMITER = ",";
static public ArrayList<SortList> ReadData(String filename) {
BufferedReader br = null;
ArrayList<SortList> inputList = new ArrayList<SortList>();
try {
br = new BufferedReader(new FileReader(filename));
String line = "";
br.readLine();
while ((line = br.readLine()) != null) {
String[] inputData = line.split(COMMA_DELIMITER);
if (inputData.length > 0) {
try {
double abscissa = Double.parseDouble(inputData[0]);
double ordinate = Double.parseDouble(inputData[1]);
SortList row = new SortList(abscissa, ordinate);
inputList.add(row);
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return inputList;
}
}
Open your FXML file with Scene Builder and check this
Heyho,
i have a very strange load exception after starting my javafx project. The loadexception just appears when i provoke another error, otherwise everything seems to work fine. So the nullpointerexception which i also do not understand and might correlate with the load exception is the reason why i even see this loadexception.
I wrote a getController() Method in my Main class and in start() i wanted to get the controller by loader.getController(), which seems to return null. In my #FXML initialize() i instantiate the model graph, which calls my getController() Method in the constructor and when graph trie to use this constructor i certainly get a nullpointerexception..
Does anybody know the problem?
Here is the Stack trace
`javafx.fxml.LoadException:
/C:/Users/bertr/eclipse-workspace/Hashiwokakero/bin/application/view/Layout.fxml
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2571)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
at application.Main.start(Main.java:30)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2566)
... 12 more
Caused by: java.lang.NullPointerException
at application.model.Graph.<init>(Graph.java:88)
at application.view.Controller.initialize(Controller.java:68)
... 22 more
`
And the start()- Method
public class Main extends Application {
public static Controller controller;
#Override
public void start(Stage primaryStage) {
try {
//anLeitungLaden();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("view/Layout.fxml"));
Pane pane = (Pane) loader.load();
controller = loader.getController();
Scene scene = new Scene(pane);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("Hashiwokakero");
primaryStage.setScene(scene);
//primaryStage.getIcons().add(new Image("resources/logo2.png"));
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
The beginning of Controller class
package application.view;
import java.io.File;
import java.util.Arrays;
import application.model.Vertex;
import application.Main;
import application.model.Edge;
import application.model.Graph;
import application.model.HashiGenerator;
import application.model.HashiGenerator2;
import javafx.animation.Animation;
import javafx.animation.AnimationTimer;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.effect.Glow;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.shape.Shape;
import javafx.util.Duration;
public class Controller {
#FXML public Pane root;
#FXML public Pane pane;
#FXML public CheckBox checkboxMusic;
#FXML public CheckBox checkboxSoundeffect;
#FXML public Button newLevelButton;
public MediaPlayer mediaPlayer;
private MediaPlayer soundeffectPlayer;
private boolean soundEffect;
public int numberOfEmptyContainer;
public Graph level;
public DragStartHandler startHandler;
#FXML private void initialize() {
String musicFile = "src/resources/star-wars-cantina-song.mp3";
Media sound = new Media(new File(musicFile).toURI().toString());
mediaPlayer = new MediaPlayer(sound);
mediaPlayer.play();
numberOfEmptyContainer=0;
checkboxMusic.setSelected(true);
checkboxSoundeffect.setSelected(true);
soundEffect = true;
newLevelButton.setVisible(false);
newLevelButton.setDisable(true);
startHandler = new DragStartHandler();
level = new Graph(pane);
and the Layout.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.paint.*?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.text.*?>
<Pane id="root" fx:id="root" prefHeight="839.0" prefWidth="1281.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.view.Controller">
<children>
<Pane id="pane" fx:id="pane" layoutX="21.0" layoutY="64.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="749.0" prefWidth="1209.0" style="-fx-border-radius: 100; -fx-border-width: 100;">
<children>
<Button id="newLevelButton" fx:id="newLevelButton" layoutX="363.0" layoutY="342.0" mnemonicParsing="false" prefHeight="66.0" prefWidth="484.0" style="-fx-border-color: #ffd308; -fx-border-radius: 30;" text="Weiter zu Level 2" textFill="#ffd308">
<font>
<Font name="System Italic" size="40.0" />
</font></Button>
</children></Pane>
<CheckBox id="checkboxSoundeffect" fx:id="checkboxSoundeffect" layoutX="1032.0" layoutY="23.0" mnemonicParsing="false" onAction="#handleCheckboxSoundEffect" text="Soundeffekte" textFill="WHITE" />
<CheckBox id="checkboxMusic" fx:id="checkboxMusic" layoutX="1185.0" layoutY="23.0" mnemonicParsing="false" onAction="#handleCheckboxMusic" text="Musik" textFill="WHITE" />
</children>
</Pane>
Edit:
This is my class Graph
package application.model;
import java.io.File;
import java.util.Arrays;
import application.Main;
import application.view.Controller;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class Graph {
public int numberOfContainer = 8;
public int[][] adjazenzMatrix;
public int[] nodelist;
public boolean[] nodelistvisited;
private Controller controller;
private Pane pane = new Pane();
public Edge ContainerLine ;
public Vertex startContainer;
// 3 Zeilen/ 4 Spalten
// TODO: Positionen überlegen
public Vertex createContainer(double x, double y, double radius, int anzahl) {
return new Vertex(x, y, radius,anzahl);
}
public Graph(Pane pane){
controller= Main.getController();
pane = pane;
nodelist = new int[numberOfContainer];
adjazenzMatrix = new int[numberOfContainer][numberOfContainer];
for (int i = 0; i < numberOfContainer; ++i ) {
Arrays.fill(adjazenzMatrix[i],0);
nodelist[i] = i;
}
nodelistvisited = new boolean[numberOfContainer] ;
Arrays.fill(nodelistvisited,false);
Vertex[][] containerGrid = new Vertex[][]{
{createContainer(pane.getPrefWidth()-(7*pane.getPrefWidth())/8, (double)pane.getPrefHeight()-(5*pane.getPrefHeight())/6,30,4), null ,createContainer(pane.getPrefWidth()-(7*pane.getPrefWidth())/8, pane.getPrefHeight()-(1*pane.getPrefHeight())/6,30,3)},
{createContainer(pane.getPrefWidth()-(5*pane.getPrefWidth())/8, (double)pane.getPrefHeight()-(5*pane.getPrefHeight())/6,30,5), createContainer(pane.getPrefWidth()-(5*pane.getPrefWidth())/8, (double)pane.getPrefHeight()-(3*pane.getPrefHeight())/6,30,3),null},
{null, createContainer(pane.getPrefWidth()-(3*pane.getPrefWidth())/8, (double)pane.getPrefHeight()-(3*pane.getPrefHeight())/6,30,2),createContainer(pane.getPrefWidth()-(3*pane.getPrefWidth())/8, (double)pane.getPrefHeight()-(1*pane.getPrefHeight())/6,30,1)},
{createContainer(pane.getPrefWidth()-(1*pane.getPrefWidth())/8, (double)pane.getPrefHeight()-(5*pane.getPrefHeight())/6,30,1), createContainer(pane.getPrefWidth()-(1*pane.getPrefWidth())/8, (double)pane.getPrefHeight()-(3*pane.getPrefHeight())/6,30,1),null}
};
//Zeilen X Richtung
for (int i = 0; i < 4; ++i) {
//Spalten Y Richtung
for ( int j = 0; j<3; ++j) {
if(containerGrid[i][j] != null) {
Vertex c = containerGrid[i][j];
c.setOnDragDetected(controller.startHandler);
c.setOnMouseDragReleased(controller.dragReleaseHandler);
c.setOnMouseDragEntered(controller.dragEnteredHandler);
c.setUserData(Boolean.TRUE);
c.getChildren().addAll(c.circle, c.label,c.label2);
pane.getChildren().add(c);
}
}
}
} // KostruktorLevel
public void deepSearch(int[][] matrix,int[] nodelist ,boolean[] nodelistvisited ,int current,int suche){
nodelistvisited[current]=true; // Knoten als besucht kennzeichnen
for (int i=0;i<nodelist.length;i++)
{
if(matrix[current][i] == 1&& !nodelistvisited[i]) deepSearch(matrix,nodelist,nodelistvisited,i,suche);
}
}
}
I am working on a new GUI client and we are considering using JavaFX. I was wondering if anyone has a suggestion regarding making a draggable ToolWindow:
(Customer window) in the example. This mini-window should be able to get minimized and dragged out of the parent window, and docked back to it. I really do not want to use netbeans platform (or eclipse or swing for that matter).
You just have to create a custom pane for that:
The complete example is available on gist.
CustomPane.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
public class CustomPane extends AnchorPane implements Initializable {
#FXML Button closePane;
#FXML Button minPane;
#FXML Label title;
#FXML Pane contentPane;
#FXML Rectangle separator;
private boolean restoreFlag = false;
private double prefX;
private double prefY;
public CustomPane(String title){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"CustomPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
this.title.setText(title);
setButtonsLayout();
setStandardLayout();
}
public CustomPane(String title, double y, double x){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"CustomPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
this.title.setText(title);
this.setPrefSize(x, y);
setButtonsLayout();
setStandardLayout();
restoreRoot();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
closePane.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
setInvisible();
}
});
minPane.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
if(restoreFlag){
restoreFlag = false;
minPane.setText("_");
restoreRoot();
}
else{
restoreFlag = true;
minPane.setText("▭");
minimizeRoot();
}
}
});
}
protected void minimizeRoot() {
this.setPrefSize(prefX/2, title.getPrefHeight() + 5.0);
separator.setWidth(prefX/2 + 5);
this.setLayoutX(0);
this.setLayoutY(prefY-40);
setButtonsLayout();
contentPane.setVisible(false);
}
protected void restoreRoot() {
this.setPrefSize(prefX, prefY);
separator.setWidth(prefX);
contentPane.setVisible(true);
this.setLayoutX(0);
this.setLayoutY(0);
setButtonsLayout();
}
private void setStandardLayout() {
prefX = this.getPrefHeight();
prefY = this.getPrefWidth()-50;
}
public void setButtonsLayout(){
closePane.setLayoutX(this.getPrefWidth()-30);
minPane.setLayoutX(this.getPrefWidth()-55);
}
public void setInvisible(){
this.setVisible(false);
}
public ObservableList<Node> getContent(){
return contentPane.getChildren();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
customPane.fxml
<fx:root prefHeight="400.0" prefWidth="400.0"
type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1">
<children>
<Rectangle fx:id="separator" arcHeight="5.0" arcWidth="5.0" fill="WHITE"
height="33.0" layoutY="1.0" stroke="BLACK" strokeType="INSIDE" width="600.0" />
<Button fx:id="closePane" layoutX="573.0" layoutY="6.0"
mnemonicParsing="false" text="X" />
<Button fx:id="minPane" layoutX="545.0" layoutY="6.0"
mnemonicParsing="false" text="__" />
<Label fx:id="title" layoutX="14.0" layoutY="12.0" text="Title" />
<Pane fx:id="contentPane" layoutY="34.0" prefHeight="366.0"
prefWidth="600.0" />
</children>
</fx:root>