JavaFX does not seem to have support for scroll views. So, you have to
implement it on your own. Here is how I started implementing my own scroll view supporting
vertical scrolling:
package scrollviewdemo; import javafx.scene.CustomNode; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.control.ScrollBar; import javafx.util.Math; import javafx.scene.shape.Rectangle; import javafx.scene.paint.Paint; public class ScrollView extends CustomNode { public-init var node: Node; public var width: Float; public var height: Float; var group: Group; var gap = bind group.layoutBounds.height - height; def scrollBar: ScrollBar = ScrollBar { translateX: bind width - scrollBar.width min: 0 max: bind Math.max(0, gap) visible: bind gap > 0 vertical: true height: bind height } override function create() { Group { content: [ Group { content: [ group = Group { translateY: bind - scrollBar.value content: [node] } ] clip: Rectangle { width: bind width - {if (gap > 0) scrollBar.width else 0} height: bind height } }, scrollBar ] } } }
This is how it can be used in a simple application:
var stage: Stage = Stage { title: "Application title" width: 200 height: 200 scene: Scene { content: [ ScrollView { width: bind stage.scene.width height: bind stage.scene.height node: VBox { content: for (i in [0..20]) ImageView { image: Image { // some picture url: "{__DIR__}pic.png" } } } } ] } }
To support mouse scroll wheel I added the following to the ScrollView class:
override var onMouseWheelMoved = function(event) { // multiplying by 4 makes the scrolling faster and still smooth scrollBar.value += event.wheelRotation * 4; }
However, as it turned out, transparent components don’t receive mouse events, so the mouse
wheel worked only when the mouse pointer was on top of a non-transparent object. So, to work
around this, I had to fill the scroll view background using an opaque rectangle. The resulting
ScrollView component looks like this:
package scrollviewdemo; import javafx.scene.CustomNode; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.control.ScrollBar; import javafx.util.Math; import javafx.scene.shape.Rectangle; import javafx.scene.paint.Paint; public class ScrollView extends CustomNode { public-init var node: Node; public var width: Float; public var height: Float; public var fill: Paint; var group: Group; var gap = bind group.layoutBounds.height - height; def scrollBar: ScrollBar = ScrollBar { translateX: bind width - scrollBar.width min: 0 max: bind Math.max(0, gap) visible: bind gap > 0 vertical: true height: bind height } override function create() { Group { content: [ Rectangle { fill: bind fill width: bind width - {if (gap > 0) scrollBar.width else 0} height: bind height }, Group { content: [ group = Group { translateY: bind - scrollBar.value content: [node] } ] clip: Rectangle { width: bind width - {if (gap > 0) scrollBar.width else 0} height: bind height } }, scrollBar ] } } override var onMouseWheelMoved = function(event) { // multiplying by 4 makes the scrolling faster and still smooth scrollBar.value += event.wheelRotation * 4; } }
And the following line should be added to the Main.fx to make it work:
package scrollviewdemo; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.layout.VBox; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.paint.Color; var stage: Stage = Stage { title: "Application title" width: 200 height: 200 scene: Scene { content: [ ScrollView { width: bind stage.scene.width height: bind stage.scene.height fill: Color.WHITE node: VBox { content: for (i in [0..20]) ImageView { image: Image { // some picture url: "{__DIR__}pic.png" } } } } ] } }