├── project └── build.properties ├── hello-sbt ├── project │ └── build.properties ├── README.md ├── src │ └── main │ │ └── scala │ │ └── hello │ │ └── HelloSBT.scala └── build.sbt ├── event-filters ├── project │ └── build.properties ├── README.md ├── build.sbt └── src │ └── main │ └── scala │ └── event_filters │ ├── DraggablePanelsExample.scala │ └── DraggablePanelsExample2.scala ├── molecule-3d ├── project │ └── build.properties ├── README.md ├── build.sbt └── src │ └── main │ └── scala │ └── molecule3d │ ├── Xform.scala │ └── MoleculeSampleDemo.scala ├── properties ├── project │ ├── build.properties │ └── plugins.sbt ├── README.md ├── build.sbt └── src │ └── main │ └── scala │ └── org │ └── scalafx │ └── tutorials │ └── properties │ ├── CustomStringBinding.scala │ ├── Properties101.scala │ ├── VariablePrecisionComparison.scala │ ├── BindingExpressions.scala │ ├── PropertyBinding.scala │ └── WhenChooseOtherwiseExpression.scala ├── slick-table ├── project │ └── build.properties ├── src │ └── main │ │ ├── resources │ │ └── application.conf │ │ └── scala │ │ └── org │ │ └── scalafx │ │ └── slick_table │ │ ├── Person.scala │ │ ├── ContactsView.scala │ │ ├── SlickTableDemo.scala │ │ ├── AddContactDialog.scala │ │ ├── TaskRunner.scala │ │ ├── ContactsDB.scala │ │ └── ContactsViewModel.scala ├── ReadMe.md └── build.sbt ├── splash-demo ├── project │ └── build.properties ├── README.md ├── build.sbt └── src │ └── main │ └── scala │ └── splash_demo │ ├── Splash.scala │ └── SplashDemoApp.scala ├── cell_factories ├── project │ └── build.properties ├── README.md ├── build.sbt └── src │ └── main │ └── scala │ └── cell_factories │ ├── ListViewSimpleDemo.scala │ ├── ComboBoxCellFactoryDemo.scala │ ├── CheckBoxListCellDemo.scala │ ├── ListViewCustomDemo.scala │ ├── MyTreeViewCellFactoryDemo.scala │ ├── ColorCharactersInTableView.scala │ ├── EditableTableView.scala │ ├── extras │ └── SimpleTableView.scala │ └── TreeViewCellFactoryDemo.scala ├── sam_event_handlers ├── project │ └── build.properties ├── build.sbt ├── src │ └── main │ │ └── scala │ │ └── samEventHandlers │ │ └── SAMDemo.scala └── Readme.md ├── scalafxml-example ├── project │ └── build.properties ├── src │ └── main │ │ └── scala │ │ └── sfxml │ │ ├── cat.jpg │ │ ├── FXMLAdoptionForm.scala │ │ ├── AdoptionFormPresenter.scala │ │ └── AdoptionForm.fxml ├── README.md └── build.sbt ├── spreadsheetview ├── project │ └── build.properties ├── src │ └── main │ │ ├── resources │ │ └── spreadsheetview │ │ │ ├── minusPicker.png │ │ │ ├── plusPicker.png │ │ │ └── spreadsheetSample2.css │ │ └── scala │ │ └── spreadsheetview │ │ ├── SpreadsheetViewExample2App.scala │ │ ├── TableViewExample5App.scala │ │ ├── SpreadsheetViewExample4App.scala │ │ ├── SpreadsheetViewExample3App.scala │ │ └── SpreadsheetViewExample2.scala ├── README.md └── build.sbt ├── stand-alone-dialog ├── project │ └── build.properties ├── README.md ├── build.sbt └── src │ └── main │ └── scala │ └── stand_alone_dialog │ ├── FXUtils.scala │ ├── StandAloneFXDialog.scala │ ├── DialogBeforePrimaryStage.scala │ └── StandAloneFXDialogRunAndWait.scala ├── .scalafmt.conf ├── .github └── workflows │ └── scala.yml ├── README.md └── .gitignore /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /hello-sbt/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /event-filters/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /molecule-3d/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /properties/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /slick-table/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /splash-demo/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /cell_factories/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | 3 | -------------------------------------------------------------------------------- /sam_event_handlers/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /scalafxml-example/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /spreadsheetview/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /stand-alone-dialog/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /scalafxml-example/src/main/scala/sfxml/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalafx/ScalaFX-Tutorials/HEAD/scalafxml-example/src/main/scala/sfxml/cat.jpg -------------------------------------------------------------------------------- /properties/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | // eclipse @ https://github.com/typesafehub/sbteclipse 2 | addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0") 3 | -------------------------------------------------------------------------------- /spreadsheetview/src/main/resources/spreadsheetview/minusPicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalafx/ScalaFX-Tutorials/HEAD/spreadsheetview/src/main/resources/spreadsheetview/minusPicker.png -------------------------------------------------------------------------------- /spreadsheetview/src/main/resources/spreadsheetview/plusPicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalafx/ScalaFX-Tutorials/HEAD/spreadsheetview/src/main/resources/spreadsheetview/plusPicker.png -------------------------------------------------------------------------------- /slick-table/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | h2mem1 = { 2 | url = "jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1" 3 | driver = org.h2.Driver 4 | connectionPool = disabled 5 | keepAliveConnection = true 6 | } -------------------------------------------------------------------------------- /cell_factories/README.md: -------------------------------------------------------------------------------- 1 | Cell Factories 2 | ============== 3 | 4 | Examples of using cell factories to customize cell rendering. 5 | 6 | Some draft text is in: `ScalaFX\scalafx.github.io.git\_docs\call_factories.md` -------------------------------------------------------------------------------- /spreadsheetview/README.md: -------------------------------------------------------------------------------- 1 | Spreadsheet View 2 | ================ 3 | 4 | Examples of 5 | using [ContolsFX SpreadsheetView](https://github.com/controlsfx/controlsfx/wiki/ControlsFX-Features#spreadsheetview) 6 | from ScalaFX. -------------------------------------------------------------------------------- /properties/README.md: -------------------------------------------------------------------------------- 1 | properties 2 | ========== 3 | 4 | Examples of using properties, property bindings, and binding expressions. Complete description is in ScalaFX documentation section [Properties](http://www.scalafx.org/docs/properties/). -------------------------------------------------------------------------------- /molecule-3d/README.md: -------------------------------------------------------------------------------- 1 | Molecule 3D 2 | =========== 3 | 4 | ScalaFX implementation of `MoleculeSampleApp` from tutorial [Getting Started with JavaFX 3D Graphics](http://docs.oracle.com/javafx/8/3d_graphics/jfxpub-3d_graphics.htm) 5 | by Cindy Castillo and John Yoon. 6 | -------------------------------------------------------------------------------- /event-filters/README.md: -------------------------------------------------------------------------------- 1 | Event Filters 2 | ============= 3 | 4 | Examples demonstrating use of ScalaFX Event Filter API. The code is based on JavaFX example 5 | [Handling JavaFX Events, Part 3 Working with Event Filters](http://docs.oracle.com/javafx/2/events/filters.htm). 6 | -------------------------------------------------------------------------------- /stand-alone-dialog/README.md: -------------------------------------------------------------------------------- 1 | Stand-alone Dialog 2 | ================== 3 | 4 | Examples of displaying a ScalaFX dialog (stage) without using `JFXApp3`. You can use this approach, for instance, to 5 | show a JavaFX dialog from a command line or from a Swing application. 6 | -------------------------------------------------------------------------------- /splash-demo/README.md: -------------------------------------------------------------------------------- 1 | Splash Stage Demo 2 | ================= 3 | 4 | Displays a splash stage with a progress bar during startup then opens main application stage. 5 | Based on [TaskBasedSplash](https://gist.github.com/jewelsea/2305098) by [jewelsea](https://gist.github.com/jewelsea). 6 | 7 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 3.9.4 2 | 3 | runner.dialect = scala213 4 | 5 | preset = IntelliJ 6 | align.preset = more 7 | maxColumn = 120 8 | docstrings.style = Asterisk 9 | docstrings.blankFirstLine = yes 10 | docstrings.wrap = no 11 | importSelectors = singleLine 12 | newlines.source = keep -------------------------------------------------------------------------------- /slick-table/ReadMe.md: -------------------------------------------------------------------------------- 1 | Slick Table Demo 2 | ================ 3 | 4 | This is an example of using a table view with database interfaced through [Slick](http://slick.lightbend.com/) API. 5 | 6 | The main class is the `SlickTableDemo`. The implementation is separated into a domain model `ContactsDB`, 7 | the main view definition `ContactsView`, the main view model `ContactsViewModel`. -------------------------------------------------------------------------------- /hello-sbt/README.md: -------------------------------------------------------------------------------- 1 | hello-sbt 2 | ========= 3 | 4 | A basic example of using [Simple-Build-Tool](http://www.scala-sbt.org/) (SBT) and [ScalaFX](http://scalafx.org). 5 | Detailed description of this example can be found in the blog post 6 | ["Getting Started with ScalaFX: Compile and Run"](http://codingonthestaircase.wordpress.com/2013/05/17/getting-started-with-scalafx-compile-and-run-2/). 7 | -------------------------------------------------------------------------------- /spreadsheetview/build.sbt: -------------------------------------------------------------------------------- 1 | name := "SpreadsheetView" 2 | scalaVersion := "2.13.16" 3 | 4 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 5 | libraryDependencies += "org.controlsfx" % "controlsfx" % "11.2.2" 6 | 7 | resolvers += Resolver.mavenLocal 8 | 9 | // Prevent startup bug in JavaFX 10 | fork := true 11 | 12 | scalacOptions += "-feature" 13 | 14 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 15 | -------------------------------------------------------------------------------- /scalafxml-example/README.md: -------------------------------------------------------------------------------- 1 | ScalaFXML Example 2 | ================= 3 | 4 | This example demonstrates use of FXML with ScalaFX using 5 | [ScalaFXML](https://github.com/vigoo/scalafxml) library. 6 | 7 | The source code is based on [FXML example from ProJavaFX](https://github.com/scalafx/ProScalaFX/tree/master/src/proscalafx/ch10). 8 | The [ScalaFXML](https://github.com/vigoo/scalafxml) library enables much simplified way of using 9 | FXML from ScalaFX. 10 | -------------------------------------------------------------------------------- /.github/workflows/scala.yml: -------------------------------------------------------------------------------- 1 | name: Scala CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up JDK 24 13 | uses: actions/setup-java@v4 14 | with: 15 | java-version: '24' 16 | distribution: 'temurin' 17 | cache: sbt 18 | - uses: sbt/setup-sbt@v1 19 | - name: Run compilation as a basic check 20 | run: sbt +test 21 | -------------------------------------------------------------------------------- /slick-table/src/main/scala/org/scalafx/slick_table/Person.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.slick_table 2 | 3 | import scalafx.beans.property.StringProperty 4 | 5 | /** 6 | */ 7 | case class Person(id: Option[Int], first: String, last: String, email: String) { 8 | val firstName = new StringProperty(this, "firstName", first) 9 | val lastName = new StringProperty(this, "lastName", last) 10 | val emailAddress = new StringProperty(this, "emailAddress", email) 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /molecule-3d/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Molecule 3D" 2 | organization := "scalafx.org" 3 | version := "0.2.6" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | resolvers += Resolver.sonatypeRepo("snapshots") 8 | 9 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 10 | 11 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 12 | 13 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 14 | fork := true 15 | -------------------------------------------------------------------------------- /properties/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Properties" 2 | organization := "scalafx.org" 3 | version := "0.3" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 8 | 9 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 10 | 11 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 12 | 13 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 14 | fork := true 15 | -------------------------------------------------------------------------------- /event-filters/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Event Filters" 2 | organization := "scalafx.org" 3 | version := "1.0.8" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 8 | 9 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 10 | 11 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 12 | 13 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 14 | fork := true 15 | -------------------------------------------------------------------------------- /sam_event_handlers/build.sbt: -------------------------------------------------------------------------------- 1 | name := "SAM Event Handlers" 2 | organization := "ScalaFX.org" 3 | version := "0.1.3" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 8 | 9 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 10 | 11 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 12 | 13 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 14 | fork := true 15 | -------------------------------------------------------------------------------- /stand-alone-dialog/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Stand-Alone Dialog" 2 | organization := "scalafx.org" 3 | version := "1.0.8" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 8 | 9 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 10 | 11 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 12 | 13 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 14 | fork := true 15 | 16 | -------------------------------------------------------------------------------- /cell_factories/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Cell Factories" 2 | organization := "scalafx.org" 3 | version := "1.0.0" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 8 | 9 | // Add dependency on ScalaFX library 10 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 11 | 12 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 13 | 14 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 15 | fork := true 16 | -------------------------------------------------------------------------------- /splash-demo/build.sbt: -------------------------------------------------------------------------------- 1 | name := "splash-demo" 2 | 3 | organization := "org.scalafx" 4 | 5 | version := "0.2.2" 6 | 7 | scalaVersion := "2.13.16" 8 | 9 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 10 | 11 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 12 | 13 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 14 | 15 | // set the main class for the main 'run' task 16 | // change Compile to Test to set it for 'test:run' 17 | Compile / run / mainClass := Some("splash_demo.SplashDemoApp") 18 | -------------------------------------------------------------------------------- /properties/src/main/scala/org/scalafx/tutorials/properties/CustomStringBinding.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.tutorials.properties 2 | 3 | import scalafx.beans.binding.Bindings 4 | import scalafx.beans.property.StringProperty 5 | 6 | /** 7 | * Custom String Binding example. 8 | */ 9 | object CustomStringBinding extends App { 10 | 11 | val a = new StringProperty() 12 | val b = Bindings.createStringBinding(() => Option(a.value).getOrElse("").toLowerCase(), a) 13 | 14 | a.value = "Hello" 15 | println(s"Setting `a` to ${a.value}, `b` = ${b.value}") 16 | 17 | } 18 | -------------------------------------------------------------------------------- /properties/src/main/scala/org/scalafx/tutorials/properties/Properties101.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.tutorials.properties 2 | 3 | import scalafx.beans.property.DoubleProperty 4 | 5 | /** 6 | * Basic ScalaFX Properties example. 7 | */ 8 | object Properties101 extends App { 9 | 10 | val speed = new DoubleProperty(this, "speed", 55) { 11 | onChange { (_, oldValue, newValue) => 12 | println(s"Value of property '$name' is changing from $oldValue to $newValue") 13 | } 14 | } 15 | 16 | speed() = 60 17 | speed() = 75 18 | speed.value = 25 19 | 20 | } 21 | -------------------------------------------------------------------------------- /hello-sbt/src/main/scala/hello/HelloSBT.scala: -------------------------------------------------------------------------------- 1 | package hello 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.geometry.Insets 5 | import scalafx.scene.Scene 6 | import scalafx.scene.control.Label 7 | import scalafx.scene.layout.BorderPane 8 | 9 | object HelloSBT extends JFXApp3 { 10 | override def start(): Unit = { 11 | stage = new JFXApp3.PrimaryStage { 12 | scene = new Scene { 13 | root = new BorderPane { 14 | padding = Insets(25) 15 | center = new Label("Hello SBT") 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /hello-sbt/build.sbt: -------------------------------------------------------------------------------- 1 | // Name of the project 2 | name := "Hello SBT" 3 | 4 | // Project version 5 | version := "1.0.7" 6 | 7 | // Version of Scala used by the project 8 | scalaVersion := "2.13.16" 9 | 10 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 11 | 12 | // Add dependency on ScalaFX library 13 | libraryDependencies += "org.scalafx" %% "scalafx" % "24.0.0-R35" 14 | 15 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 16 | 17 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 18 | fork := true 19 | -------------------------------------------------------------------------------- /scalafxml-example/build.sbt: -------------------------------------------------------------------------------- 1 | name := "ScalaFXML Example" 2 | organization := "scalafx.org" 3 | version := "1.0.7" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8", "-Ymacro-annotations") 8 | 9 | Compile / resourceDirectory := (Compile / scalaSource).value 10 | libraryDependencies ++= Seq( 11 | "org.scalafx" %% "scalafx" % "24.0.0-R35", 12 | "org.scalafx" %% "scalafxml-core-sfx8" % "0.5" 13 | ) 14 | 15 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 16 | 17 | // Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems 18 | fork := true 19 | -------------------------------------------------------------------------------- /slick-table/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Slick Table" 2 | organization := "org.scalafx" 3 | version := "0.3" 4 | 5 | scalaVersion := "2.13.16" 6 | 7 | scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8") 8 | 9 | libraryDependencies ++= Seq( 10 | "org.scalafx" %% "scalafx" % "24.0.0-R35", 11 | "com.typesafe.slick" %% "slick" % "3.6.0", 12 | "org.slf4j" % "slf4j-nop" % "2.0.17", 13 | "com.h2database" % "h2" % "2.3.232" 14 | ) 15 | 16 | resolvers ++= Opts.resolver.sonatypeOssSnapshots 17 | 18 | // Fork a new JVM for 'run' and 'test:run' to avoid JavaFX double initialization problems 19 | fork := true 20 | -------------------------------------------------------------------------------- /sam_event_handlers/src/main/scala/samEventHandlers/SAMDemo.scala: -------------------------------------------------------------------------------- 1 | package samEventHandlers 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.scene.Scene 5 | import scalafx.scene.control.Button 6 | import scalafx.scene.layout.HBox 7 | 8 | object SAMDemo extends JFXApp3 { 9 | 10 | override def start(): Unit = { 11 | stage = new JFXApp3.PrimaryStage { 12 | title = "SAM Demo" 13 | scene = new Scene { 14 | root = new HBox { 15 | children = Seq( 16 | new Button { 17 | text = "Print message" 18 | onAction = _ => println("some message") 19 | } 20 | ) 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /spreadsheetview/src/main/scala/spreadsheetview/SpreadsheetViewExample2App.scala: -------------------------------------------------------------------------------- 1 | package spreadsheetview 2 | 3 | import scalafx.Includes._ 4 | import scalafx.application.JFXApp3 5 | import scalafx.geometry.Insets 6 | import scalafx.scene.Scene 7 | import scalafx.scene.layout.BorderPane 8 | 9 | object SpreadsheetViewExample2App extends JFXApp3 { 10 | override def start(): Unit = { 11 | val spv = new SpreadsheetViewExample2() 12 | val stage = new JFXApp3.PrimaryStage { 13 | scene = new Scene { 14 | title = "SpreadsheetView Example 2" 15 | root = new BorderPane { 16 | padding = Insets(5) 17 | center = spv.spreadSheetView 18 | right = spv.controlGrid 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /properties/src/main/scala/org/scalafx/tutorials/properties/VariablePrecisionComparison.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.tutorials.properties 2 | 3 | import scalafx.Includes._ 4 | import scalafx.beans.property.DoubleProperty 5 | 6 | /** 7 | * Boolean expression that compares a double property to double value within given precision. 8 | */ 9 | object VariablePrecisionComparison extends App { 10 | 11 | val a = DoubleProperty(1) 12 | val b = a === 2d +- 0.1d 13 | 14 | println(s"Setting a to ${a.value}: b = ${b.value}") 15 | 16 | a() = 1.5 17 | println(s"Setting a to ${a.value}: b = ${b.value}") 18 | 19 | a() = 1.95 20 | println(s"Setting a to ${a.value}: b = ${b.value}") 21 | 22 | a() = 2.5 23 | println(s"Setting a to ${a.value}: b = ${b.value}") 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /properties/src/main/scala/org/scalafx/tutorials/properties/BindingExpressions.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.tutorials.properties 2 | 3 | import scalafx.beans.property.DoubleProperty 4 | 5 | /** 6 | * Examples of numeric binding expressions. 7 | */ 8 | object BindingExpressions extends App { 9 | val base = DoubleProperty(15) 10 | val height = DoubleProperty(10) 11 | val area = DoubleProperty(0) 12 | 13 | area <== base * height / 2 14 | 15 | printValues() 16 | 17 | println("Setting base to " + 20) 18 | base() = 20 19 | 20 | printValues() 21 | 22 | println("Setting height to " + 5) 23 | height() = 5 24 | 25 | printValues() 26 | 27 | def printValues(): Unit = { 28 | println(f"base = ${base()}%4.1f, height = ${height()}%4.1f, area = ${area()}%5.1f\n") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /stand-alone-dialog/src/main/scala/stand_alone_dialog/FXUtils.scala: -------------------------------------------------------------------------------- 1 | package stand_alone_dialog 2 | 3 | import java.util.concurrent 4 | 5 | import scalafx.application.Platform 6 | 7 | object FXUtils { 8 | 9 | /** 10 | * Run operation `op` on FX application thread and wait for completion. 11 | * If the current thread is the FX application, the operation will be run on it. 12 | * 13 | * @param op operation to be performed. 14 | */ 15 | def onFXAndWait[R](op: => R): R = { 16 | if (Platform.isFxApplicationThread) { 17 | op 18 | } else { 19 | val callable = new concurrent.Callable[R] { 20 | override def call(): R = op 21 | } 22 | val future = new concurrent.FutureTask(callable) 23 | Platform.runLater(future) 24 | future.get() 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /properties/src/main/scala/org/scalafx/tutorials/properties/PropertyBinding.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.tutorials.properties 2 | 3 | import scalafx.beans.property.DoubleProperty 4 | 5 | /** 6 | * Property binding examples. 7 | */ 8 | object PropertyBinding extends App { 9 | 10 | val a = DoubleProperty(1) 11 | val b = DoubleProperty(2) 12 | val c = DoubleProperty(3) 13 | val d = DoubleProperty(4) 14 | 15 | println(s"a = $a, b= $b, c = $c, d = d") 16 | 17 | a <== b 18 | c <==> d 19 | 20 | println(s"a = ${a()}, b= ${b()}, c = ${c()}, d = ${d()}") 21 | 22 | b() = 5 23 | println(s"a = ${a()}, b= ${b()}, c = ${c()}, d = ${d()}") 24 | 25 | c() = 7 26 | println(s"a = ${a()}, b= ${b()}, c = ${c()}, d = ${d()}") 27 | 28 | d() = 9 29 | println(s"a = ${a()}, b= ${b()}, c = ${c()}, d = ${d()}") 30 | 31 | } 32 | -------------------------------------------------------------------------------- /scalafxml-example/src/main/scala/sfxml/FXMLAdoptionForm.scala: -------------------------------------------------------------------------------- 1 | package sfxml 2 | 3 | import scalafx.Includes._ 4 | import scalafx.application.JFXApp3 5 | import scalafx.scene.Scene 6 | import scalafxml.core.{FXMLView, NoDependencyResolver} 7 | 8 | import java.io.IOException 9 | 10 | /** 11 | * Example of using FXMLLoader from ScalaFX. 12 | * 13 | * @author Jarek Sacha 14 | */ 15 | object FXMLAdoptionForm extends JFXApp3 { 16 | override def start(): Unit = { 17 | 18 | val resource = getClass.getResource("AdoptionForm.fxml") 19 | if (resource == null) { 20 | throw new IOException("Cannot load resource: AdoptionForm.fxml") 21 | } 22 | 23 | val root = FXMLView(resource, NoDependencyResolver) 24 | 25 | stage = new JFXApp3.PrimaryStage() { 26 | title = "FXML GridPane Demo" 27 | scene = new Scene(root) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /properties/src/main/scala/org/scalafx/tutorials/properties/WhenChooseOtherwiseExpression.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.tutorials.properties 2 | 3 | import scalafx.Includes._ 4 | import scalafx.application.JFXApp3 5 | import scalafx.scene.Scene 6 | import scalafx.scene.paint.Color 7 | import scalafx.scene.shape.Rectangle 8 | 9 | /** 10 | * Example use of `when/choose/otherwise` binding expression.. 11 | */ 12 | object WhenChooseOtherwiseExpression extends JFXApp3 { 13 | override def start(): Unit = { 14 | stage = new JFXApp3.PrimaryStage { 15 | title.value = "when/choose/otherwise" 16 | width = 400 17 | height = 300 18 | scene = new Scene { 19 | fill = Color.LightGreen 20 | content = new Rectangle { 21 | x = 25 22 | y = 40 23 | width = 100 24 | height = 100 25 | fill <== when(hover) choose Color.Green otherwise Color.Red 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scalafxml-example/src/main/scala/sfxml/AdoptionFormPresenter.scala: -------------------------------------------------------------------------------- 1 | package sfxml 2 | 3 | import scalafx.event.ActionEvent 4 | import scalafx.scene.control.{ChoiceBox, TextArea, TextField} 5 | import scalafx.scene.layout.GridPane 6 | import scalafxml.core.macros.sfxml 7 | 8 | @sfxml 9 | class AdoptionFormPresenter(private val sizeTextField: TextField, 10 | private val breedTextField: TextField, 11 | private val sexChoiceBox: ChoiceBox[String], 12 | private val additionalInfoTextArea: TextArea, 13 | private val grid: GridPane) { 14 | 15 | def handleSubmit(event: ActionEvent): Unit = { 16 | grid.gridLinesVisible() = !grid.gridLinesVisible() 17 | } 18 | 19 | def handleClear(event: ActionEvent): Unit = { 20 | sizeTextField.text = "" 21 | breedTextField.text = "" 22 | sexChoiceBox.selectionModel().clearSelection() 23 | additionalInfoTextArea.text = "" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/ListViewSimpleDemo.scala: -------------------------------------------------------------------------------- 1 | package cell_factories 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.application.JFXApp3.PrimaryStage 5 | import scalafx.collections.ObservableBuffer 6 | import scalafx.scene.Scene 7 | import scalafx.scene.control.ListView 8 | 9 | object ListViewSimpleDemo extends JFXApp3 { 10 | 11 | case class Person(firstName: String, lastName: String) 12 | 13 | override def start(): Unit = { 14 | case class Person(firstName: String, lastName: String) 15 | val characters = ObservableBuffer[Person]( 16 | Person("Bungalow ", "Bill"), 17 | Person("Dennis", "O\u2019Dell"), 18 | Person("Eleanor", "Rigby"), 19 | Person("Rocky", "Raccoon"), 20 | Person("Peggy", "Sue") 21 | ) 22 | stage = new PrimaryStage { 23 | title = "ListView with Selection Demo" 24 | scene = new Scene { 25 | content = new ListView[Person] { 26 | items = characters 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/ComboBoxCellFactoryDemo.scala: -------------------------------------------------------------------------------- 1 | package cell_factories 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.geometry.Insets 5 | import scalafx.scene.Scene 6 | import scalafx.scene.control.ComboBox 7 | import scalafx.scene.layout.VBox 8 | import scalafx.util.StringConverter 9 | 10 | /** 11 | * https://groups.google.com/forum/#!topic/scalafx-users/jDuMETUx3fY 12 | */ 13 | object ComboBoxCellFactoryDemo extends JFXApp3 { 14 | 15 | case class Herd(name: String) 16 | 17 | override def start(): Unit = { 18 | val items: Seq[Herd] = Seq(Herd("A"), Herd("B"), Herd("C"), Herd("D"), Herd("E")) 19 | 20 | stage = new JFXApp3.PrimaryStage { 21 | scene = new Scene(200, 100) { 22 | title = "ComboBox CellFactory Demo" 23 | root = new VBox { 24 | children = new ComboBox[Herd](items) { 25 | converter = StringConverter.toStringConverter((h: Herd) => h.name) 26 | selectionModel.value.select(2) 27 | } 28 | padding = Insets(14, 14, 14, 14) 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/CheckBoxListCellDemo.scala: -------------------------------------------------------------------------------- 1 | package cell_factories 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.beans.property.BooleanProperty 5 | import scalafx.collections.ObservableBuffer 6 | import scalafx.scene.Scene 7 | import scalafx.scene.control.ListView 8 | import scalafx.scene.control.cell.CheckBoxListCell 9 | import scalafx.scene.layout.VBox 10 | 11 | object CheckBoxListCellDemo extends JFXApp3 { 12 | 13 | class Item(initialSelection: Boolean, val name: String) { 14 | val selected: BooleanProperty = BooleanProperty(initialSelection) 15 | 16 | override def toString: String = name 17 | } 18 | 19 | // Create sample data 20 | private val data = 21 | ObservableBuffer 22 | .from((1 to 10) 23 | .map(i => new Item(i % 2 == 0, s"Item $i"))) 24 | 25 | override def start(): Unit = { 26 | stage = new JFXApp3.PrimaryStage { 27 | scene = new Scene { 28 | title = "CheckBoxListCell Demo" 29 | root = new VBox { 30 | children = Seq( 31 | new ListView[Item] { 32 | prefHeight = 250 33 | items = data 34 | cellFactory = CheckBoxListCell.forListView[Item](_.selected) 35 | } 36 | ) 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/ListViewCustomDemo.scala: -------------------------------------------------------------------------------- 1 | package cell_factories 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.application.JFXApp3.PrimaryStage 5 | import scalafx.collections.ObservableBuffer 6 | import scalafx.scene.Scene 7 | import scalafx.scene.control.ListView 8 | import scalafx.scene.paint.Color 9 | import scalafx.scene.shape.Circle 10 | 11 | object ListViewCustomDemo extends JFXApp3 { 12 | 13 | case class Person(firstName: String, lastName: String) 14 | 15 | override def start(): Unit = { 16 | case class Person(firstName: String, lastName: String, color: Color) 17 | val characters = ObservableBuffer[Person]( 18 | Person("Bungalow ", "Bill", Color.DodgerBlue), 19 | Person("Dennis", "O'Dell", Color.Brown), 20 | Person("Eleanor", "Rigby", Color.Olive), 21 | Person("Rocky", "Raccoon", Color.DarkCyan), 22 | Person("Peggy", "Sue", Color.Coral) 23 | ) 24 | stage = new PrimaryStage { 25 | title = "ListView with Selection Demo" 26 | scene = new Scene { 27 | content = new ListView[Person] { 28 | items = characters 29 | 30 | cellFactory = (cell, value) => { 31 | cell.text = s"${value.firstName} ${value.lastName}" 32 | cell.graphic = new Circle { 33 | fill = value.color 34 | radius = 4 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /stand-alone-dialog/src/main/scala/stand_alone_dialog/StandAloneFXDialog.scala: -------------------------------------------------------------------------------- 1 | package stand_alone_dialog 2 | 3 | import javafx.embed.swing.JFXPanel 4 | import scalafx.application.Platform 5 | import scalafx.geometry.Insets 6 | import scalafx.scene.Scene 7 | import scalafx.scene.control.Button 8 | import scalafx.scene.layout.BorderPane 9 | import scalafx.stage.Stage 10 | 11 | 12 | /** Example of displaying an FX dialog without starting an FX application. 13 | * Dialog is displayed in a "non-modal" manner (thread from which dialog is displayed is not blocked). 14 | */ 15 | object StandAloneFXDialog extends App { 16 | 17 | // Shortcut to initialize JavaFX, force initialization by creating JFXPanel() object 18 | // (we will not use it for anything else) 19 | new JFXPanel() 20 | 21 | // Create a dialog stage and display it on JavaFX Application Thread 22 | Platform.runLater { 23 | 24 | // Create dialog 25 | val dialogStage = new Stage { 26 | outer => 27 | title = "Stand-Alone Dialog" 28 | scene = new Scene { 29 | root = new BorderPane { 30 | padding = Insets(25) 31 | bottom = new Button { 32 | text = "Click me to close the dialog" 33 | onAction = _ => outer.close() 34 | } 35 | } 36 | } 37 | } 38 | 39 | // Show dialog and wait till it is closed 40 | dialogStage.showAndWait() 41 | 42 | // Force application exit 43 | Platform.exit() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sam_event_handlers/Readme.md: -------------------------------------------------------------------------------- 1 | SAM Event Handlers 2 | ================== 3 | 4 | Syntax for event handlers in ScalaFX can be simplifies using new SAM (Single Abstract Method) feature of the Scala 2.11 5 | compiler. This corresponds to Java 8 syntax for using lambdas instead implementing interfaces with simple abstract 6 | method, like `Runnable`. For instance rather than creating anonymous class implementing `Runnable`, in Java 8, we can 7 | pass a lambda: 8 | 9 | ```java 10 | new Thread(()->println("hi")).run() 11 | ``` 12 | 13 | In Scala 2.11 you can do it too when you enable experimental features of the compiler: 14 | 15 | ```scala 16 | scalacOptions += "-Xexperimental" 17 | ``` 18 | 19 | Here is a complete example using SAM for an event handler, exactly the way you were asking for: 20 | 21 | ```scala 22 | import scalafx.application.JFXApp3 23 | import scalafx.scene.Scene 24 | import scalafx.scene.control.Button 25 | import scalafx.scene.layout.HBox 26 | 27 | object SAMDemo extends JFXApp3 { 28 | 29 | override def start(): Unit = { 30 | stage = new JFXApp3.PrimaryStage { 31 | title = "SAM Demo" 32 | scene = new Scene { 33 | root = new HBox { 34 | children = Seq( 35 | new Button { 36 | text = "Print message" 37 | onAction = _ => println("some message") 38 | } 39 | ) 40 | } 41 | } 42 | } 43 | } 44 | } 45 | 46 | ``` 47 | 48 | Note the imports used. There is nothing related to event handling. You can import it but it is not necessary as the 49 | handler is created by Scala compiler using SAM feature. -------------------------------------------------------------------------------- /stand-alone-dialog/src/main/scala/stand_alone_dialog/DialogBeforePrimaryStage.scala: -------------------------------------------------------------------------------- 1 | package stand_alone_dialog 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.geometry.Insets 5 | import scalafx.scene.Scene 6 | import scalafx.scene.control.Label 7 | import scalafx.scene.layout.BorderPane 8 | import scalafx.stage.{FileChooser, Stage} 9 | 10 | /** 11 | * Example of displaying a dialog before primary stage is displayed. 12 | */ 13 | object DialogBeforePrimaryStage extends JFXApp3 { 14 | 15 | override def start(): Unit = { 16 | // Do something with command line arguments here we print them 17 | // Named arguments have a form: --name=value 18 | // For instance, "--output=alpha beta" is interpreted as named argument "output" with value "alpha" 19 | // and unnamed parameter "beta". 20 | println("Commend line arguments:\n" + 21 | " unnamed: " + parameters.unnamed.mkString("[", ", ", "]") + "\n" + 22 | " named : " + parameters.named.mkString("[", ", ", "]")) 23 | 24 | // Show a dialog before primary stage is constructed 25 | val fileChooser = new FileChooser() 26 | val file = Option(fileChooser.showOpenDialog(new Stage())) 27 | 28 | // Primary stage is provided by JavaFX runtime, but you can create other stages of you need to. 29 | stage = new JFXApp3.PrimaryStage { 30 | scene = new Scene { 31 | root = new BorderPane { 32 | padding = Insets(25) 33 | center = new Label { 34 | text = file match { 35 | case Some(f) => "Selected file: " + f.getPath 36 | case None => "File not selected." 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/MyTreeViewCellFactoryDemo.scala: -------------------------------------------------------------------------------- 1 | package cell_factories 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.collections.ObservableBuffer 5 | import scalafx.scene.Scene 6 | import scalafx.scene.control._ 7 | 8 | /** 9 | * https://groups.google.com/forum/#!topic/scalafx-users/jDuMETUx3fY 10 | */ 11 | object MyTreeViewCellFactoryDemo extends JFXApp3 { 12 | 13 | case class Person(firstName: String, lastName: String, children: List[Person] = Nil) 14 | 15 | def toTreeItem(p: Person): TreeItem[Person] = { 16 | if (p.children.isEmpty) new TreeItem(p) 17 | else new TreeItem(p) { 18 | children = p.children map toTreeItem 19 | } 20 | } 21 | 22 | override def start(): Unit = { 23 | val children1 = List( 24 | Person("Bungalow", "Bill"), 25 | Person("Dennis", "O’Dell"), 26 | Person("Peggy", "Sue"), 27 | Person("Molly", "Jones") 28 | ) 29 | 30 | val children2 = List( 31 | Person("Maxwell", "Edison"), 32 | Person("Desmond", "Jones"), 33 | Person("Loretta", "Martin") 34 | ) 35 | 36 | val parents = ObservableBuffer[Person]( 37 | Person("Eleanor", "Rigby", children1), 38 | Person("Rocky", "Raccoon", children2) 39 | ) 40 | 41 | stage = new JFXApp3.PrimaryStage { 42 | title = "TreeView CellFactory Demo" 43 | scene = new Scene { 44 | content = new TreeView[Person] { 45 | prefWidth = 250 46 | prefHeight = 250 47 | showRoot = false 48 | root = new TreeItem[Person] { 49 | expanded = true 50 | children = parents.map(toTreeItem).toSeq 51 | } 52 | cellFactory = (cell, value) => { 53 | cell.text = value.firstName + " " + value.lastName 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /slick-table/src/main/scala/org/scalafx/slick_table/ContactsView.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.slick_table 2 | 3 | import scalafx.Includes._ 4 | import scalafx.geometry.Insets 5 | import scalafx.scene.Parent 6 | import scalafx.scene.control._ 7 | import scalafx.scene.layout.BorderPane 8 | import scalafx.scene.text.Font 9 | 10 | /** 11 | * Created main view and connects it to the view model. 12 | */ 13 | class ContactsView(val model: ContactsViewModel) { 14 | 15 | val title = "Address Book" 16 | 17 | private val table: TableView[Person] = { 18 | // Define columns 19 | val firstNameColumn = new TableColumn[Person, String] { 20 | text = "First name" 21 | cellValueFactory = { 22 | _.value.firstName 23 | } 24 | prefWidth = 180 25 | } 26 | 27 | val lastNameColumn = new TableColumn[Person, String] { 28 | text = "Last name" 29 | cellValueFactory = { 30 | _.value.lastName 31 | } 32 | prefWidth = 180 33 | } 34 | 35 | val emailColumn = new TableColumn[Person, String] { 36 | text = "email address" 37 | cellValueFactory = { 38 | _.value.emailAddress 39 | } 40 | prefWidth = 250 41 | } 42 | 43 | // Build the table 44 | new TableView[Person](model.items) { 45 | columns ++= Seq(firstNameColumn, lastNameColumn, emailColumn) 46 | margin = Insets(10, 0, 10, 0) 47 | } 48 | } 49 | 50 | model.selectedItems = table.selectionModel.value.selectedItems 51 | 52 | private val addButton = new Button { 53 | text = "Add" 54 | onAction = _ => model.onAddItem() 55 | } 56 | 57 | private val removeButton = new Button { 58 | text = "Remove" 59 | disable <== !model.canRemoveRow 60 | onAction = _ => model.onRemove() 61 | } 62 | 63 | private val resetButton = new Button { 64 | text = "Reset" 65 | onAction = _ => model.onReset() 66 | } 67 | 68 | val view: Parent = { 69 | 70 | val label = new Label(title) { 71 | font = Font("Arial", 20) 72 | } 73 | 74 | val buttonBar = new ButtonBar { 75 | buttons = Seq(addButton, removeButton, resetButton) 76 | } 77 | 78 | new BorderPane { 79 | top = label 80 | center = table 81 | bottom = buttonBar 82 | padding = Insets(10, 10, 10, 10) 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /stand-alone-dialog/src/main/scala/stand_alone_dialog/StandAloneFXDialogRunAndWait.scala: -------------------------------------------------------------------------------- 1 | package stand_alone_dialog 2 | 3 | import javafx.embed.swing.JFXPanel 4 | import scalafx.application.Platform 5 | import scalafx.geometry.Insets 6 | import scalafx.scene.Scene 7 | import scalafx.scene.control.Button 8 | import scalafx.scene.layout.BorderPane 9 | import scalafx.stage.Stage 10 | 11 | 12 | /** Example of displaying an FX dialog without starting an FX application. 13 | * Dialog is displayed in a "modal" manner (blocks the invoking thread till dialog is closed). 14 | * Blocking of the invoking thread is done using `FXUtils.runAndWait` method. 15 | */ 16 | object StandAloneFXDialogRunAndWait extends App { 17 | 18 | // Prevent JavaFX from auto exiting, it may happen after first dialog is closed and before second is opened. 19 | Platform.implicitExit = false 20 | 21 | // Shortcut to initialize JavaFX, force initialization by creating JFXPanel() object 22 | // (we will not use it for anything else) 23 | new JFXPanel() 24 | 25 | // Create the first dialog stage and display it on JavaFX Application Thread 26 | // Wait for the dialog to close before proceeding 27 | FXUtils.onFXAndWait { 28 | showInDialog("Click me to close the FIRST dialog") 29 | } 30 | 31 | println("First dialog closed.") 32 | 33 | // Create the second dialog stage and display it on JavaFX Application Thread 34 | // Wait for the dialog to close before proceeding 35 | FXUtils.onFXAndWait { 36 | showInDialog("Click me to close the SECOND dialog") 37 | } 38 | 39 | println("First dialog closed.") 40 | 41 | // Tell JavaFX that we want to exit. 42 | Platform.exit() 43 | 44 | 45 | /** Show a `message` in a dialog box, wait till dialog is closed */ 46 | private def showInDialog(message: String): Unit = { 47 | // Create dialog 48 | val dialogStage = new Stage { 49 | outer => 50 | title = "Stand-Alone Dialog - runAndWait" 51 | scene = new Scene { 52 | root = new BorderPane { 53 | padding = Insets(25) 54 | bottom = new Button { 55 | text = message 56 | onAction = _ => outer.close() 57 | } 58 | } 59 | } 60 | } 61 | 62 | // Show dialog and wait till it is closed 63 | dialogStage.showAndWait() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/ColorCharactersInTableView.scala: -------------------------------------------------------------------------------- 1 | package cell_factories 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.beans.property.StringProperty 5 | import scalafx.collections.ObservableBuffer 6 | import scalafx.scene.control.TableColumn._ 7 | import scalafx.scene.control.{TableColumn, TableView} 8 | import scalafx.scene.layout.{HBox, VBox} 9 | import scalafx.scene.paint.Color 10 | import scalafx.scene.text.Text 11 | import scalafx.scene.{Node, Scene} 12 | 13 | object ColorCharactersInTableView extends JFXApp3 { 14 | 15 | class Person(firstName_ : String, lastName_ : String) { 16 | val firstName = new StringProperty(this, "firstName", firstName_) 17 | val lastName = new StringProperty(this, "lastName", lastName_) 18 | } 19 | 20 | private val characters = ObservableBuffer[Person]( 21 | new Person("Peggy", "Sue"), 22 | new Person("Rocky", "Raccoon"), 23 | new Person("Bill", "Bungalow") 24 | ) 25 | 26 | /** Render string as colored text */ 27 | def createColorText(name: String): Node = { 28 | val texts = name.map { char => 29 | val color = char.toLower match { 30 | case 'r' => Color.Red 31 | case 'g' => Color.Green 32 | case 'b' => Color.Blue 33 | case _ => Color.Black 34 | } 35 | new Text { 36 | text = char.toString 37 | fill = color 38 | } 39 | } 40 | new HBox(texts: _*) 41 | } 42 | 43 | private val firstNameColumn = new TableColumn[Person, String] { 44 | text = "First Name" 45 | cellValueFactory = _.value.firstName 46 | cellFactory = (cell, value) => { 47 | cell.graphic = createColorText(value) 48 | } 49 | prefWidth = 180 50 | } 51 | 52 | private val lastNameColumn = new TableColumn[Person, String]() { 53 | text = "Last Name" 54 | cellValueFactory = _.value.lastName 55 | // TableColumn renders cell values as String by default, so we do not need call factory here 56 | prefWidth = 180 57 | } 58 | 59 | override def start(): Unit = { 60 | val tableView = new TableView[Person]() { 61 | columns ++= Seq(firstNameColumn, lastNameColumn) 62 | } 63 | stage = new JFXApp3.PrimaryStage { 64 | title = "Table View with Color Text - ScalaFX way" 65 | scene = new Scene { 66 | root = new VBox { 67 | children = Seq(tableView) 68 | } 69 | } 70 | } 71 | 72 | tableView.items = characters 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /slick-table/src/main/scala/org/scalafx/slick_table/SlickTableDemo.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.slick_table 2 | 3 | import scalafx.application.JFXApp3 4 | import scalafx.geometry.{Insets, Pos} 5 | import scalafx.scene.Scene 6 | import scalafx.scene.control.Alert.AlertType 7 | import scalafx.scene.control.{Alert, Label, ProgressIndicator} 8 | import scalafx.scene.layout.{BorderPane, StackPane, VBox} 9 | 10 | /** 11 | * Basic example of using a table view with database interfaced through Slick API. 12 | * The implementation is separated into a domain model `ContactsDB`, 13 | * main view definition `ContactsView`, the main view model `ContactsViewModel`. 14 | */ 15 | object SlickTableDemo extends JFXApp3 { 16 | 17 | // Catch unhandled exceptions on FX Application thread 18 | Thread.currentThread().setUncaughtExceptionHandler((_: Thread, ex: Throwable) => { 19 | ex.printStackTrace() 20 | new Alert(AlertType.Error) { 21 | initOwner(owner) 22 | title = "Unhandled exception" 23 | headerText = "Exception: " + ex.getClass + "" 24 | contentText = Option(ex.getMessage).getOrElse("") 25 | }.showAndWait() 26 | }) 27 | 28 | override def start(): Unit = { 29 | 30 | // Create application components 31 | val contactsViewModel = new ContactsViewModel() 32 | val contactsView = new ContactsView(contactsViewModel) 33 | 34 | val glassPane = new VBox { 35 | children = new ProgressIndicator { 36 | progress = ProgressIndicator.IndeterminateProgress 37 | visible = true 38 | } 39 | alignment = Pos.Center 40 | visible = false 41 | } 42 | 43 | val statusLabel = new Label { 44 | maxWidth = Double.MaxValue 45 | padding = Insets(0, 10, 10, 10) 46 | } 47 | 48 | val rootView = new StackPane { 49 | children = Seq( 50 | new BorderPane { 51 | center = contactsView.view 52 | bottom = statusLabel 53 | }, 54 | glassPane 55 | ) 56 | } 57 | 58 | stage = new JFXApp3.PrimaryStage { 59 | title = contactsView.title 60 | scene = new Scene(rootView) 61 | } 62 | 63 | val taskRunner = new TaskRunner(contactsView.view, glassPane, statusLabel) 64 | contactsViewModel.taskRunner = taskRunner 65 | 66 | // Initialize database on a separate thread 67 | taskRunner.run( 68 | caption = "Setup Database", 69 | op = { 70 | contactsViewModel.setUp() 71 | } 72 | ) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /slick-table/src/main/scala/org/scalafx/slick_table/AddContactDialog.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.slick_table 2 | 3 | import scalafx.Includes._ 4 | import scalafx.application.Platform 5 | import scalafx.geometry.Insets 6 | import scalafx.scene.control._ 7 | import scalafx.scene.layout.GridPane 8 | import scalafx.stage.Window 9 | 10 | /** 11 | * Creates and displays an Add Contact dialog. 12 | */ 13 | object AddContactDialog { 14 | 15 | def showAndWait(parentWindow: Window): Option[Person] = { 16 | // Create the custom dialog. 17 | val dialog = new Dialog[Person]() { 18 | initOwner(parentWindow) 19 | title = "Add New Contact" 20 | headerText = "Enter contact details" 21 | } 22 | 23 | // Set the button types. 24 | dialog.dialogPane().buttonTypes = Seq(ButtonType.OK, ButtonType.Cancel) 25 | 26 | // Create the username and password labels and fields. 27 | val firstNameTextField = new TextField() 28 | val lastNameTextField = new TextField() 29 | val emailTextField = new TextField() 30 | 31 | dialog.dialogPane().content = new GridPane { 32 | hgap = 10 33 | vgap = 10 34 | padding = Insets(20, 100, 10, 10) 35 | 36 | add(new Label("First name:"), 0, 0) 37 | add(firstNameTextField, 1, 0) 38 | add(new Label("Last name:"), 0, 1) 39 | add(lastNameTextField, 1, 1) 40 | add(new Label("email:"), 0, 2) 41 | add(emailTextField, 1, 2) 42 | } 43 | 44 | // Enable/Disable OK button depending on whether all data was entered. 45 | val okButton = dialog.dialogPane().lookupButton(ButtonType.OK) 46 | // Simple validation that sufficient data was entered 47 | okButton.disable <== (firstNameTextField.text.isEmpty || 48 | lastNameTextField.text.isEmpty || emailTextField.text.isEmpty) 49 | 50 | // Request focus on the first name field by default. 51 | Platform.runLater(firstNameTextField.requestFocus()) 52 | 53 | // When the OK button is clicked, convert the result to a Person. 54 | dialog.resultConverter = dialogButton => 55 | if (dialogButton == ButtonType.OK) 56 | Person(None, firstNameTextField.text(), lastNameTextField.text(), emailTextField.text()) 57 | else 58 | null 59 | 60 | val result = dialog.showAndWait() 61 | 62 | // Clean up result type 63 | result match { 64 | case Some(Person(is, first, last, email)) => Some(Person(is, first, last, email)) 65 | case _ => None 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ScalaFX-Tutorials 2 | ================= 3 | 4 | [![Scala CI](https://github.com/scalafx/ScalaFX-Tutorials/actions/workflows/scala.yml/badge.svg)](https://github.com/scalafx/ScalaFX-Tutorials/actions/workflows/scala.yml) 5 | 6 | Examples of using ScalaFX. Each example is a stand-alone complete project 7 | 8 | * [__hello-sbt__](hello-sbt): 9 | a basic example of using [Simple-Build-Tool](http://www.scala-sbt.org/) (SBT) and 10 | [ScalaFX](http://scalafx.org). Detailed description can be found in the blog post 11 | ["Getting Started with ScalaFX: Compile and Run"](http://codingonthestaircase.wordpress.com/2013/05/17/getting-started-with-scalafx-compile-and-run-2/) 12 | . 13 | 14 | * [__cell_factories__](cell_factories) - examples of using cell factories, including custom cell factories. 15 | 16 | * [__event-filters__](event-filters): 17 | demonstrates use of ScalaFX Event Filter API. The code is based on JavaFX example 18 | [Handling JavaFX Events, Part 3 Working with Event Filters](http://docs.oracle.com/javafx/2/events/filters.htm). 19 | 20 | * [__molecule-3d__](molecule-3d): 21 | ScalaFX 8 example of using 3D graphics. Based on tutorial 22 | [Getting Started with JavaFX 3D Graphics](http://docs.oracle.com/javafx/8/3d_graphics/jfxpub-3d_graphics.htm) 23 | by Cindy Castillo and John Yoon. 24 | 25 | * [__sam_event_handlers__](sam_event_handlers): 26 | Scala 2.11 provides for Java8-like support for using lambdas in places of interfaces with a Single Abstract Method ( 27 | SAM). The example shows required compiler options and use with ScalaFX. 28 | 29 | * [__scalafxml-example__](scalafxml-example): 30 | demonstrates use of FXML with ScalaFX using [ScalaFXML](https://github.com/vigoo/scalafxml) 31 | library. 32 | 33 | * [__Slick-table__](slick-table): An example of using a table view with database interfaced 34 | through [Slick](http://slick.lightbend.com/) API. 35 | 36 | * [__splash-demo__](splash-demo): Displays a splash stage with a progress bar during startup then opens main application 37 | stage. 38 | 39 | * [__SpreadsheetView__](spreadsheetview): Examples of 40 | using [ContolsFX SpreadsheetView](https://github.com/controlsfx/controlsfx/wiki/ControlsFX-Features#spreadsheetview) 41 | from ScalaFX. 42 | 43 | * [__stand-alone-dialog__](stand-alone-dialog): 44 | shows how to display a ScalaFX dialog (stage) without using `JFXApp3`. You can use this approach, for instance, to 45 | show a JavaFX dialog from a command line or from a Swing application. 46 | -------------------------------------------------------------------------------- /splash-demo/src/main/scala/splash_demo/Splash.scala: -------------------------------------------------------------------------------- 1 | package splash_demo 2 | 3 | import scalafx.Includes._ 4 | import scalafx.animation.FadeTransition 5 | import scalafx.concurrent.{Task, Worker} 6 | import scalafx.geometry.Pos 7 | import scalafx.scene.Scene 8 | import scalafx.scene.control.{Label, ProgressBar} 9 | import scalafx.scene.effect.DropShadow 10 | import scalafx.scene.image.{Image, ImageView} 11 | import scalafx.scene.layout.VBox 12 | import scalafx.stage.{Screen, Stage, StageStyle} 13 | 14 | /** 15 | */ 16 | object Splash { 17 | 18 | private val SplashImage = "http://fxexperience.com/wp-content/uploads/2010/06/logo.png" 19 | private val SplashWidth = 676 20 | private val SplashHeight = 227 21 | 22 | private val splash = new ImageView(new Image(SplashImage)) 23 | private val loadProgress = new ProgressBar { 24 | prefWidth = SplashWidth - 20 25 | } 26 | private val progressText = new Label("Will find friends for peanuts . . .") { 27 | alignment = Pos.Center 28 | } 29 | private val splashLayout = new VBox() { 30 | children ++= Seq(splash, loadProgress, progressText) 31 | style = 32 | "-fx-padding: 5; " + 33 | "-fx-background-color: cornsilk; " + 34 | "-fx-border-width:5; " + 35 | "-fx-border-color: " + 36 | "linear-gradient(" + 37 | "to bottom, " + 38 | "chocolate, " + 39 | "derive(chocolate, 50%)" + 40 | ");" 41 | effect = new DropShadow() 42 | } 43 | 44 | def show(splashStage: Stage, loaderTask: Task[_], onSuccess: () => Unit): Unit = { 45 | progressText.text <== loaderTask.message 46 | loadProgress.progress <== loaderTask.progress 47 | loaderTask.state.onChange { (_, _, newState) => 48 | newState match { 49 | case Worker.State.Succeeded.delegate => 50 | loadProgress.progress.unbind() 51 | loadProgress.progress = 1 52 | new FadeTransition(0.5.s, splashLayout) { 53 | fromValue = 1.0 54 | toValue = 0.0 55 | onFinished = _ => splashStage.hide() 56 | }.play() 57 | 58 | onSuccess() 59 | 60 | case _ => 61 | // TODO: handle other states 62 | } 63 | } 64 | 65 | 66 | splashStage.initStyle(StageStyle.Undecorated) 67 | splashStage.alwaysOnTop = true 68 | splashStage.scene = new Scene(splashLayout) 69 | val bounds = Screen.primary.bounds 70 | splashStage.x = bounds.minX + bounds.width / 2 - SplashWidth / 2 71 | splashStage.y = bounds.minY + bounds.height / 2 - SplashHeight / 2 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /splash-demo/src/main/scala/splash_demo/SplashDemoApp.scala: -------------------------------------------------------------------------------- 1 | package splash_demo 2 | 3 | import javafx.{collections => jfxc, concurrent => jfxr} 4 | import scalafx.Includes._ 5 | import scalafx.application.JFXApp3 6 | import scalafx.beans.property.ReadOnlyObjectProperty 7 | import scalafx.collections.ObservableBuffer 8 | import scalafx.scene.Scene 9 | import scalafx.scene.control.ListView 10 | import scalafx.scene.image.Image 11 | import scalafx.stage.{Stage, StageStyle} 12 | 13 | import scala.language.postfixOps 14 | 15 | /** 16 | * Splash screen demo based JavaFX version from [[https://gist.github.com/jewelsea/2305098]] 17 | */ 18 | object SplashDemoApp extends JFXApp3 { 19 | 20 | private val ApplicationIcon = "http://cdn1.iconfinder.com/data/icons/Copenhagen/PNG/32/people.png" 21 | 22 | private val friendTask = new jfxr.Task[jfxc.ObservableList[String]]() { 23 | 24 | protected def call: jfxc.ObservableList[String] = { 25 | val foundFriends = new ObservableBuffer[String]() 26 | val availableFriends = ObservableBuffer[String]( 27 | "Fili", 28 | "Kili", 29 | "Oin", 30 | "Gloin", 31 | "Thorin", 32 | "Dwalin", 33 | "Balin", 34 | "Bifur", 35 | "Bofur", 36 | "Bombur", 37 | "Dori", 38 | "Nori", 39 | "Ori" 40 | ) 41 | 42 | updateMessage("Finding friends . . .") 43 | 44 | for (i <- availableFriends.indices) { 45 | Thread.sleep(400) 46 | updateProgress(i + 1, availableFriends.size) 47 | val nextFriend = availableFriends.get(i) 48 | foundFriends += nextFriend 49 | updateMessage("Finding friends . . . found " + nextFriend) 50 | } 51 | Thread.sleep(400) 52 | updateMessage("All friends found.") 53 | foundFriends 54 | } 55 | } 56 | 57 | override def start(): Unit = { 58 | // Show splash stage 59 | Splash.show(new JFXApp3.PrimaryStage(), friendTask, () => showMainStage(friendTask.value)) 60 | 61 | // Start background task, splash stage will fade when the task is done 62 | new Thread(friendTask).start() 63 | } 64 | 65 | private def showMainStage(friends: ReadOnlyObjectProperty[jfxc.ObservableList[String]]): Unit = { 66 | val mainStage = new Stage(StageStyle.Decorated) { 67 | title = "My Friends" 68 | icons += new Image(ApplicationIcon) 69 | } 70 | 71 | val peopleView = new ListView[String] { 72 | items <== friends 73 | } 74 | mainStage.scene = new Scene(peopleView) 75 | mainStage.show() 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /slick-table/src/main/scala/org/scalafx/slick_table/TaskRunner.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.slick_table 2 | 3 | import javafx.{concurrent => jfxc} 4 | 5 | import scalafx.application.Platform 6 | import scalafx.scene.Node 7 | import scalafx.scene.control.Alert.AlertType 8 | import scalafx.scene.control.{Alert, Label} 9 | 10 | /** 11 | * Runs a background task disabling the `mainView` and main visible `glassPane`. 12 | * Shows statis using `statusLabel`. 13 | */ 14 | class TaskRunner(mainView: Node, 15 | glassPane: Node, 16 | statusLabel: Label) { 17 | 18 | /** 19 | * Run an operation on a separate thread. Return and wait for its completion, 20 | * then return result of running that operation. 21 | * 22 | * A progress indicator is displayed while running the operation. 23 | * 24 | * @param caption name for the thread (useful in debugging) and status displayed 25 | * when running the task. 26 | * @param op operation to run. 27 | * @tparam R type of result returned by the operation. 28 | * @return result returned by operation `op`. 29 | */ 30 | def run[R](caption: String, 31 | op: => R): Unit = { 32 | 33 | def showProgress(progressEnabled: Boolean): Unit = { 34 | mainView.disable = progressEnabled 35 | glassPane.visible = progressEnabled 36 | } 37 | 38 | // Indicate task in progress 39 | Platform.runLater { 40 | showProgress(true) 41 | statusLabel.text = caption 42 | } 43 | 44 | val task = new jfxc.Task[R] { 45 | override def call(): R = { 46 | op 47 | } 48 | override def succeeded(): Unit = { 49 | showProgress(false) 50 | statusLabel.text = caption + " - Done." 51 | // Do callback, of defined 52 | } 53 | override def failed(): Unit = { 54 | 55 | showProgress(false) 56 | statusLabel.text = caption + " - Failed." 57 | val t = Option(getException) 58 | t.foreach(_.printStackTrace()) 59 | // Show error message 60 | new Alert(AlertType.Error) { 61 | initOwner(owner) 62 | title = caption 63 | headerText = "Operation failed. " + t.map("Exception: " + _.getClass).getOrElse("") 64 | contentText = t.map(_.getMessage).getOrElse("") 65 | }.showAndWait() 66 | } 67 | override def cancelled(): Unit = { 68 | showProgress(false) 69 | statusLabel.text = caption + " - Cancelled." 70 | } 71 | } 72 | 73 | val th = new Thread(task, caption) 74 | th.setDaemon(true) 75 | th.start() 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/EditableTableView.scala: -------------------------------------------------------------------------------- 1 | package cell_factories 2 | 3 | import scalafx.Includes._ 4 | import scalafx.application.JFXApp3 5 | import scalafx.beans.property.StringProperty 6 | import scalafx.collections.ObservableBuffer 7 | import scalafx.scene.Scene 8 | import scalafx.scene.control.TableColumn._ 9 | import scalafx.scene.control.cell.TextFieldTableCell 10 | import scalafx.scene.control.{Button, TableColumn, TableView} 11 | import scalafx.scene.layout.VBox 12 | 13 | /** 14 | * Example for StackOverflow question "how to create an updateable tableview cell in Scala" 15 | * [[https://stackoverflow.com/questions/33733341/how-to-create-an-updateable-tableview-cell-in-scala]] 16 | */ 17 | object EditableTableView extends JFXApp3 { 18 | 19 | class Person(firstName_ : String, lastName_ : String) { 20 | 21 | val firstName = new StringProperty(this, "firstName", firstName_) 22 | val lastName = new StringProperty(this, "lastName", lastName_) 23 | 24 | firstName.onChange { (_, oldValue, newValue) => println(s"Value changed from `$oldValue` to `$newValue`") } 25 | lastName.onChange { (_, oldValue, newValue) => println(s"Value changed from `$oldValue` to `$newValue`") } 26 | 27 | override def toString: String = firstName() + " " + lastName() 28 | } 29 | 30 | private val characters = ObservableBuffer[Person]( 31 | new Person("Peggy", "Sue"), 32 | new Person("Rocky", "Raccoon") 33 | ) 34 | 35 | override def start(): Unit = { 36 | 37 | val tableView = new TableView[Person](characters) { 38 | editable = true 39 | columns ++= List( 40 | new TableColumn[Person, String] { 41 | text = "First Name" 42 | cellValueFactory = _.value.firstName 43 | cellFactory = TextFieldTableCell.forTableColumn[Person]() 44 | prefWidth = 180 45 | }, 46 | new TableColumn[Person, String]() { 47 | text = "Last Name" 48 | cellValueFactory = _.value.lastName 49 | cellFactory = TextFieldTableCell.forTableColumn[Person]() 50 | prefWidth = 180 51 | } 52 | ) 53 | } 54 | 55 | stage = new JFXApp3.PrimaryStage { 56 | title = "Editable Table View" 57 | scene = new Scene { 58 | root = new VBox { 59 | children = Seq( 60 | tableView, 61 | new Button { 62 | text = "Print content" 63 | onAction = () => { 64 | println("Characters:") 65 | characters.foreach(println) 66 | } 67 | } 68 | ) 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /slick-table/src/main/scala/org/scalafx/slick_table/ContactsDB.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.slick_table 2 | 3 | import org.scalafx.slick_table.ContactsDB.Persons 4 | import slick.jdbc.H2Profile.api._ 5 | import slick.lifted.ProvenShape 6 | 7 | import scala.concurrent.Await 8 | import scala.concurrent.duration.Duration 9 | 10 | object ContactsDB { 11 | 12 | /** Definition of the Persons table */ 13 | class Persons(tag: Tag) extends Table[Person](tag, "PERSONS") { 14 | def id: Rep[Int] = column[Int]("ID", O.PrimaryKey, O.AutoInc) 15 | def first: Rep[String] = column[String]("FIRST") 16 | def last: Rep[String] = column[String]("LAST") 17 | def email: Rep[String] = column[String]("EMAIL") 18 | def * : ProvenShape[Person] = (id.?, first, last, email) <> (Person.tupled, Person.unapply) 19 | } 20 | 21 | } 22 | 23 | /** 24 | * Wrapper to simplify use of Slick API. It is the domain model for this application. 25 | */ 26 | class ContactsDB { 27 | 28 | private val persons: TableQuery[Persons] = TableQuery[Persons] 29 | 30 | private val samplePersons = Seq( 31 | Person(None, "Bungalow ", "Bill", "saxon@firce.not"), 32 | Person(None, "Dennis", "O’Dell", "lutn@sluggers.net"), 33 | Person(None, "Eleanor", "Rigby", "e.rigby@lonely.com"), 34 | Person(None, "Rocky", "Raccoon", "nancy@black_mining_hills.dak"), 35 | Person(None, "Peggy", "Sue", "sue.p@gerron.so") 36 | ) 37 | 38 | /** Setup the contacts database and create the Persons table */ 39 | def setup(): Unit = { 40 | run(persons.schema.create) 41 | } 42 | 43 | /** Add sample content of the Persons table */ 44 | def addSampleContent(): Unit = { 45 | add(samplePersons) 46 | } 47 | 48 | /** Remove all entries from the Persons table */ 49 | def clear(): Unit = { 50 | run(persons.delete) 51 | } 52 | 53 | /** Return current content of the Persons table */ 54 | def queryPersons(): Seq[Person] = { 55 | run(persons.to[Seq].result) 56 | } 57 | 58 | /** Add a person to the Persons table */ 59 | def add(p: Person): Unit = { 60 | add(Seq(p)) 61 | } 62 | 63 | /** Add items to the Persons table */ 64 | def add(items: Seq[Person]): Unit = { 65 | run(persons ++= items) 66 | } 67 | 68 | /** Remove items from Persons table */ 69 | def remove(items: Seq[Person]): Unit = { 70 | val qs = items.map { i => 71 | val q = persons.filter { p => 72 | p.first === i.first && p.last === i.last && p.email === i.email 73 | } 74 | q.delete 75 | } 76 | 77 | run(DBIO.seq(qs: _*)) 78 | } 79 | 80 | /** Perform database actions and wait for completion. */ 81 | private def run[R](actions: DBIOAction[R, NoStream, Nothing]): R = { 82 | val db = Database.forConfig("h2mem1") 83 | try { 84 | Await.result(db.run(actions), Duration.Inf) 85 | } finally { 86 | db.close() 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /cell_factories/src/main/scala/cell_factories/extras/SimpleTableView.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2016, ScalaFX Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the ScalaFX Project nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE SCALAFX PROJECT OR ITS CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | package cell_factories.extras 29 | 30 | import scalafx.application.JFXApp3 31 | import scalafx.beans.property.StringProperty 32 | import scalafx.collections.ObservableBuffer 33 | import scalafx.scene.Scene 34 | import scalafx.scene.control.TableColumn._ 35 | import scalafx.scene.control.{TableColumn, TableView} 36 | 37 | class Person(name_ : String) { 38 | val name = new StringProperty(this, "firstName", name_) 39 | } 40 | 41 | object SimpleTableView extends JFXApp3 { 42 | 43 | private val characters = ObservableBuffer[Person]( 44 | new Person("Peggy"), 45 | new Person("Rocky") 46 | ) 47 | 48 | override def start(): Unit = { 49 | 50 | stage = new JFXApp3.PrimaryStage { 51 | title = "Simple Table View" 52 | scene = new Scene { 53 | content = new TableView[Person](characters) { 54 | columns ++= List( 55 | new TableColumn[Person, String] { 56 | text = "First Name" 57 | cellValueFactory = { 58 | _.value.name 59 | } 60 | // cellFactory = (_: TableColumn[Person, String]) => new TextFieldTableCell[Person, String]() 61 | cellFactory = (cell, value) => cell.text = value 62 | prefWidth = 180 63 | } 64 | ) 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /slick-table/src/main/scala/org/scalafx/slick_table/ContactsViewModel.scala: -------------------------------------------------------------------------------- 1 | package org.scalafx.slick_table 2 | 3 | import scalafx.application.Platform 4 | import scalafx.beans.property.{BooleanProperty, ObjectProperty} 5 | import scalafx.collections.ObservableBuffer 6 | import scalafx.stage.Window 7 | 8 | /** 9 | * The view model. Defines UI actions and connection to the domain model - ContactsDB. 10 | */ 11 | class ContactsViewModel { 12 | 13 | var taskRunner: TaskRunner = _ 14 | 15 | private val contactsDB = new ContactsDB() 16 | 17 | val parentWindow: ObjectProperty[Window] = ObjectProperty[Window](null.asInstanceOf[Window]) 18 | 19 | // TODO: Only make public a read-only wrapper for `items` 20 | val items: ObservableBuffer[Person] = new ObservableBuffer[Person]() 21 | 22 | // Read-only collection of rows selected in the table view 23 | var _selectedItems: ObservableBuffer[Person] = _ 24 | def selectedItems: ObservableBuffer[Person] = _selectedItems 25 | def selectedItems_=(v: ObservableBuffer[Person]): Unit = { 26 | _selectedItems = v 27 | _selectedItems.onChange { 28 | canRemoveRow.value = selectedItems.nonEmpty 29 | } 30 | } 31 | 32 | val canRemoveRow = BooleanProperty(false) 33 | 34 | def setUp(): Unit = { 35 | items.clear() 36 | contactsDB.setup() 37 | contactsDB.addSampleContent() 38 | items ++= contactsDB.queryPersons() 39 | } 40 | 41 | def onAddItem(): Unit = { 42 | 43 | val result = AddContactDialog.showAndWait(parentWindow.value) 44 | 45 | result match { 46 | case Some(person) => 47 | taskRunner.run( 48 | caption = "Add Contact", 49 | op = { 50 | // Add new items from database 51 | contactsDB.add(person) 52 | // Return items from database 53 | val updatedItems = contactsDB.queryPersons() 54 | // Update items on FX thread 55 | Platform.runLater { 56 | updateItems(updatedItems) 57 | } 58 | } 59 | ) 60 | case _ => 61 | } 62 | } 63 | 64 | def onRemove(): Unit = { 65 | taskRunner.run( 66 | caption = "Remove Selection", 67 | op = { 68 | contactsDB.remove(selectedItems.toSeq) 69 | // Return items from database 70 | val updatedItems = contactsDB.queryPersons() 71 | // Update items on FX thread 72 | Platform.runLater { 73 | updateItems(updatedItems) 74 | } 75 | } 76 | ) 77 | } 78 | 79 | def onReset(): Unit = { 80 | taskRunner.run( 81 | caption = "Reset DB", 82 | op = { 83 | contactsDB.clear() 84 | contactsDB.addSampleContent() 85 | // Return items from database 86 | val updatedItems = contactsDB.queryPersons() 87 | // Update items on FX thread 88 | Platform.runLater { 89 | updateItems(updatedItems) 90 | } 91 | } 92 | ) 93 | } 94 | 95 | private def updateItems(updatedItems: Seq[Person]): Unit = { 96 | val toAdd = updatedItems.diff(items) 97 | val toRemove = items.diff(updatedItems) 98 | items ++= toAdd 99 | items --= toRemove 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /scalafxml-example/src/main/scala/sfxml/AdoptionForm.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |