I'm writing an image library for intro programming students to play with. (I stole the idea and the patterns from the image library for DrRacket.)
https://github.com/dupontmanualhs/dm-image
It's mostly written in Swing (that's the master
branch), but I'm trying to convert it to ScalaFX (see the scalafx
branch), and there are some issues. Ideally, a student should be able to do something like:
scala> import org.dupontmanual.image._
scala> TrainEngine.display()
and have a dialog box with a train engine show up. I've tried using the code at
https://github.com/scalafx/ScalaFX-Tutorials
in the stand-alone-dialog
project, but if I include System.exit(0)
after I dialog.showAndWait()
, I get this error:
Not interrupting system thread Thread[process reaper,10,system]
Exception while removing reference: java.lang.InterruptedException
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at com.sun.glass.utils.Disposer.run(Disposer.java:69)
at java.lang.Thread.run(Thread.java:744)
Not interrupting system thread Thread[Prism Font Disposer,10,system]
Exception in runnable
Exception in thread "JavaFX Application Thread"
(Note that I get the same error if I try to run the App
from stand-alone-dialog
in the console, so I'm guessing that calling System.exit(0)
is not a great idea in the SBT console.)
If I leave the System.exit(0)
line out, then things seem to work fine--mostly. After the first time I display the dialog, it doesn't bring the dialog into focus, so I have to click it to dismiss the dialog. But the real problem is that when I :q
to exit the console, SBT hangs and I have to Ctrl-C
to be able to type again. (And, yes, Ctrl-C
exits SBT completely, not just the console.)
I think what I may need to do is create a thread specifically for ScalaFX stuff. For example, I have a method to stack one image on top of another, and I got an IllegalStateException
when I tried to call that function, even though it doesn't actually display anything, just creates a new Group
with the two previous Node
s stacked appropriately. Unfortunately, I'm not sure how to create a new thread and make sure that everything image-related runs through that.
I've already set fork := true
in build.sbt
, but that doesn't seem to make a difference with the console.
== Update ==
I found initialCommands
and cleanupCommands
in the SBT documentation and tried to clean up after everything when the console starts and ends. The values are:
initialCommands in console := """import org.dupontmanual.image._; org.dupontmanual.image.initialize()"""
cleanupCommands in console := """org.dupontmanual.image.cleanUp()"""
which are defined thusly:
package object image {
var masterFrame: JFrame = _
def initialize() {
masterFrame = new JFrame()
masterFrame.add(new JFXPanel())
masterFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
}
def cleanUp() {
println("exiting platform")
Platform.exit()
println("disposing of frames")
Frame.getFrames().foreach {
_.dispose()
}
println("frames all disposed")
System.exit(0);
}
Here's the result of running the console and then trying to quit:
> console
[info] Compiling 1 Scala source to /home/sysadmin/dm-workspace/dm-image/target/scala-2.10/classes...
[info] Starting scala interpreter...
[info]
import org.dupontmanual.image._
Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51).
Type in expressions to have them evaluated.
Type :help for more information.
scala> Hacker.display()
scala> :q
exiting platform
disposing of frames
frames all disposed
Not interrupting system thread Thread[XToolkt-Shutdown-Thread,5,system]
Not interrupting system thread Thread[AWT-XAWT,6,system]
Not interrupting system thread Thread[Prism Font Disposer,10,system]
Not interrupting system thread Thread[Java2D Disposer,10,system]
Exception while removing reference: java.lang.InterruptedException
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at com.sun.glass.utils.Disposer.run(Disposer.java:69)
at java.lang.Thread.run(Thread.java:744)
Exception: sbt.TrapExitSecurityException thrown from the UncaughtExceptionHandler in thread "run-main-0"
and that doesn't even exit the console. You still have to use Ctrl-C, which exits out of SBT completely.
Something is still running, but I can't figure out what it is. Grrr.
scalafx.Platform.exit()
instead ofSystem.exit(0)
? The former is the preferred method for terminating a ScalaFX application. – Tillandsiascalafx.application.Platform.exit()
! Sorry for the confusion... – Tillandsia:q
in the console. – BelviaSystem.exit(0)
in the ScalaFX-Tutorials StandAloneFXDialog code and it just locks up the sbt console. According to the JavaFX version of this function (which ScalaFX calls under the hood), Note: if the application is embedded in a browser, then this method may have no effect. That could be a problem. I'll look into this some more... – TillandsiaPlatform.exit()
, but with the implementation of theFXUtils.runAndWait(...)
function in thestand_alone_dialog
package. In essence, it terminates the executing thread under a very limited set of conditions, soPlatform.exit()
ends up having no effect. I'm going to take a look at improving this. I'll place the revised code on GitHub... – TillandsiaPlatform.exit()
isn't doing anything. If you look at the documentation for the JavaFX JFXPanel class - for embedding JavaFX/ScalaFX into Swing applications - there is a neat worked example to follow. I guess since it's a Swing app, you terminate the app by calling thedispose()
method of the main frame. Hope this helps... – TillandsiaPlatform.exit()
thenSystem.exit(0)
and see if that does the trick. BTW, I'll happily turn the comments into an answer when I figure out how you should terminate your app - but thanks! It shouldn't be this hard... :-( – TillandsiaImage
class'sdisplay()
method? I assume I'd have to run it in a new Thread or Process (because I tried just launching it without doing that and got an error). – Belviaexit
I see the error now, although I see it everytime Iexit
the sbt console, even when not executing the TrainEngine. – Strawworm