SplitPane Divider Position changes on its own - java

I have a SplitPane that is behaving strangely. It is "spontaneously" moving without interaction from the user.
Here is the sample FXML layout:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<SplitPane fx:id="splitPane" dividerPositions="0.29797979797979796" layoutX="100.0" layoutY="67.0" prefHeight="160.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
And the controller:
public class Controller {
#FXML
private SplitPane splitPane;
#FXML
private void initialize() {
// Add Listener to the divider value
splitPane.getDividers().get(0).positionProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("newValue = " + newValue);
});
splitPane.getDividers().get(0).setPosition(0.80);
}
}
Here I set the listener on the only divider to output it's current value when it changes. Just below, I set it to 0.80.
Here is the output:
newValue = 0.8
newValue = 0.7986577181208053
You see it does change after initially setting it. While this change is minimal in the example, the problem is exacerbated in my main application.
I am trying to save the divider's position between runs of my program, but with the position value changing on its own every time, the minor issue becomes a major one.
What is happening here and how can I prevent it from changing? Per the FXML, you can see there are no other controls that should be forcing a change due to minimum width, etc.

Related

How to reduce button click area (only to the button)

I've got a simple password generator in JavaFX. Whenever I click the button, a password is generated but also when I click somewhere else in the application area, the button also reacts. How can I reduce the click area?
Main
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("/sample/main.fxml"));
primaryStage.setTitle("Password Generator");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.setMaxWidth(610.0);
primaryStage.setMaxHeight(450.0);
primaryStage.setMinWidth(600.0);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Main.fxml
<Pane fx:id="mainPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="416.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#generatePassword" prefHeight="417.0" prefWidth="600.0" style="-fx-background-color: #ed801a;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button fx:id="generatePassword" layoutX="206.0" layoutY="216.0" mnemonicParsing="false" onMouseClicked="#generatePassword" prefHeight="59.0" prefWidth="188.0" text="Generate">
<font>
<Font name="System Italic" size="20.0" />
</font>
</Button>
</children>
</AnchorPane>
</children>
</Pane>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#generatePassword" prefHeight="417.0" prefWidth="600.0" style="-fx-background-color: #ed801a;" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
Remove the onMouseClicked="#generatePassword" from the AnchorPane declaration.

custom FXML component not loading - classnotfoundexception

I have followed tutorials and created my own custom element. It is an AnchorPane containing 6 overlapped canvases to create a graphing framework.
Below is the magnitudeGraph.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.layout.AnchorPane?>
<fx:root type="javafx.scene.layout.AnchorPane" minHeight="200.0" minWidth="700.0" prefHeight="300.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Canvas fx:id="backgroundCanvas" height="300.0" width="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Canvas fx:id="series1Canvas" height="300.0" width="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Canvas fx:id="series2Canvas" height="300.0" width="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Canvas fx:id="series3Canvas" height="300.0" layoutX="7.0" width="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Canvas fx:id="series4Canvas" height="300.0" width="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Canvas fx:id="savedSeriesCanvas" height="300.0" layoutY="-1.0" width="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</fx:root>
Fairly Simple. I then have a custom controller which loads this framework, called magnitudeGraphController
public class magnitudeGraphController extends AnchorPane implements Initializable {
#FXML
public Canvas backgroundCanvas;
#FXML
public Canvas series1Canvas;
#FXML
public Canvas series2Canvas;
#FXML
public Canvas series3Canvas;
#FXML
public Canvas series4Canvas;
#FXML
public Canvas savedSeriesCanvas;
public magnitudeGraphController(){
System.out.println("Graph Initialised");
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("magnitudeGraph.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
Nice and easy. So then on my main application controller I can call an instance of magnitudeGraph and the controller will load the fxml file with the root element being the anchorPane.
This is called with the following method in the main app:
public magnitudeGraphController spectrumgraph = new magnitudeGraphController();
Now the difficult thing comes when writing the fxml for my main app. I wrote the import for the controller:
<?import myApp.magnitudeGraphController?>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<magnitudeGraphController fx:id="spectrumgraph" layoutX="38.0" layoutY="33.0" minHeight="200.0" minWidth="700.0" prefHeight="300.0" prefWidth="944.0">
</AnchorPane>
What I get is an error on the fxml editor stating 'Class javafx.scene.layout.AnchorPane' does not support property MagnitudeGraphController'.
What is confusing me is that this was working perfectly. All I have done is changed the name of the fxml file and controller to a more identifiable name and have refactored the file to reflect this. I have gone back through my archived backup of when this was working and cannot find any difference except the file names. If I try and compile the error throws classnotfoundexception when trying to load magnitudeGraphController.
I have been tearing my hair out for ages and cannot find what has brought the whole thing down.

Components won't auto-resizing when using JFXDecorator, how to fix that?

I want to use JFXDecorator to fancy a look of a Window of my application. But using it brokes an auto-resize of components. This is what my code looks like
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("ApplicationView.fxml"));
Parent root = loader.load();
JFXDecorator decorator = new JFXDecorator(stage, root);
decorator.setCustomMaximize(true);
stage.setTitle("Weather API");
stage.setScene(new Scene(decorator));
String cssURI = getClass().getResource("stylesheet/style.css").toExternalForm();
decorator.getStylesheets().add(cssURI);
stage.show();
}
And this is the effect, look at the split-pane.
Without JFXDecorator works normally with code like below.
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("ApplicationView.fxml"));
Parent root = loader.load();
stage.setTitle("Weather API");
stage.setScene(new Scene(root));
String cssURI = getClass().getResource("stylesheet/style.css").toExternalForm();
stage.show();
}
I tried to set AncorPane properties of main pane similar to childs so maybe it will resising but it failed. My FXML looks like that
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="640.0" stylesheets="#stylesheet/style.css" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.161">
<children>
<SplitPane dividerPositions="0.29797979797979796" layoutX="220.0" layoutY="129.0" prefHeight="480.0" prefWidth="640.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
How can I fix it? Thank You.
Get rid of the AnchorPane and make the SplitPane the root node.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>
<SplitPane dividerPositions="0.29797979797979796" prefHeight="480.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
</items>
</SplitPane>

Make Button inside TextField in FXML

I made a TextField in FXML. I want to add Button in this TextField like clear button. How can I implement this?
You could use an AnchorPane to wrap the TextField and the Button and set the anchors to have the TextField to fill the entire AnchorPane and the Button to be anchored to the right-side.
Example:
<AnchorPane prefHeight="24.0" prefWidth="322.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TextField prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Button graphicTextGap="0.0" minHeight="10.0" minWidth="13.0" mnemonicParsing="false" prefHeight="20.0" prefWidth="22.0" style="-fx-background-color: #7085FF;
-fx-background-radius: 30;
-fx-background-insets: 0;" text="x" textFill="WHITE" AnchorPane.bottomAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0">
<font>
<Font size="9.0" />
</font>
</Button>
</children>
</AnchorPane>
The output is like:
If you need it more than once (and most probably you will), it is a good idea to have it separately in another FXML file with the corresponding controller class that also handles the action of the Button.
Example with separated FXML:
ButtonedTextField.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.*?>
<?import javafx.scene.text.Font?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.ButtonedTextField">
<children>
<TextField fx:id="textField" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Button fx:id="button" graphicTextGap="0.0" minHeight="10.0" minWidth="13.0" mnemonicParsing="false" prefHeight="20.0" prefWidth="22.0" style="-fx-background-color: #7085FF;
-fx-background-radius: 30;
-fx-background-insets: 0;" text="x" textFill="WHITE" AnchorPane.bottomAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0">
<font>
<Font size="9.0" />
</font>
</Button>
</children>
</AnchorPane>
ButtonedTextField.java (controller)
public class ButtonedTextField implements Initializable {
public #FXML TextField textField;
private #FXML Button button;
#Override
public void initialize(URL location, ResourceBundle resources) {
button.setOnAction(e -> textField.setText(""));
}
}
And then you can include this control to another FXML:
ButtonedTextFieldTest.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.*?>
<TabPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.ButtonedTextFieldTest">
<tabs>
<Tab text="Untitled Tab">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<fx:include fx:id="buttonedTextField" source="ButtonedTextField.fxml" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="2.0" />
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
ButtonedTextFieldTest.java (controller of including FXML)
public class ButtonedTextFieldTest implements Initializable {
private #FXML AnchorPane buttonedTextField;
private #FXML ButtonedTextField buttonedTextFieldController;
#Override
public void initialize(URL location, ResourceBundle resources) {
buttonedTextFieldController.textField.textProperty().addListener((ov, oldVal, newVal) -> {
System.out.println(newVal);
});
}
}
Notes:
You can customize the Button as you wish (maybe it is the easier to set the graphic)
The placement and the styling can be further customized.
As you can see in the last class, the control itself and its controller can be also injected! The convention is to have the controller injected is to use the "Controller" postfix after the ID of the inected control.
I have used the CustomTextField class from the ControlsFX project for this kind of functionality before. ControlsFX lacks good documentation, but the CustomTextField class is quite easy to use:
CustomTextField textfield = new CustomTextField
textfield.setRight(new Button());

JavaFX - How can i add a container in an anchor pane

I have a simple project that has a fxml with a splitter.
So the fxml is this:
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="accordionproject.FXMLDocumentController">
<children>
<SplitPane fx:id="splitPane" dividerPositions="0.29797979797979796" focusTraversable="true" layoutX="60.0" layoutY="14.0" prefHeight="200.0" prefWidth="320.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns:fx="http://javafx.com/fxml">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
What i would want is to insert a vbox in the left anchor pane from the splitter using only java code.
Can this be done?
I am new to fxml so any help would be apreciated.
Thank you in advance.
Add an fx:id to the AnchorPane you want to manipulate:
<AnchorPane fx:id="leftAnchorPane" minHeight="0.0" minWidth="0.0"
prefHeight="160.0" prefWidth="100.0" />
Get it in your controller as a #FXML member field:
public class FXMLDocumentController
{
#FXML private AnchorPane leftAnchorPane;
...
}
And manipulate it in the desired place (initialize() shown here, can be -almost- anywhere else):
public void initialize() {
VBox vbox = new VBox();
...
AnchorPane.setTopAnchor(vbox, 10.0); // obviously provide your own constraints
leftAnchorPane.getChildren().add(vbox);
}

Categories

Resources