package extras
- Alphabetic
- By Inheritance
- extras
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Package Members
- package image
- package mvcfx
Package
mvcfx
helps in implementation of Model-View-Controller-like patters, we call it MVCfx.Package
mvcfx
helps in implementation of Model-View-Controller-like patters, we call it MVCfx. The pattern is build around use of views defined in FXML (the view), with binding to ScalaFX using ScalaFXML library.There are two cooperating classes
ControllerFX
for binding FXML to Scala code andModelFX
that contains logic for the component. An additional helperMVCfx
class is provided to instantiate theControllerFX
and the correspondingModelFX
.The structure of the UI component is defined in a standard JavaFX FXML file. The Scala side of the FXML is in a class
ControllerFX
. Part of theControllerFX
is automatically generated by ScalaFXML macro, the rest can be customized as needed, including binding of the UI to appropriate parts of the component logic represented by theModelFX
. Use of theMVCfx
is optional and primarily intended to simplify instantiation of theControllerFX
and theModelFX
.Below is an example using the classes in
mvcfx
. The code implements a simple Stop Watch. The complete code is in demos part of the ScalaFX Extras project.Note the recommended naming convention used: * StopWatch extends MVCfx * StopWatchModel extends ModelFX * StopWatchController extends ControllerFX * StopWatch.fxml the FXVM declaration of the view
First we have the FXML definitions representing the structure of the user interface (
org/scalafx/extras/mvcfx/stopwatch/StopWatch.fxml
)<?import javafx.geometry.Insets?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.BorderPane?> <?import javafx.scene.layout.HBox?> <?import javafx.scene.text.*?> <BorderPane xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.scalafx.extras.mvcfx.stopwatch.StopWatchController"> <bottom> <ButtonBar BorderPane.alignment="CENTER"> <buttons> <Button fx:id="startButton" mnemonicParsing="false" text="Start"/> <Button fx:id="stopButton" mnemonicParsing="false" text="Stop"/> <Button fx:id="resetButton" mnemonicParsing="false" text="Reset"/> </buttons> </ButtonBar> </bottom> <center> <HBox> <children> <Label fx:id="minutesLabel" alignment="CENTER" contentDisplay="CENTER" text="99" textAlignment="CENTER" BorderPane.alignment="CENTER"> </Label> <Label text=":"> </Label> <Label fx:id="secondsLabel" alignment="CENTER" contentDisplay="CENTER" text="99" textAlignment="CENTER"> </Label> <Label text="."> </Label> <Label fx:id="fractionLabel" alignment="CENTER" contentDisplay="CENTER" text="99" textAlignment="CENTER"> </Label> </children> </HBox> </center> </BorderPane>
The
ControllerFX
creates connection of the FXML to Scala code and underlyingModelFX
for the application logic. Note the@sfxml
annotation and the constructor arguments corresponding to controls defined in FXML, likeminutesLabel
. The last argument to the constructor is theModelFX
. (org.scalafx.extras.mvcfx.stopwatch.StopWatchController
)package org.scalafx.extras.mvcfx.stopwatch import org.scalafx.extras.mvcfx.ControllerFX import scalafx.Includes._ import scalafx.scene.control.{Button, Label} import scalafxml.core.macros.sfxml @sfxml class StopWatchController(minutesLabel: Label, secondsLabel: Label, fractionLabel: Label, startButton: Button, stopButton: Button, resetButton: Button, model: StopWatchModel) extends ControllerFX { minutesLabel.text.value = format2d(model.minutes.longValue) model.minutes.onChange { (_, _, newValue) => minutesLabel.text.value = format2d(newValue.longValue) } secondsLabel.text.value = format2d(model.seconds.longValue()) model.seconds.onChange { (_, _, newValue) => secondsLabel.text.value = format2d(newValue.longValue()) } fractionLabel.text.value = format2d(model.secondFraction.longValue() / 10) model.secondFraction.onChange { (_, _, newValue) => fractionLabel.text.value = format2d(newValue.longValue() / 10) } startButton.disable <== model.running stopButton.disable <== !model.running resetButton.disable <== model.running startButton.onAction = handle { model.onStart() } stopButton.onAction = handle { model.onStop() } resetButton.onAction = handle { model.onReset() } private def format2d(t: Number) = f"${t.longValue()}%02d" }
The
ModelFX
implements the logic for the operation of the Stop Watch. Notice that there are no direct references to UI controls. The connection to the UI is through the properties (likeminutes
). TheModelFX
is not aware how theControllerFX
is implemented. (org.scalafx.extras.mvcfx.stopwatch.StopWatchModel
)package org.scalafx.extras.mvcfx.stopwatch import javafx.{concurrent => jfxc} import org.scalafx.extras._ import org.scalafx.extras.mvcfx.ModelFX import scalafx.Includes._ import scalafx.beans.property.{LongProperty, ReadOnlyBooleanProperty, ReadOnlyBooleanWrapper} class StopWatchModel extends ModelFX { private val _running = ReadOnlyBooleanWrapper(false) val running: ReadOnlyBooleanProperty = _running.readOnlyProperty private val counterService = new CounterService() counterService.period = 10.ms val minutes = new LongProperty() val seconds = new LongProperty() val secondFraction = new LongProperty() counterService.elapsedTime.onChange { (_, _, newValue) => val t = newValue.longValue() secondFraction.value = t % 1000 seconds.value = (t / 1000) % 60 minutes.value = t / 1000 / 60 } def onStart(): Unit = { counterService.doResume() _running.value = true } def onStop(): Unit = { counterService.doPause() _running.value = false } def onReset(): Unit = counterService.doReset() private class CounterService extends jfxc.ScheduledService[Long] { private var timeAccumulator: Long = 0 private var restartTime: Long = 0 val elapsedTime = new LongProperty() override def createTask(): jfxc.Task[Long] = { new jfxc.Task[Long]() { override protected def call(): Long = { val ct = System.currentTimeMillis() val et = timeAccumulator + (ct - restartTime) onFX {elapsedTime.value = et} et } } } def doPause(): Unit = { val ct = System.currentTimeMillis() timeAccumulator += (ct - restartTime) onFX {elapsedTime.value = timeAccumulator} this.cancel() } def doResume(): Unit = { restartTime = System.currentTimeMillis() this.restart() } def doReset(): Unit = { timeAccumulator = 0 onFX {elapsedTime.value = 0} } } }
The
MVCfx
implementation is very simple, it only needs instance of the model and information about location of the FXML resource. (org.scalafx.extras.mvcfx.stopwatch.StopWatch
)package org.scalafx.extras.mvcfx.stopwatch import org.scalafx.extras.mvcfx.MVCfx class StopWatch(val model: StopWatchModel = new StopWatchModel()) extends MVCfx("/org/scalafx/extras/mvcfx/stopwatch/StopWatchView.fxml")
The
MVCfx
can be easily used in an Application class to create UI. (org.scalafx.extras.mvcfx.stopwatch.StopWatchApp
)package org.scalafx.extras.mvcfx.stopwatch import scala.language.implicitConversions import scalafx.application.JFXApp import scalafx.application.JFXApp.PrimaryStage import scalafx.scene.Scene import scalafx.scene.layout.BorderPane object StopWatchApp extends JFXApp { stage = new PrimaryStage { scene = new Scene { title = "StopWatch" root = new BorderPane { center = new StopWatch().view } } } }
- package pong
Type Members
- class BusyWorker extends ShowMessage
BusyWorker helps running UI tasks a separate threads (other than the JavaFX Application thread).
BusyWorker helps running UI tasks a separate threads (other than the JavaFX Application thread). It will show busy cursor and disable specified nodes while task is performed. It gives an option to show progress and status messages.
BusyWorker
run tasks and takes care of handling handling exceptions and displaying error dialogs. There is also option to perform custom finish actions after task is completed.While task is performed property
busy
is set to true. Only one task, for a given worker, can be run at the time. When a task in being performedbusyDisabledNode
will be disabled and its cursor will be set toWait
/Busy
cursor.Progress and messages from the running task can be monitored using
progressValue
andprogressMessage
properties.Below is an example of using using BusyWorker that updates a progress message and progress indicator. The full example can be found in the
BusyWorkerDemo
of the ScalaFX Extras Demo project.val buttonPane: Pane = ... val progressLabel: Label = ... val progressBar: ProgressBar = ... val busyWorker = new BusyWorker("BusyWorker Demo", buttonPane) { progressLabel.text <== progressMessage progressBar.progress <== progressValue } val button = new Button("Click Me") { onAction = () => busyWorker.doTask("Task 1")( new SimpleTask[String] { override def call(): String = { val maxItems = 10 for (i <- 1 to maxItems) { println(i) message() = s"Processing item $i/$maxItems" progress() = (i - 1) / 10.0 Thread.sleep(250) } progress() = 1 "Done" } } ) }
- trait ShowMessage extends AnyRef
Mixin that adds ability to easily show message dialogs.
Mixin that adds ability to easily show message dialogs. A messageLogger can be provided, so when the error or warning dialogs are shown, they are also logged.
A ShowMessage mixin will typically be used with the ModelFX.
- trait ShowMessageLogger extends AnyRef
Logging operations used by ShowMessage.
Logging operations used by ShowMessage. Enables ShowMessage to use loggers preferred by the user.
Value Members
- def initFX(): Unit
Attempt to initialize JavaFX Toolkit.
Attempt to initialize JavaFX Toolkit. This is only needed when application is not started by
JFXApp
or JavaFXApplication
.When JavaFX toolkit is not initialized and you attempt to use JavaFX components you will get exception:
java.lang.IllegalStateException: Toolkit not initialized
.In JavaFX 9 and newer you can use
Platform.startup(() -> {})
. - def offFX[R](op: => R): Unit
Runs an operation
op
on a separate thread.Runs an operation
op
on a separate thread. Exceptions during execution are ignored. Similar to org.scalafx.extras#run, with default name for the thread: "offFX".- op
operation to be performed.
- def offFXAndWait[R](op: => R): R
Run operation
op
off FX application thread and wait for completion.Run operation
op
off FX application thread and wait for completion. If the current thread is not the FX application, the operation will be run on it (no new thread will ne created).- op
operation to be performed.
- Exceptions thrown
java.lang.InterruptedException
- if the current thread was interrupted while waitingjava.util.concurrent.CancellationException
- if the computation was cancelledjava.util.concurrent.ExecutionException
- if the computation threw an exception
- def onFX[R](op: => R): Unit
Run operation
op
on FX application thread.Run operation
op
on FX application thread. If on FX Application thread it will wait for operation to compete, if not on FX Application thread it will return without waiting for the operation to complete.- op
operation to be performed.
- def onFXAndWait[R](op: => R): R
Run operation
op
on FX application thread and wait for completion.Run operation
op
on FX application thread and wait for completion. If the current thread is the FX application, the operation will be run on it.- op
operation to be performed.
- Exceptions thrown
java.lang.InterruptedException
- if the current thread was interrupted while waitingjava.util.concurrent.CancellationException
- if the computation was cancelledjava.util.concurrent.ExecutionException
- if the computation threw an exception
- def run[R](op: => R, name: String): Unit
Runs an operation
op
on a separate thread.Runs an operation
op
on a separate thread. Exceptions during execution are ignored.- op
operation to run
- name
name for the thread to run the operation. Useful for debugging.
- def runTask[T](task: Task[T], name: String): Unit
Run task on a named daemon thread.
Run task on a named daemon thread.
- task
to run
- name
name for the thread to run the operation. Useful for debugging.
- def showException(title: String, message: String, t: Throwable, ownerWindow: Option[Window] = None): Unit
Show a modal dialog with an expandable details about an exception (stack trace).
Show a modal dialog with an expandable details about an exception (stack trace).
- title
dialog title
- message
message shown in the dialog header.
- t
exception.
- ownerWindow
owner window that will be blacked by the dialog.
- def showException(title: String, message: String, t: Throwable, ownerWindow: Window): Unit
Show a modal dialog with an expandable details about an exception (stack trace).
Show a modal dialog with an expandable details about an exception (stack trace).
- title
dialog title
- message
message shown in the dialog header.
- t
exception.
- ownerWindow
owner window that will be blacked by the dialog. Can be
null
to match JavaFX convention.
- def showException(title: String, message: String, t: Throwable, ownerWindow: Node): Unit
Show a modal dialog with an expandable details about an exception (stack trace).
Show a modal dialog with an expandable details about an exception (stack trace).
- title
dialog title
- message
message shown in the dialog header.
- t
exception.
- ownerWindow
owner window that will be blacked by the dialog. Can be
null
.
- object BusyWorker
Helper methods and classes to simplify ScalaFX use.
Package
org.scalafx.extras
contains basic helper methods for running tasks on threads and showing messages.Package
org.scalafx.extras.image
contains image display component with scrolling and zooming.Package
org.scalafx.extras.mvcfx
contains classes for creating with UI components based on FXML.