How to achieve soft round effect on border in JavaFX - css

I have a generic border of a node and i want to make the border look like this image (both CSS and code way) in JavaFX:
Can anybody help me?
Thanks in advance

You should use box-shadow to add a soft round effect with border and border-radius.
border: 1px solid #888888;
box-shadow: 1px 1px 2px #888888;
border-radius: 25px;

The main Class for stage
public class SpiderMan extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"SpiderMan.fxml"
)
);
loader.setController(new clipRound());
Pane batman = loader.load();
stage.setTitle("Where's Spider man Round image?");
stage.setScene(new Scene(batman));
stage.show();
}
}
The Round Image Class View
class clipRound {
#FXML
private ImageView imageView;
#FXML
public void initialize() {
// set a clip to apply rounded border to the original image.
Rectangle clip = new Rectangle(
imageView.getFitWidth(), imageView.getFitHeight()
);
clip.setArcWidth(20); the radius Arch
clip.setArcHeight(20); the radius Arch
imageView.setClip(clip);
// snapshot the rounded image.
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
WritableImage image = imageView.snapshot(parameters, null);
// remove the rounding clip so that our effect can show through.
imageView.setClip(null);
// apply a shadow effect.
imageView.setEffect(new DropShadow(20, Color.BLACK));
// store the rounded image in the imageView.
imageView.setImage(image);
}
}
The round Image FXML view "SpiderMan.fxml"
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="313.0" prefWidth="477.0" style="-fx-background-color: azure;" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<children>
<ImageView fx:id="imageView" layoutX="29.0" layoutY="44.0" fitHeight="224.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="http://collider.com/wp-content/uploads/lego-batman-movie-dc-super-heroes-unite-1.jpg" />
</image>
</ImageView>
</children>
</AnchorPane>
Snapshot :
snapshot programme is running

Related

JavaFX Slider with 2 different colors , for example green for selected area and red for unselected area

What i want to achieve is the have a JavaFX Slider like the below :
I want the selected are to be green and the unselected area to be red :
Can this be done with let's say simple css because JavaFX is awesome i am sure it can but now how :_)
What i was doing till ....
Until now i was just adding a StackPane and behind that a ProgressBar , synchronized with the value of the Slider , what i mean? :)
, but hey now i need two colors and i have to create two ProgressBars in a StackPane with different colors (RED and Green) .... to much code ...
1 slider and 2 progress bars , I will post below the .fxml code , .java code and the needed .css for look and feel :)
Any question feel free to answer :)
As for the code , this is created for XR3Player (Open Source Github Project)
.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.String?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<fx:root prefHeight="389.0" prefWidth="228.0" style="-fx-background-color: #202020;" stylesheets="#../../style/application.css" type="StackPane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9.0.1">
<children>
<BorderPane fx:id="borderPane" minHeight="0.0" minWidth="0.0">
<bottom>
<StackPane minHeight="0.0" minWidth="0.0" BorderPane.alignment="CENTER">
<children>
<HBox alignment="CENTER" maxHeight="-Infinity" minHeight="0.0" minWidth="0.0" prefHeight="15.0">
<children>
<ProgressBar fx:id="volumeProgress1" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" mouseTransparent="true" prefHeight="15.0" progress="1.0" HBox.hgrow="ALWAYS">
<styleClass>
<String fx:value="transparent-progress-bar" />
<String fx:value="transparent-volume-progress-bar2-nostrip" />
</styleClass>
</ProgressBar>
<ProgressBar fx:id="volumeProgress2" layoutX="10.0" layoutY="10.0" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" mouseTransparent="true" prefHeight="15.0" progress="1.0" HBox.hgrow="ALWAYS">
<styleClass>
<String fx:value="transparent-progress-bar" />
<String fx:value="transparent-volume-progress-bar3-nostrip" />
</styleClass>
</ProgressBar>
</children>
</HBox>
<Slider fx:id="masterVolumeSlider" majorTickUnit="15.0" max="150.0" maxWidth="1.7976931348623157E308" minorTickCount="55" value="75.0">
<styleClass>
<String fx:value="transparency-slider" />
<String fx:value="timer-slider" />
</styleClass>
</Slider>
</children>
<BorderPane.margin>
<Insets left="5.0" right="5.0" />
</BorderPane.margin>
</StackPane>
</bottom>
</BorderPane>
</children>
</fx:root>
.java
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.Slider;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import main.java.com.goxr3plus.xr3player.application.tools.InfoTool;
public class MixTabInterface extends StackPane {
//--------------------------------------------------------------
#FXML
private BorderPane borderPane;
#FXML
private ProgressBar volumeProgress1;
#FXML
private ProgressBar volumeProgress2;
#FXML
private Slider masterVolumeSlider;
// -------------------------------------------------------------
/**
* Constructor.
*/
public MixTabInterface() {
// ------------------------------------FXMLLOADER ----------------------------------------
FXMLLoader loader = new FXMLLoader(getClass().getResource(InfoTool.PLAYERS_FXMLS + "MixTabInterface.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* Called as soon as fxml is initialized
*/
#FXML
private void initialize() {
//masterVolumeSlider
masterVolumeSlider.boundsInLocalProperty().addListener((observable , oldValue , newValue) -> calculateBars());
masterVolumeSlider.valueProperty().addListener((observable , oldValue , newValue) -> {
calculateBars();
});
}
/**
* Calculate bars positioning
*/
private void calculateBars() {
//Variables
double value = masterVolumeSlider.getValue();
double half = masterVolumeSlider.getMax() / 2;
double masterVolumeSliderWidth = masterVolumeSlider.getWidth();
//Progress Max1
volumeProgress1.setProgress(1);
volumeProgress2.setProgress(1);
//Below is mind tricks
if ((int) value == (int) half) {
volumeProgress1.setMinWidth(masterVolumeSliderWidth / 2);
volumeProgress2.setMinWidth(masterVolumeSliderWidth / 2);
} else if (value < half) {
double progress = 1.0 - ( value / half );
double minimumWidth = masterVolumeSlider.getWidth() / 2 + ( masterVolumeSlider.getWidth() / 2 ) * ( progress );
volumeProgress1.setMinWidth(masterVolumeSliderWidth - minimumWidth);
volumeProgress1.setMaxWidth(masterVolumeSliderWidth - minimumWidth);
volumeProgress2.setMinWidth(minimumWidth);
} else if (value > half) {
double progress = ( value - half ) / half;
double minimumWidth = masterVolumeSlider.getWidth() / 2 + ( masterVolumeSlider.getWidth() / 2 ) * ( progress );
volumeProgress1.setMinWidth(minimumWidth);
volumeProgress2.setMinWidth(masterVolumeSliderWidth - minimumWidth);
volumeProgress2.setMaxWidth(masterVolumeSliderWidth - minimumWidth);
}
}
/**
* #return the borderPane
*/
public BorderPane getBorderPane() {
return borderPane;
}
/**
* #return the masterVolumeSlider
*/
public Slider getMasterVolumeSlider() {
return masterVolumeSlider;
}
}
.css
.transparent-volume-progress-bar2-nostrip > .bar,.transparent-volume-progress-bar2-nostrip:indeterminate .bar,.transparent-volume-progress-bar2-nostrip:determinate .track,.transparent-volume-progress-bar2-nostrip:indeterminate .track{
-fx-accent:rgb(0.0, 144.0, 255.0);
-fx-background-color: -fx-accent;
-fx-background-radius:0.0;
-fx-border-radius:0.0;
}
.transparent-volume-progress-bar3-nostrip > .bar,.transparent-volume-progress-bar3-nostrip:indeterminate .bar,.transparent-volume-progress-bar3-nostrip:determinate .track,.transparent-volume-progress-bar3-nostrip:indeterminate .track{
-fx-accent:#fc4f4f;
-fx-background-color: -fx-accent;
-fx-background-radius:0.0;
-fx-border-radius:0.0;
}
.progress-bar > .bar {
-fx-accent:firebrick;
/*-fx-background-color:firebrick;*/
-fx-background-color: linear-gradient(
from 0.0px 0.75em to 0.75em 0.0px,
repeat,
-fx-accent 0.0%,
-fx-accent 49.0%,
derive(-fx-accent, 30.0%) 50.0%,
derive(-fx-accent, 30.0%) 99.0%
);
-fx-background-insets: 3.0;
-fx-padding: 0.2em;
}
.transparent-progress-bar:determinate .track,.transparent-progress-bar:indeterminate .track{
-fx-background-color:rgb(0.0,0.0,0.0,0.5);
}
/* .transparent-progress-bar */
.transparent-progress-bar > .bar,.transparent-progress-bar:indeterminate .bar{
-fx-accent:firebrick;
}

java fx add element an ScroolPane

I 've searched and have not found an answer.
I have a scroll , a button and a textarea. when i press the button, i take the value in the textarea, then I want the text to be put at the top right in scrool , if ipress one more time to go under and so on. example
hello guys
this is my label
text area button
this is my fxml file
<AnchorPane id="AnchorPane" prefHeight="392.0" prefWidth="357.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="indixischat.ChatController">
<children>
<Pane id="title" layoutX="14.0" layoutY="14.0" prefHeight="60.0" prefWidth="333.0" />
<TextField fx:id="text" layoutX="14.0" layoutY="362.0" prefHeight="17.0" prefWidth="299.0" />
<Button fx:id="sendMessage" onAction="#sendMessage" layoutX="318.0" layoutY="365.0" mnemonicParsing="false" prefHeight="11.0" prefWidth="29.0" text="Button" />
<ScrollPane fx:id="scroll" layoutX="14.0" layoutY="44.0" prefHeight="319.0" prefWidth="339.0">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="412.0" prefWidth="326.0" />
</content>
</ScrollPane>
You can use a VBox as a container for the texts in the ScrollPane. Then on each Button click you create a new TextField and add that to the VBox:
public class Test extends Application {
#Override
public void start(Stage primaryStage) {
TextField txtInput = new TextField();
VBox boxTextFields = new VBox();
boxTextFields.setAlignment(Pos.TOP_RIGHT);
boxTextFields.setFillWidth(false);
ScrollPane scrollPane = new ScrollPane(boxTextFields);
scrollPane.setFitToWidth(true);
Button button = new Button();
button.setOnAction(e -> boxTextFields.getChildren().add(new TextField(txtInput.getText())));
VBox root = new VBox(textField, button, scrollPane);
root.setAlignment(Pos.TOP_CENTER);
primaryStage.setScene(new Scene(root, 300, 300));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

javaFX cannot access Scene elements

I am new to javafX, have run through various tutorials, and googled extensively. I am attempting to write a multiscreen javaFX program whose second screen has a split pane, whose right pane should display a grid and a button. The framework I am using for multiple screens is copied form Angela Caiedo's MultipleScreens Framework tutorial ( https://github.com/acaicedo/JFX-MultiScreen/tree/master/ScreensFramework) .
What works: The screens framework is successful in terms of flipping between my multiple screens.
My problem: I click the button on screen 1 to move to screen 2. Screen 2 successfully shows. On screen 2 I click a button to populate data in my vBox. The code in my controller class for screen 2 is unable to access the vbox (or any other defined containers on this screen).
My main class sets up the controller screens.
public class FieldMapCreator extends Application {
public static String mainID = "main";
public static String mainFile = "MainMapFXMLDocument.fxml";
public static String initialMapID = "initialMap";
public static String initialMapFile = "FXMLMapPicture.fxml";
#Override
public void start(Stage stage) throws Exception {
ScreensController mainContainer = new ScreensController();
mainContainer.loadScreen(FieldMapCreator.mainID, FieldMapCreator.mainFile);
mainContainer.loadScreen(FieldMapCreator.initialMapID, FieldMapCreator.initialMapFile);
mainContainer.setScreen(FieldMapCreator.mainID);
Group root = new Group();
root.getChildren().addAll(mainContainer);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
I get to the second screen by clicking a button on screen 1. Button1 code looks like:
#FXML
private void initialMapButtonAction(ActionEvent event) {
myController.setScreen(FieldMapCreator.initialMapID);
}
Screen 2 has a button that when clicked executes a method that creates data for the vbox. The fxml for screen 2 is this:
<AnchorPane id="AnchorPane" fx:id="mainAnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="FieldMapCreator.FXMLMapPictureController">
<children>
<SplitPane fx:id="mapSplitPane" dividerPositions="0.29797979797979796" layoutX="3.0" layoutY="7.0" prefHeight="400.0" prefWidth="600.0">
<items>
<AnchorPane fx:id="anchorPaneLeft" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<Button fx:id="backButton" layoutX="14.0" layoutY="348.0" mnemonicParsing="false" onAction="#goToMainScreen" text="Back" />
</children>
</AnchorPane>
<AnchorPane fx:id="anchorPaneRight" minHeight="0.0" minWidth="0.0" prefHeight="364.0" prefWidth="401.0">
<children>
<Button fx:id="vBoxShowMap" layoutX="24.0" layoutY="346.0" mnemonicParsing="false" onAction="#buildMapFromNurseries" prefHeight="26.0" prefWidth="91.0" text="show map" />
<VBox fx:id="mapVBox" layoutX="24.0" layoutY="24.0" onMouseClicked="#vBoxMouseClicked" prefHeight="200.0" prefWidth="309.0" />
</children></AnchorPane>
</items>
</SplitPane>
</children>
</AnchorPane>
The code that fails is in the "showInitialMap()" method of the controller class for screen 2. When executed, the last line of this method "mapVBox.getChildren().add(root)", results in a null pointer exception. I expected this to be resolved via the fxml injection. I also tried the commented out code to retrieve "mapVBox" using scene lookup, but it also results in a null pointer exception. The controller code is below:
public class FXMLMapPictureController implements Initializable, ControlledScreen {
ScreensController myController;
static MyNode[][] mainField ;
#FXML
private AnchorPane mainAnchorPane;
#FXML
private static SplitPane mapSplitPane;
#FXML
private AnchorPane anchorPaneLeft;
#FXML
private static AnchorPane anchorPaneRight;
#FXML
private static VBox mapVBox;
#FXML
private Button vBoxShowMap;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// Should something be in here ??
}
public void goToMainScreen() {
myController.setScreen(FieldMapCreator.mainID);
}
public void showInitialMap() {
int row = userFieldMap.getNumRows();
int col = userFieldMap.getNumCols();
double gridWidth = 309/col;
double gridHeight = 200/row;
Group root = new Group();
// initialize the field
for (int idx = 0; idx < col; idx++) {
for (int jdx = 0; jdx < row; jdx++) {
// create plot
Plot plot = new Plot(idx, jdx, "Plot" + idx + "/" + jdx);
// Create node to hold the Plot
MyNode node = new MyNode(idx*gridWidth, jdx*gridHeight, gridWidth, gridHeight, plot);
// add plot to group
root.getChildren().add(node);
}
}
//Scene myScene = myController.getScene();
//VBox mapVBox = (VBox)myScene.lookup("#mapVBox");
mapVBox.getChildren().add(root);
}
#Override
public void setScreenParent(ScreensController screenParent) {
myController = screenParent;
}
Is there something missing from the initialize() method? I'm wondering if I am not setting something correctly when I change screens. I am able to access the initial screen's containers without problem from all screen 1 methods including the initialize class. When I attempt the same in screen 2, I get the message "screen hasn't been loaded !!!"
Thanks for any help you can provide.
You are using static fields as FXML injection targets which don't work in Java 8 and should not have been implemented to work in any other version, as static UI elements just don't make sense. Here's a bit more detailed answer. Having resorted to a static field most of the time means the software design of the application needs to be reconsidered.

Failed to load skin : null when applying css to fxml in Scene builder

I am trying to create a knob control for JavaFX with this example as starting point: http://fxexperience.com/2012/01/fun-javafx-2-0-audio-player/
In that example they are applying a skin (KnobSkin.java) to a slider in the css file.
I have created a custom control like this:
Knob.fxml
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<children>
<AnchorPane id="myTestButton" layoutX="0.0" layoutY="5.0" minHeight="49.0" prefHeight="140.0" prefWidth="14.0">
<children>
<Slider id="volume" orientation="VERTICAL" styleClass="knobStyle" />
</children>
</AnchorPane>
</children>
</fx:root>
Knob.java
package application;
public class Knob extends AnchorPane {
#FXML
private AnchorPane myTestButton;
public Knob() {
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("/application/Knob.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
My main scene looks like this:
test.fxml
<?import application.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?scenebuilder-classpath-element ../../bin?>
<AnchorPane prefHeight="217.0" prefWidth="221.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<Knob layoutX="5.0" layoutY="4.0" />
</AnchorPane>
When I try to open the test.fxml file in Scene Builder and apply this css to it:
.slider.knobStyle {
-fx-skin: "application.KnobSkin";
}
I get the following error:
Failed to load skin 'StringProperty [bean: Slider[id=volume, styleClass=slider knobStyle], name:skinClassName, value:application.KnobSkin]' for control Slider[id=volume, styleClass=slider knobStyle] :null
If I run the application the knob is displayed perfectly.
Any idea what I have done wrong?
Thanks!
After reading this blog post: http://www.guigarage.com/2012/11/custom-ui-controls-with-javafx-part-1/
I found that if I change my class Knob.java to
package application;
public class Knob extends AnchorPane {
#FXML
private AnchorPane myTestButton;
public Knob() {
setSkinClassName(KnobSkin.class.getName());
}
}
And I remove the Knob.fxml the knob will show up in Scene Builder when I select my stylesheet

ScrollPane containing ImageView does not update its scrollbars after calling setImage()

I am experimenting JavaFX with a simple image viewer. I want it to display an image and, if it does not fit in the window, display scrollbars. The image to dislay is loaded with the FileChooser and set to the ImageView using imageView.setImage(image).
The problem is that the scrollbars of the containing ScrollPane do not update after calling imageView.setImage(image). Instead, I need to perform an action that changes the scene (e.g. resize the window). It behaves the same when an image is displayed and another is loaded, i.e. the sizes of the scrollbars reflect the size of the previous image.
The bug is reproducible using the following cut-down version of the code:
(Java)
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class ImageViewerBug extends Application
{
#FXML private ImageView imageView;
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("ImageViewerBug.fxml"));
fxmlLoader.setController(this);
try {
BorderPane borderPane = (BorderPane) fxmlLoader.load();
Scene scene = new Scene(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
catch( IOException e ) {
throw new RuntimeException(e);
}
}
public void loadClicked() {
FileChooser fileChooser = new FileChooser();
File f = fileChooser.showOpenDialog(null);
if( f != null ) {
try( InputStream is = new FileInputStream(f) ) {
Image image = new Image(is);
imageView.setImage(image);
}
catch( IOException e ) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
launch(args);
}
}
(FXML)
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.Group?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<BorderPane id="BorderPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml">
<center>
<ScrollPane prefHeight="200.0" prefWidth="200.0">
<content>
<Group>
<ImageView fx:id="imageView" pickOnBounds="true" preserveRatio="true" />
</Group>
</content>
</ScrollPane>
</center>
<top>
<ToolBar>
<items>
<Button mnemonicParsing="false" onAction="#loadClicked" text="Load" />
</items>
</ToolBar>
</top>
</BorderPane>
I can confirm this bug. A quick and dirty workaround that fixed it for me:
public void loadClicked() {
FileChooser fileChooser = new FileChooser();
File f = fileChooser.showOpenDialog(null);
if( f != null ) {
try( InputStream is = new FileInputStream(f) ) {
Image image = new Image(is);
imageView.setImage(image);
imageView.snapshot(new SnapshotParameters(), new WritableImage(1, 1));
double rnd = new Random().nextInt(10);
imageView.setX(rnd/1000);
imageView.setY(rnd/1000);
}
catch( IOException e ) {
e.printStackTrace();
}
}
}
The snapshot() Method sometimes works like a charm whenever some UI-element isn't updated or displayed correctly. But don't ask me why that works, maybe it has something to do with the rendering process, because snapshots forces JavaFX to render the scene graph or the target elements. The random stuff is needed to create the right scrollbar sizes when adding a new image after one already part of the ImageView.
Maybe this has something to do with the strange behaviour i found some weeks earlier. The workaround also solved my problems back then.
(Really late)EDIT
The problem is caused by the Group which wraps the ImageView. If you use a node that inherits from Pane the behaviour of the ScrollPane should be as expected even without the workaround. A Group can still be used as the direct child of the ScrollPane as long as a Pane wraps the ImageView.
Example:
<ScrollPane prefHeight="200.0" prefWidth="200.0">
<content>
<Group id="Group">
<children>
<HBox id="HBox" alignment="CENTER" layoutX="0.0" layoutY="0.0" spacing="5.0">
<children>
<ImageView fx:id="imageView" pickOnBounds="true" preserveRatio="true" />
</children>
</HBox>
</children>
</Group>
</content>
</ScrollPane>
I have had the same problem with image...Instead of
Image image = new Image(is);
You should write:
Image image = new Image("file:" + ABSOLUTE_PATH_TO_FILE);
Image will refresh automatically, you don't have to do anything. For me, it works
use the command:
Scrollbar scrollbar
// ...
// Some activities with children that extends canvas, so scrollbar is needed.
// ...
scrollbar.layout();
this will update your scrollbar.
No Workaround needed.

Resources