Giter VIP home page Giter VIP logo

scalafx-extras's Introduction

ScalaFX Extras

Scala CI Maven Central Scaladoc

ScalaFX Extras are additions to ScalaFX that simplify creation of User interfaces. In contrast to ScalaFX core, the Extras do not have direct corresponding concepts in JavaFX.

Contents

Project Structure

Module scalafx-extras contain feature implementations. Module scalafx-extras-demos illustrates use of scalafx-extras

SBT

To use ScalaFX Extras with SBT add following dependency:

libraryDependencies += "org.scalafx" %% "scalafx-extras" % scalafx_extras_version

The latest published ScalaFX Extras version: Maven Central

Features

Helper Methods

Package org.scalafx.extras contains basic helper methods for running tasks on threads and showing exception messages. The main helper methods:

  • onFX run code on FX Application thread in parallel
  • onFXAndWait run code on FX Application thread and wait till finished
  • offFX run code a thread in parallel
  • offFXAndWait run code a thread and wait till finished

Example scheduling some code on FX Application thread

onFX {
  counterService.doResume()
  _running.value = true
}

Example execution some code on a separate thread and waiting for the result of computation

val x = offFXAndWait {
  val a = 3
  val b = 7
  a * b
}

Simpler Display of Standard Dialogs

Standard dialogs can be quickly displayed using functions provided my ShowMessage. For instance,

import org.scalafx.extras.ShowMessage

ShowMessage.information(
  "Dialog Title",
  "This is the information 'header'",
  "This is the information detailed 'content'.",
  parentWindow
)

Dialog types supported:

  • confirmation
  • confirmationYesNoCancel
  • error
  • exception
  • information
  • warning

ShowMessage can be also used as a mixin to be used within a class where there is the same parentWindow. It is typically used with a UI Model. The dialogs can be displayed using a single method, like showInformation, showConfirmation. ShowMessage takes care of blocking parent windows and using parent icons in dialogs. It can also log warnings, errors, and exceptions when warnings, errors, and exceptions dialogs are displayed.

class MyUIModel extends Model with ShowMessage {

  def onSomeUserAction(): Unit = {
    // ...
    showInformation("Dialog Title",
      "This is the information 'header'",
      "This is the information detailed 'content'.")
    // ...
  }

  // ...
}

The demos module has a complete example of a simple application in ShowMessageDemoApp.

Easy Custom Panes

GenericPane is a helper class that simplifies creation of panes. Particularly suited for creation of input controls.

Typically there are 4 steps to using a GenericPane:

  1. Creation, where elements of the pane are appended vertically using add*(...) methods, for instance, addStringField(label, defaultText)

  2. Adding the pane to the UI

  3. User interaction, after the pane is displayed

  4. Optionally, reading of input. Pane's editable content can be read using next*() methods. Content is read in the order it is added. The whole pane content can be read multiple tiles. Remember to call resetReadout() to ensure that reading is restarted from the beginning of the pane.

A complete example in Scala 3. Shows a pane with 2 directory selection fields and a button "Print Fields". When the button is pressed values of the directory fields are printed

import org.scalafx.extras.generic_pane.GenericPane
import scalafx.application.JFXApp3
import scalafx.application.JFXApp3.PrimaryStage
import scalafx.geometry.Insets
import scalafx.scene.Scene
import scalafx.scene.control.Button
import scalafx.scene.layout.VBox

object GenericPaneDemo extends JFXApp3:

  override def start(): Unit =

    val gp = new GenericPane():
      addDirectoryField("Input", "images")
      addDirectoryField("Output", "output")

    stage = new PrimaryStage:
      title = "GenericPane Demo"
      scene = new Scene:
        content = new VBox:
          padding = Insets(7, 7, 7, 7)
          spacing = 7
          children = Seq(
            gp.pane,
            new Button("Print Fields"):
              onAction = (_) =>
                gp.resetReadout()
                println(s"Input dir : ${gp.nextString()}")
                println(s"Output dir: ${gp.nextString()}")
          )

GenericPane Demo

Easy Custom Dialogs

Custom dialogs can be quickly created using GenericDialogFX class. This class is particularly suited for creation of input dialogs.

There are 3 steps to using the GenericDialogFX:

  1. Creation, where elements of the dialog are appended vertically using add*(...) methods, for instance,addStringField(label, defaultText)
  2. User interaction, dialog is displayed using showDialog() method
  3. Reading of input, once the dialog is closed, dialog content can be read using next*() methods. Content is read in the order it is added.

Here is en example:

// Create a dialog
val dialog =
  new GenericDialogFX(
    title = "GenericDialogFX Demo",
    header = "Fancy description can go here."
  ) {
    // Add fields
    addCheckbox("Check me out!", defaultValue = false)
    addCheckbox("Check me too!", defaultValue = true)
  }

// Show dialog to the user
dialog.showDialog()

// Read input provided by the user
if (dialog.wasOKed) {
  val select1 = dialog.nextBoolean()
  val select2 = dialog.nextBoolean()

  println(s"Selection 1: $select1")
  println(s"Selection 2: $select2")
} else {
  println("Dialog was cancelled.")
}

GenericDialogFX Demo

A more elaborate example is in the GenericDialogFXDemo.

Edit a Case Class object with AutoDialog

AutoDialog can be used too quickly open auto generated dialog from case class. After closing, the dialog will return edited version of the input case class.

Here is an example of usage:

import org.scalafx.extras.auto_dialog.AutoDialog

case class FilterOptions(kernelSize: Int = 7,
                         start: Double = 3.14,
                         tag: String = "alpha",
                         debugMode: Boolean = false)

val filterOptions = FilterOptions()

val result: Option[FilterOptions] =
  new AutoDialog(filterOptions)
    .showDialog(
      "AutoDialog Demo",
      "Fields are auto generated from `FilterOptions` object")

println(s"Result: $result")

GenericDialogFX Demo

BusyWorker

BusyWorker helps running a UI task on separate threads (other than the JavaFX Application thread). It will show busy cursor and disable specified nodes while the task is performed. It gives an option to show progress and status messages. BusyWorker takes care of handling exceptions and displaying error dialogs. It provides for an option to perform custom finish actions after task is completed.

Example 1

Below is a simple example of using BusyWorker. When the task is running, BusyWorker will disable the root pane of the parentWindow to indicate that a task is performed. It will also change the cursor in the root pane to "busy". When task is done, the cursor will be changed back to default and root pane will be enabled back.

new BusyWorker("Simple Task", parentWindow).doTask { () =>
  Thread.sleep(1000)
  print(1 + 1)
}

Example 2

Here is a little more elaborated example. It updates a progress message and progress indicator.

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"
      }
    }
  )
}

The full code example can be found in the BusyWorkerDemo.

Simpler Use of FXML with MVCfx Pattern

Package org.scalafx.extras.mvcfx contains classes for creating with UI components based on FXML that use Model-View-Controller, here we call it the MVCfx Pattern. See wiki page MVCfx Pattern for details.

The demos module has a complete example of a simple application: StopWatchApp.

ImageDisplay Component

ImageDisplay Component is an image view with the ability to zoom in, zoom out, zoom to fit. It can also automatically resize to parent size.

Batch Processing and Progress Dialog

Work in progress

  • Helper UI for running batch processing tasks, see BatchRunnerProgressDemoApp for example of use
  • Component for display of progress of batch processing tasks, see ProgressStatusDemoApp for example of use

Demos

Module scalafx-extras-demos contains examples of using ScalaFX Extras.

StopWatch Application

StopWatchApp is an application that illustrates uses of the MVCfx Pattern: a Model-View-Controller with FXML layout.

StopWatch Demo

There are slight differences between Scala 2 and 3 related to use of annotations. See StopWatchDemo Scala 2 and StopWatchDemo Scala 3 files for details. It is described in details in MVCfx Pattern wiki page.

ShowMessage Demo

ShowMessageDemoApp is a full example of using ShowMessage and MVCfx.

ShowMessage Demo

There are slight differences between Scala 2 and 3 related to use of annotations. See ShowMessageDemo Scala 2 and ShowMessageDemo Scala 3 files for details.

BusyWorker Demo

BusyWorkerDemo illustrated different aspects of using BusyWorker.

BusyWorker Demo

ImageDisplay Demo

ImageDisplayDemoApp a simple example of an application that can display images, with the ability to zoom in, zoom out, and fit to the current window, flip, and rotate the image. Illustrates use of the ImageDisplay component.

Image Display Demo

BatchRunnerWithProgress Demo

BatchRunnerWithProgressDemoApp demo of BatchRunnerWithProgress GUI.

BatchRunnerWithProgress Demo

Status

ScalaFX Extras is still quite experimental and APIs may change significantly.

Discussion and Support

For discussion and support, please use ScalaFX Users Group or project Discussions. Please report issues using the projects Issue tracker.

License

BSD-3-Clause ScalaFX license.

scalafx-extras's People

Contributors

jpsacha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

scalafx-extras's Issues

IllegalAccessError in AutoDialog (0.7.0)

Exception when trying to use AutoDialog. This happening with release 0.7.0

Exception in thread "main" java.lang.IllegalAccessError: failed to access class org.scalafx.extras.auto_dialog.DialogEncoder$LabeledBuilder from class staircase.AutoDialogDemo1$$anon$1 (org.scalafx.extras.auto_dialog.DialogEncoder$LabeledBuilder and staircase.AutoDialogDemo1$$anon$1 are in unnamed module of loader 'app')
	at staircase.AutoDialogDemo1$$anon$1.<init>(AutoDialogDemo1.scala:51)
	at staircase.AutoDialogDemo1$.main(AutoDialogDemo1.scala:51)
	at staircase.AutoDialogDemo1.main(AutoDialogDemo1.scala)

The source code to reproduce the issue:

package staircase

import org.scalafx.extras.auto_dialog.AutoDialog
import org.scalafx.extras.initFX

object AutoDialogDemo1:

  case class LikeRecord(
    firstName: String = "",
    lastName: String = "",
    age: Int = 0,
    likesBeatles: Boolean = true
  )
  def main(args: Array[String]): Unit =

    initFX()

    val srcData = LikeRecord()

    val result: Option[LikeRecord] =
      new AutoDialog(srcData)
        .showDialog(
          "AutoDialog Demo",
          "Fields are auto generated from `LikeRecord` object"
        )

    println(result)

    System.exit(0)

v.0.7.0 was build with Scala 3.0.2, rebuilding scalafx-extras with Scala 3.2.2 resolves the issue (without modification to the above example).

Do not include JavaFX as transitive dependency

JavaFX dependency is OS dependent, when you make it a transitive dependency, chance is that somebody using it on different OS than that it was build for will run into issues.

In SBT mark JavaFX dependencies as "provided".

Generic Pane

Add Generic Pane with API similar to GenericDialogFX, but creating a pane can used with more flexibility in building UI - not limited to dialogs

[Scala 3] auto generate input dialogs from simple case classes

For a set of case classes with simple fields provide ability to automatically create a dialog and then read its fields, edited by the user, to a new case class. It could looks something like this

case class FilterOptions(kernelSize: Int = 7, start: Double = 3.14, tag:String="alpha")

val src = FilterOptions()

val dst: Option[FilterOptions] = new AutoDialog(src).showDialog("Filter Options")

BusyWorker.doTask - incorrect behavior with code blocks

Consider this code

busyWorker.doTask("myTask") {
  op1()
  op2()
  op3()
}

One would expect that all 3 operations will be run on a separate thread. However, currently op1 and op2 will be executed on current thread, only op3 will be executed on a separate thread.

BusyWorker should not allow writing this type of code.

To fix this user has to write:

busyWorker.doTask("myTask") { () =>
  op1()
  op2()
  op3()
}

Add abstract 'initialize()' to 'ControllerFX' trait (Scala 3)

To properly initialize ControllerFX the initialization method needs to be annotated with @FXML. It is possible to miss it and initialization will not be performed. Add to ControllerFX an abstract method initialize() that will need to be overwritten to remain that initialization needs to be done there. It should be used without @FXML annotation.

Support Scala 3

As of Scala 2, the MVCfx classes depend on ScalaFXML. ScalaFXML is using macros that are no longer supported in Scala 3. It is not clear if ScalaFXML will support Scala 3, if it will there will be likely API changers (vigoo/scalafxml#32).

Need to provide an alternate means of using MVCfx in Scala 3. The simplest way is to use JavaFX @fxml annotation and attempt to preserve as much as possible of the current MVCfx API. It should be possible to at fully reuse the ModelFX.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.