You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
4.6 KiB

9 years ago
9 years ago
9 years ago
  1. # Sarah’s ScalaFX Utilities #
  2. This project contains helper functions, utilities and convenience functions
  3. for working with JavaFX and ScalaFx in Scala.
  4. ScalaFX does a tremendous job at making JavaFX more usable from Scala, but
  5. it doesn't go as far as it could in facilitating functional and reactive
  6. programming. This project is an attempt to add additional facilities that
  7. further bridge the beautiful Scala with JavaFX.
  8. In particular, here are some key features:
  9. * Monadic and applicative interfaces on top of `Observable` make it easy to
  10. build up computations.
  11. * Converters that allow you to use a `Future` or Akka `Stream` as an
  12. `Observable`.
  13. This code is offered as is with no guarantees. You are free to use it if you
  14. find it useful, but this is not part of any production project and it may have
  15. serious bugs. These APIs may also change at any time, and I make no guarantees
  16. that the project will be maintained at all. I welcome any bug reports and I
  17. will be happy to merge high-quality pull requests if you find a bug.
  18. ## Installation ##
  19. To use ScalaFX, add the following to your SBT build:
  20. libraryDependencies += "org.gerweck.scala" %% "scalafx-utils" % "0.9.1"
  21. ## Usage ##
  22. The primary use of this library is to provide a number of implicit conversions
  23. and instances, which are all brought into scope with this import:
  24. import org.gerweck.scalafx.util._
  25. If you use Scalaz, this makes ScalaFX observables instances of `Functor`,
  26. `Applicative` and `Monad`. It also provides some simple extension methods
  27. along these lines.
  28. ### Functional Transformations ###
  29. Note that the output of a functional transformation is always a
  30. `ReadOnlyObjectProperty[A]`, even if there exists a more specific result type
  31. like `ReadOnlyIntegerProperty` that would work. (The types used by ScalaFX are
  32. fairly complicated, and no real harm is done by using an `ObjectProperty` in
  33. all cases.)
  34. #### Map ####
  35. To facilitate functional programming, the standard `map` function allows you
  36. to transform an observable value using a pure function.
  37. Note that, for performance reasons, these functionally defined observables do
  38. not trigger an update if an input or output value is changed to one that is
  39. identical as defined by `equals`.
  40. import scalafx.beans.value._
  41. import scalafx.scene.control._
  42. import org.gerweck.scalafx.util._
  43. val textBox = new TextField { /* ... */ }
  44. val boxText: ObservableValue[String, String] = textBox.text
  45. /* Construct a new observable derived from the underlying one using `map` */
  46. val characterCount: ReadOnlyObjectProperty[String] = textBox.text map (_.size)
  47. #### Multiple Function Inputs ####
  48. If your function depends on several observable values, you can use the
  49. applicative behavior provided by the library. The Scalaz applicative
  50. functionality is all available, but there is a more convenient mechanism for
  51. the most common use case where you want to operate on a tuple.
  52. import scalafx.beans.property._
  53. import org.gerweck.scalafx.util._
  54. val startedDownloads = IntegerProperty(0)
  55. val finishedDownloads = IntegerProperty(0)
  56. val runningDownloads: ReadOnlyObjectProperty[Int] =
  57. (startedDownloads, finishedDownloads).observe map {
  58. case (st, fi) => st - fi
  59. }
  60. This `observe` extension method is available on tuples of any arity and
  61. efficiently processes updates from any of its dependent values.
  62. #### Monadically Chained Observables ####
  63. In addition to the behavior of an applicative functor, this library also
  64. provides the ability to act like a monadic functor by providing `flatMap` and
  65. `flatten`. *Where possible use the applicative syntax defined above rather
  66. than a chain of `flatMap` applications: the applicative format performs much
  67. better.*
  68. Here is an example of a model where you might have a dialog box or window.
  69. In this window, you could have a list selection where you choose from one of
  70. many transformation types. Once you've selected a transformation type, it will
  71. display a configuration panel that you can use to control the details of that
  72. transformation.
  73. import scalafx.beans.property._
  74. import org.gerweck.scalafx.util._
  75. /** An object that has a config dialog that produces a function */
  76. trait ConfigurableIntFunction {
  77. val typeName: String
  78. val configPanel: scalafx.scene.layout.Pane
  79. val currentFunction: ReadOnlyObjectProperty[Int => Int]
  80. }
  81. val selectedFunctionType: ObjectProperty[ConfigurableIntFunction] = ???
  82. val selectedFunction = selectedFunctionType flatMap (_.currentFunction)
  83. val inputInt = IntegerProperty(0)
  84. val outputInt =
  85. (selectedFunction, inputInt).observe map {
  86. case (sf, ii) => sf(ii)
  87. }