How to create a scrollpane on fxml using controller - javafx

I would like to create a scrollpane and button from the controller and display it in fxml, is that possible? This my code but it doesn't work
controller
package application;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
public class controller {
ScrollPane scrollPane = new ScrollPane();
Button button = new Button("My Button");
public void initialize() {
button.setPrefSize(400, 300);
scrollPane.setContent(button);
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
}
}
main
package application;
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 primaryStage) throws Exception {
final Parent parent = FXMLLoader.load(getClass().getResource("ui.fxml"));
primaryStage.setTitle("ScrollPane Demo ");
primaryStage.setScene(new Scene(parent,600, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);}
}
fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<VBox id="vbox" prefHeight="400" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.controller">
<children>
<Pane prefHeight="200.0" prefWidth="200.0" />
</children>
</VBox>

You need to include your vbox in your controller, like this:
#FXML
private VBox vbox;
After that, add your scrollpane to your vbox's children:
vbox.getChildren().add(scrollPane);
Note that, you not added your button to your scrollpane's content, so your scrollpane is currently empty!
Edit: why you want to add nodes via fxml and from code too? Use this solution if it is really necessary, anyway use fxml to build your UI.

Related

JavaFX Fxml Display Image

I have been endeavouring to implement a JavaFX application which includes the display of an image using fxml.
However, it is unclear to me how to successfully create the image url.
I have tried using the ampersand annotation to create a relative path and also tried an absolute path but all are rejected by the IDE.
Consequently I have created a simplified application as follows:
Main.java
package sample;
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 primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Display an Image");
primaryStage.setScene(new Scene(root, 300, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
sample.fxml
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<FlowPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<ImageView fx:id="ivWoodland">
<image>
<Image fx:id="imgWoodland" url="file:///D:/TF/ImageDemo/woodland.jpg"/>
</image>
</ImageView
If anybody can inform me how to format the url it will be much appreciacted.
Thanks.

JavaFX Animation(TranslateTransition) Not running but scene is being displayed without error messages

I'm worked with java for a year and am pretty new to javaFX and have been have been following a basic tutorial so far using scenebuilder. I've tried to apply a translatetransition to my button so far but it doesn't seem to move at all. When I run the program the scene with its background is displayed, but the button just stays in its defined start position in scenebuilder and won't move. After checking other similar questions on this site I've made sure that I implemented Initializable and adding #Override before my initialize function, and I've made sure my transition is played. I've tried the translatetransition on a rectangle too and it won't move. Might just be that I'm using eclipse and not netbeans
Driver Class:
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
//import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent myroot = FXMLLoader.load(getClass().getClassLoader().getResource("MyFxml.fxml"));
//BorderPane root = new BorderPane();
Scene scene = new Scene(myroot);
//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);
}
}
FXML
<?import javafx.scene.shape.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<StackPane 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">
<children>
<ImageView fitHeight="413.0" fitWidth="638.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../../../Downloads/campusmap.png" />
</image>
</ImageView>
<AnchorPane prefHeight="200.0" prefWidth="200.0">
<children>
<Rectangle fx:id="myrectangle" arcHeight="5.0" arcWidth="5.0" fill="#128cff" height="200.0" layoutX="14.0" layoutY="64.0" stroke="BLACK" strokeType="INSIDE" width="200.0" />
<Button fx:id="startbutton" layoutX="202.0" layoutY="232.0" mnemonicParsing="false" prefHeight="64.0" prefWidth="197.0" style="-fx-background-color: #FFC0CB; -fx-background-radius: 100;" text="Start Program">
<font>
<Font name="Comic Sans MS" size="12.0" />
</font></Button>
</children>
</AnchorPane>
</children>
</StackPane>
FXML Controller
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
import javafx.animation.TranslateTransition;
public class MyFxmlController implements Initializable{
#FXML
private Button startbutton;
#FXML
private Rectangle myrectangle;
#Override
public void initialize(URL url, ResourceBundle rb) {
TranslateTransition transition = new TranslateTransition();
transition.setDuration(Duration.seconds(4));
transition.setNode(startbutton);
transition.setToX(-200);
transition.setToY(-200);
transition.play();
}
}
You are not "linking" your controller to the FXML document. So when you display the FXML layout, the Transition code is never executed.
You have a couple of options to do this. In SceneBuilder, you can specify the controller class here:
This will add the fx:controller attribute to your FXML file:
fx:controller="temp.translate.MyFxmlController"
Obviously, you'll need to use your own package paths here.
The other option is to specify the controller in your Java code by updating your loading of the FXML document.
In order to do so, you'll need to get a reference to the FXMLLoader and set the controller there. You can change your start() method like this:
#Override
public void start(Stage primaryStage) {
try {
// Create a new FXMLLoader and set the FXML path
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFxml.fxml"));
// Set the controller for this FXML document
loader.setController(new MyFxmlController());
// Load the FXML into your Parent node
Parent myRoot = loader.load();
//BorderPane root = new BorderPane();
Scene scene = new Scene(myRoot);
//scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
Note: If you've specified the controller in your FXML via fx:controller, you cannot also specify it in your Java code, and vice versa. You may only define the controller in one place or the other, so it's really personal preference and depends on your needs.

Setting menu items css font style has no visible effect

I would like to change the MenuItem's text to bold when the user clicks on it. To manage to do this I'm using setStyle, but unfortunately it has no visible effect. The css makes no effect when the user selects the MenuItem option. The css styling only has an effect in initialize method.
I created a minimal reproducible example for the problem:
MAIN:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public final class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("MainView.fxml"));
Scene scene = new Scene(root, 850.0, 650.0);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MAIN FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="475.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="MainController">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu fx:id="menu" mnemonicParsing="false" text="Switch Chart">
<items>
<MenuItem text="MenuItem1" />
<MenuItem onAction="#setFontBold" text="MenuItem2" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
MAIN CONTROLLER:
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
public class MainController implements Initializable {
#FXML private Menu menu;
private List<MenuItem> menuItems;
#Override
public void initialize(URL location, ResourceBundle resources) {
menuItems = menu.getItems();
menuItems.get(0).setStyle("-fx-font-weight: bold");
}
public void setFontBold() {
menuItems.get(1).setStyle("-fx-font-weight: bold");
System.out.println(menuItems.get(1).getStyle());
System.out.println("Font set to bold in menuitem with index 1 has no effect...");
}
}
So I get the following css effects, even after selecting the first indexed menu item (so onAction=#setFontBold not changes anything visually).
No bold effect. - only if you set the style in initialize()
I'm curious about why it makes no difference? It definitely sets the style to bold, but it is displayed as a regular font even after changing it to bold.
EDIT: JavaFX version: 8.0.211-b10
If I would have to stick to javafx 8 and switching was the requirement, I would have used RadioMenuItem. It does the job as expected, but does not make MenuItem text bold.
From official docs, I found following excerpt that would be useful.
ToggleGroup toggleGroup = new ToggleGroup();
RadioMenuItem radioItem1 = new RadioMenuItem("Option 1");
radioItem.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
System.out.println("radio toggled");
}
});
radioItem1.setToggleGroup(toggleGroup);
RadioMenuItem radioItem2 = new RadioMenuItem("Option 2");
radioItem.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
System.out.println("radio toggled");
}
});
radioItem2.setToggleGroup(toggleGroup);

Javafx scrollbars position

I have a TextArea inside of a ScrollPane. I have set the TextArea nodeOrientation="RIGHT_TO_LEFT". When I do this the scrollbars go on the left side of the window instead of the right side, which I assume is default. How do I force the scrollbars to the right side of the window?
I have tried setting the nodeOrientation of my AnchorPane and ScrollPane to left to right but that did not help
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.mycompany.mycalc.MyCalcHistoryController">
<children>
<ScrollPane fx:id="scrollPane" fitToHeight="true" fitToWidth="true" prefHeight="242.0" prefWidth="400.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<TextArea fx:id="txtHistory" editable="false" nodeOrientation="RIGHT_TO_LEFT" />
</content>
</ScrollPane>
</children>
</AnchorPane>
I used BorderPane instead of AnchorPane and did not use a fxml file. Here is my code and after the code is a screen capture. As you can see, setting the node orientation for the TextArea only does not alter the location of the scroll bar on the ScrollPane.
import javafx.application.Application;
import javafx.geometry.NodeOrientation;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class FxTest00 extends Application {
#Override
public void start(Stage stage) throws Exception {
TextArea txtAr = new TextArea("myxomatosis");
txtAr.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
ScrollPane scrollPane = new ScrollPane(txtAr);
scrollPane.setVbarPolicy(ScrollBarPolicy.ALWAYS);
BorderPane root = new BorderPane();
root.setCenter(scrollPane);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
EDIT (after Ray_White's initial comment to my answer)
The scrollbar you are referring to (in your comment) is part of TextArea and not related to the ScrollPane parent. In the below code, the TextArea is added directly to the BorderPane, i.e. the below code contains no ScrollPane.
The way I found to remove the TextArea vertical scrollbar is via the TextArea style. I created a CSS file named scrolbar.css. Here is its contents:
.text-area .scroll-pane {
-fx-vbar-policy: never;
}
And here is the modified code, including your suggestion to add text to the TextArea to force scrolling.
import javafx.application.Application;
import javafx.geometry.NodeOrientation;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class FxTest00 extends Application {
#Override
public void start(Stage stage) throws Exception {
TextArea txtAr = new TextArea("myxomatosis");
txtAr.appendText("\n");
txtAr.appendText("One");
txtAr.appendText("\n");
txtAr.appendText("Two");
txtAr.appendText("\n");
txtAr.appendText("Three");
txtAr.appendText("\n");
txtAr.appendText("Four");
txtAr.appendText("\n");
txtAr.appendText("Five");
txtAr.appendText("\n");
txtAr.appendText("Six");
txtAr.appendText("\n");
txtAr.appendText("Seven");
txtAr.appendText("\n");
txtAr.appendText("Eight");
txtAr.appendText("\n");
txtAr.appendText("Nine");
txtAr.appendText("\n");
txtAr.appendText("Ten");
txtAr.appendText("\n");
txtAr.appendText("Eleven");
txtAr.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
BorderPane root = new BorderPane();
root.setCenter(txtAr);
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("scrolbar.css").toString());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
And here is the screen capture of the modified GUI. As you can see, no scrollbar.

JavafX - Dynamic ImageView Set Default Size

I have an ImageView which I have configured so that it is resized to fit its parent AnchorPane with the two following lines of code (both the AnchorPane and the image are square).
preview.fitWidthProperty().bind(previewPane.maxWidthProperty());
preview.fitHeightProperty().bind(previewPane.maxWidthProperty());
I have also set a fitWidth of 450 px in an fxml file that injects all nodes. When I create an instance of this object however it opens the preview with a width equal to that of the loaded image (2000 px) and not 450 px. The resizing functionality works as expected and it is possible to shrink it down to 450 px. I was wondering however if it is possible to make sure it opens up with a default size different from that of the width of the image but also making sure so that it grows and shrinks with its parent.
I have tried setting loads of different default widths in both java code and fxml but the only thing that seems to work is unbinding the fitWidth which I don't want.
Do you have any suggestions as to how I might solve this?
Main:
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class MainTest extends Application {
#FXML private AnchorPane previewPane;
#FXML private ImageView preview;
#Override
public void start(Stage primaryStage) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Test.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setClassLoader(getClass().getClassLoader());
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
preview.fitWidthProperty().bind(previewPane.maxWidthProperty());
preview.fitHeightProperty().bind(previewPane.maxWidthProperty());
Scene scene = new Scene(previewPane);
primaryStage.setTitle("Test");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="previewPane" prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ImageView fx:id="preview" fitHeight="450.0" fitWidth="450.0" layoutX="55.0" layoutY="36.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<image>
<Image url="#Blue%20Eyes%20White%20Dragon.png" />
</image>
</ImageView>
</children>
</AnchorPane>
EDIT: Here is a MCVE of my problem.
The structure of your project is wrong. Also, to fix the problem you are having, you need to set the Scene size.
Code to get the ImageView from the Controller
//Code in the Main
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = loader.load();
FXMLDocumentController fXMLDocumentController = loader.getController();
ImageView preView = fXMLDocumentController.getPreview();
//Code in the Controller
public ImageView getPreview()
{
return preview;
}
Code to set the Scene's size
stage.setWidth(450);
stage.setHeight(450);
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication213 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();
ImageView preView = fXMLDocumentController.getPreview();
Scene scene = new Scene(root);
stage.setWidth(450);
stage.setHeight(450);
stage.setScene(scene);
stage.show();
preView.fitHeightProperty().bind(stage.heightProperty());
preView.fitWidthProperty().bind(stage.widthProperty());
}
/**
* #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.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.ImageView;
/**
*
* #author blj0011
*/
public class FXMLDocumentController implements Initializable
{
#FXML
private ImageView preview;
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO
}
public ImageView getPreview()
{
return preview;
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="previewPane" prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication213.FXMLDocumentController">
<children>
<ImageView fx:id="preview" fitHeight="450.0" fitWidth="450.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<image>
<Image url="#Blue%20Eyes%20White%20Dragon.png" />
</image>
</ImageView>
</children>
</AnchorPane>
Finally, you need to uncheck Preserve Ratio. The FXML should already have this unchecked. I am pointing this out because it's important.

Resources