ScalaFx Bind ImageView to custom Enumeration - scala

I just started to write scalafx application and have a question about bindings.
I have an Enumeration with connection status in my presenter class and I want to select appropriate icon in label in view class. I basically can create binding in javafx way and set converter which will select appropriate ImageView every time status changes, but is it possible to do in ScalaFX way?
I looked many scalafx examples, but still can't find anything like this.
Here is some code:
package view
import scalafx.beans.property.ObjectProperty
class MainWindowPresenter {
object DatabaseState extends Enumeration {
type DatabaseState = Value
val NOT_CONNECTED, IDLE, BUSY, ERROR = Value
}
val login = new ObjectProperty[String](this, "login", "awesomeloginname")
val state = new ObjectProperty[DatabaseState.DatabaseState](this, "state", DatabaseState.ERROR)
}
View class:
package view
import java.util.concurrent.Callable
import javafx.beans.binding.ObjectBinding
import collection.immutable.HashMap
import javafx.scene.control.SeparatorMenuItem
import scala.util.Random
import scalafx.beans.property.{ObjectProperty}
import scalafx.geometry.{Orientation, Insets, Pos}
import scalafx.scene.control._
import scalafx.scene.image.{ImageView, Image}
import scalafx.scene.layout._
import scalafx.Includes._
class MainWindowView extends BorderPane {
val model = new MainWindowPresenter
top = new HBox {
content = List(
new Label() {
graphic <== //somehow select imageview depending on model.state
}
)
}
private def imageFromResource(name : String) =
new ImageView(new Image(getClass.getClassLoader.getResourceAsStream(name)))
}
Thanks in advance and sorry for grammar mistakes, if any - English isn't my native.

You can use EasyBind or the snapshot (2.0-SNAPSHOT) version of ReactFX to create the binding. Both are Java libraries, but they are easy to use from Scala. This is the EasyBind way:
graphic <== EasyBind.map(model.state, stateToImage)
val stateToImage: Function1[DatabaseState.DatabaseState, ImageView] = {
// convert state to ImageView
}
This code uses the implicit conversion from Scala's Function1 to Java's Function.
You could also define an implicit conversion from ScalaFX ObjectProperty to EasyBind's MonadicObservableValue and then the first line above can be rewritten to:
graphic <== model.state.map(stateToImage)

Related

Importing object without class

I'm trying to import an object from another .scala file that doesn't exist inside a class. I've found you can import a class like in here Scala, importing class. Is there a way to import an object without having a class around it?
Thanks
Importing a class and importing an object work the same in scala.
If you have a class
package com.package1
class MyClass{}
and an object
package com.package2
object MyObject{}
You import both the exact same way
package com.package3
import com.package1.MyClass
import com.package2.MyObject
import syntax is the same no matter what you are importing, whether it's an object, a class, a trait, a method, or a field
Yes, Scala can do exactly what you ask, and this is used frequently. Here is an example:
object Blah {
val x = 1
val y = "hello"
}
object Main extends App {
import Blah._
println(s"x=$x; y=$y")
}
Output is:
x=1; y=hello
You can also import members of a class instance, which blew my mind the first time I saw it.
If you are talking about companion objects, they are not defined inside a class, but after the class definition:
class AClass {
def sayHello() = {
println(AClass.Hello)
}
}
object AClass {
private val Hello = "hello"
}
You should have no problem importing it.

Serialize class as its one member with Jackson

Sometimes the class has only one member to serialize (other members are transient), and I would like to serialize and deserialize this class as its only member.
Consider following code:
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
case class Content(i:Seq[Int])
case class Wrap(content:Content)
object Main extends App {
val om = new ObjectMapper() with ScalaObjectMapper {
registerModule(new DefaultScalaModule)
}
val roots = Wrap(Content(Seq(1,2,3)))
val out = om.writeValueAsString(roots)
println(out)
val test = om.readValue(out, classOf[Wrap])
println(test)
}
The result of serialization of Wrapis {"content":{"i":[1,2,3]}}.
I would like to get {"i":[1,2,3]} only. I guess I could do this with custom serializer/deserializer, but given in real case the content is a complex class, this would mean I would have to serialize the content manually, if I am not mistaken. I would prefer some more straightforward solution.
Is it possible to "delegate" the serialization/deserialization to a member/constructor parameter?
It can be done using converters, which can be used to modify Jackson behaviour using JsonSerialize and JsonDeserialize properties.
import com.fasterxml.jackson.databind.annotation.{JsonSerialize, JsonDeserialize}
import com.fasterxml.jackson.databind.util.StdConverter
#JsonDeserialize(converter=classOf[WrapConverterDeserialize])
#JsonSerialize(converter=classOf[WrapConverterSerialize])
case class Wrap(content:Content)
class WrapConverterDeserialize extends StdConverter[Content,Wrap] {
override def convert(value: Content) = new Wrap(value)
}
class WrapConverterSerialize extends StdConverter[Wrap,Content] {
override def convert(value: Wrap) = value.content
}

Base Class constructor not being called in JFXApp

package pGrid
package pUIFx
import pUtil._
object DevAppFx extends AppFx
{
println("Begining DevFxApp object constructor in package pGrid.pUIFx")
//devStart
}
package pGrid
package pUIFx
import pGeom._
import pGrid.pDev._
import scalafx.application._
import scalafx.application.JFXApp._
import scalafx.scene._
import scalafx.scene.paint._
class AppFx extends JFXApp with DevTr
{
println("Creating stage")
stage = new PrimaryStage
{
x = 3850
y = 200
width = 1000
height = 800
scene = new Scene
}
def openEFO(de: DescEFlatOne): Unit =
{
println("def in AppFx")
stage.scene = ScrEditFx(stage, de)
}
}
The DevAppFx object constructor runs, including the println ("Beginning ...
The class AppFx constructor does not run including the println ("creating stage"). The openEFO method can be called but the stage variable is null.
Edit this is a simplification. There will be a lot more functionality in DEVAppFx and AppFx, so its important to be able to keep the functionality separate.
I think the issue here is that scalafx.application.JXFApp is a class that extends the scala.DelayedInit trait. As such, some Scala magic happens under the hood: see the scala.DelayedInit docs for more. Unfortunately, DelayedInit is buggy and plays havoc with sub-class initialization/construction code - such as your AppFx class not executing its constructor.
There's no easy solution to this, I'm afraid. Until the DelayedInit behavior is resolved, or until we find a better way to initialize ScalaFX, your best bet is to merge DevAppFx and AppFx into a single object, which should work as expected.
For example:
package pGrid
package pUIFx
import pGeom._
import pGrid.pDev._
import scalafx.application._
import scalafx.application.JFXApp._
import scalafx.scene._
import scalafx.scene.paint._
object AppFx extends JFXApp with DevTr
{
println("Creating stage")
stage = new PrimaryStage
{
x = 3850
y = 200
width = 1000
height = 800
scene = new Scene
}
// Relocate DevAppFx init here...
println("Begining DevFxApp object constructor in package pGrid.pUIFx")
//devStart
def openEFO(de: DescEFlatOne): Unit =
{
println("def in AppFx")
stage.scene = ScrEditFx(stage, de)
}
}
UPDATE:
I did some more digging around, and scalafx.application.JFXApp didn't do a great job of implementing the semantics of the scala.DelayedInit trait. In essence, it was only storing the construction/initialization code of the class/object at the bottom of the inheritance hierarchy, and dropping everything else. For further details, there is a ScalaFX bug report for this issue.
So, in your example, the construction code for the object DevAppFx was replacing the construction code for your class AppFx, instead of storing both, resulting in the symptoms you observed.
I've committed a patch to the default and SFX-8 branches of ScalaFX on Google Code, which you're free to utilize. Alternatively, if you're prepared to wait a few weeks, the next updates published to the Sonatype OSS to have the patch will be 1.0.0-R9 (for the JavaFX 2 equivalent) and 8.0.0-R5 (for the JavaFX 8 equivalent).
This patch should allow your original code to run unmodified. If you get a chance to try it out, let me know how you get on...
I've use the information about possible bugs in DelayedInit from Mike Allen's answer. However I want to keep the functionality separate rather than combining it into one object. Reading the docs, the problem is with classes and Objects not with traits that inherit from JFXApp and DelayedInit, so I have converted AppFx into a trait and moved the Stage creation into a method
object DevAppFx extends AppFx with DevTr
{
openStage
devStart
}
____________--
trait AppFx extends JFXApp with StratApp
{
def openStage: Unit = stage = new PrimaryStage
{
x = 3850
y = 200
width = 1000
height = 800
scene = new Scene
}
override def openEFO(de: DescEFlatOne): Unit = stage.scene = ScrEditFx(this, de)
}

"Stable identifer required" error during companion object import

I'm really new to Scala, and I've come across an error I am unable to solve by myself or through internet searches.
I have a Scala class called "GUI" that represents a JFrame along with a companion class. When I try to import the companion class using import GUI._ I get the error "stable identifier required, but GUI.this.GUI() found".
I made an empty class and companion object and the import worked fine, so I assume that the error is related to something specific to my code. Below is the code in question:
object GUI {
def test:Integer = 1
}
class GUI extends JFrame{
import GUI._
val ICON_LOCATION:File = new File("Images/iMovies.ico");
val ICON:BufferedImage = Ootil.createImage("iMovies.png");
val TITLE:String = "iVideos";
val LICENSE_NAME:String = "OpenBSD";
def GUI(){
setLayout(new BorderLayout());
createGUI();
pack();
setSize(100,100);
setLocationRelativeTo(null);
setVisible(true);
}
def versionMajor: Integer = 1
def versionMinor: Integer = 0
def versionRevision: Integer = 0
def versionPreReleaseID: String = "alpha"
def versionBuildNumber: String = "1b"
private def createGUI():Unit = {
val panel = new JPanel();
panel.setLayout(new BorderLayout());
add(panel, BorderLayout.CENTER);
}
def getIcon():BufferedImage = ICON
def getProgramTitle():String = TITLE
def getConfigOptions():LookAndFeelConfigurationOptions = GUIConfigOptions.CONFIG_OPTIONS;
}
To add to Kipton's answer, there's nothing wrong with doing:
class GUI{
def GUI() {
println("something")
}
}
But the result won't be a constructor -- it will be an ordinary method.
val a = new GUI() won't print anything, but calling a.GUI() will.
This is why you didn't get an error message about defining your constructor incorrectly.
When you run the command import GUI._, Scala needs GUI to always evaluate to the same object. This is only the case when GUI is an object, a package, or a val.
In your code, import GUI._ referred to the method GUI that you defined, because the GUI method is defined in a closer scope than object GUI (the fact that the compiler hasn't encountered the definition of def GUI yet doesn't make a difference).
Since import GUI._ referred to the method GUI, which is not a val, object, or package, you got the error message about GUI not being a stable identifier.
Welcome to the Scala community.
Scala constructors work differently than they do in Java. To fix the error, you should put the body of your previously defined GUI() method directly into the class definition, like so,
class GUI extends JFrame{
import GUI._
val ICON_LOCATION:File = new File("Images/iMovies.ico");
val ICON:BufferedImage = Ootil.createImage("iMovies.png");
val TITLE:String = "iVideos";
val LICENSE_NAME:String = "OpenBSD";
// ** stuff that used to be in method GUI() goes below **
setLayout(new BorderLayout());
createGUI();
pack();
setSize(100,100);
setLocationRelativeTo(null);
setVisible(true);
...
}
It takes a little getting used to, but I think you'll find that Scala's way is a lot nicer.
If you want to define an auxiliary constructor, declare a method def this(...) { ... } whose first expression is a call to the primary constructor (in this case just this(), since it doesn't take parameters).
If you want to add parameters to your primary constructor, you would define the class as
class GUI( << some parameters >> ) extends JFrame { ... }
and then you can use the parameters anywhere in this class body.

why doesn't scala recognize com.vaadin.ui.MenuBar.MenuItem

I'm trying to create a Vaadin window with a MenuBar using Scala. I'm getting a compiler error that indicates that the com.vaadin.ui.MenuBar.MenuItem import can't be found. I've looked at the Vaadin library (6.4.8), and it appears that the class is there:
com/vaadin/ui/MenuBar$Command.class
com/vaadin/ui/MenuBar$MenuItem.class
com/vaadin/ui/MenuBar.class
Here is the class structure from the MenuBar source:
#SuppressWarnings("serial")
#ClientWidget(value = VMenuBar.class, loadStyle = LoadStyle.LAZY)
public class MenuBar extends AbstractComponent {
...
public interface Command extends Serializable { ... }
public class MenuItem implements Serializable { ... }
}
For demo purposes, here's a sample Scala class:
import com.vaadin.Application
import com.vaadin.ui.Button
import com.vaadin.ui.Window
import com.vaadin.ui.MenuBar
import com.vaadin.ui.MenuBar.Command
import com.vaadin.ui.MenuBar.MenuItem
class MyVaadinApplication extends Application
{
private var window : Window = null
override def init() =
{
window = new Window("My Scala Vaadin Application")
setMainWindow(window)
window.addComponent(new Button("Click Me"))
}
}
And here's the resulting error when I try to compile it:
/Users/jstanford/Development/NetBeansProjects/TraderDashboard/src/main/scala:-1: info: compiling
Compiling 2 source files to /Users/jstanford/Development/NetBeansProjects/TraderDashboard/target/classes at 1291973683915
[ERROR]MyVaadinApplication.scala:7: error: MenuItem is not a member of com.vaadin.ui.MenuBar
import com.vaadin.ui.MenuBar.MenuItem
^
Can anyone spot the problem here?
Thanks,
John
Inner classes cannot be imported as usual it is appropriate for Java. Just specify type projections as it's done for Button#ClickEvent type:
import com.vaadin._
import ui._
import Button._
class MyScalaVaadinApplication extends Application {
val window = new Window("My Vaadin Application")
def init {
window.addComponent(new Button("Click Me", new ClickListener {
def buttonClick(clickEvent: Button#ClickEvent): Unit = window.showNotification("Just a message")
}))
setMainWindow(window)
}
}
A very simple example showing what's going on.
Java:
package a;
public class Outer { public class Inner {} }
Scala:
import a.Outer
import a.Outer.Inner // causes *Inner is not a member of a.Outer*
Notice that Inner, like MenuBar.MenuItem, is a non-static inner class and as such is associated with one instance of Outer. But Scala allows us to import Inner using a instance of Outer:
import a.Outer
import a.Outer.Inner
object dummy {
val o = new Outer
val o2 = new Outer
import o.Inner
val i = new Inner
val i2 = new o2.Inner
}
If we could just import a.Outer.Inner how would the compiler know to which instance of Outer is Inner supposed to belong to?
Hope the issue has been cleared.