SwingApplication終了時の処理
scala.swingのSwingApplicationにはquit()とshutdown()というメソッドがあります。
quit()はshutdown()とSystem.exit(0)を呼んでくれるので、shutdown()をオーバーライドして終了時の処理を書けばいいんだよねー。
object QuitNotCalledApplication extends SimpleSwingApplication { def top = new MainFrame override def shutdown() { println("shutdown...") } }
と思いきやこれではquit()は呼ばれてくれません。何故でしょう。
MainFrameの定義を見ると↓のようになってます。
class MainFrame extends Frame { override def closeOperation { System.exit(0) } }
閉じるボタンが押されたらSystem.exit(0)しちゃう訳です。
MainFrameはSwingApplicationのことなんて知らないのでそりゃそうですよね。
という訳でquit()を呼んでくれるFrameを自前で作ります。
class MyFrame(app: SwingApplication) extends Frame { require(app != null) override def closeOperation() { app.quit() } }
requireでappがnullでないことを保証しています。
閉じるボタンが押されたらquit()を呼びます。
これを使って先ほどのコードを修正。
object QuitCalledApplication extends SimpleSwingApplication { def top = new MyFrame(this) override def shutdown() { println("shutdown...") } }
これで閉じるボタンを押したときにshutdown処理が走るようになります。
(しかし何か不恰好な気がする。いい感じのやり方ないかな……)
sbt-idea (plugin and processor)
sbtのよさげなプラグインがリリースされてたので使ってみる。
http://implicit.ly/sbt-idea-010
sbtのプロジェクト定義からIDEAのプロジェクトとかモジュールを生成してくれるんですって。わーい。
sbtプロジェクト作成
ここはいつも通りですね。Scala2.8.1.final出たので2.8.1使いましょう。
$ sbt Project does not exist, create new project? (y/N/s) y Name: MyProject Organization: example Version [1.0]: Scala version [2.7.7]: 2.8.1 sbt version [0.7.4]: ... [info] Building project MyProject 1.0 against Scala 2.8.1 [info] using sbt.DefaultProject with sbt 0.7.4 and Scala 2.7.7
Plugins.scala
プロジェクトフォルダの project/plugins/Plugins.scala を編集(作成)します。
import sbt._ class Plugins(info: ProjectInfo) extends PluginDefinition(info) { val sbtIdeaRepo = "sbt-idea-repo" at "http://mpeltonen.github.com/maven/" val sbtIdea = "com.github.mpeltonen" % "sbt-idea-plugin" % "0.1.0" }
Project.scala
project/build/Project.scala も編集。
import sbt._ class MyProject(info: ProjectInfo) extends DefaultProject(info) with IdeaProject { // ... }
IdeaProjectをミックスインします。
マルチモジュールなプロジェクトを作成したい場合、すべてのサブプロジェクトにIdeaProjectをミックスインする必要があります。
idea.properties
project/idea.propertiesを編集すると、作成されるIDEAプロジェクトの設定を調整できます。
デフォルトで問題ないと思いますが、IDEAに名前変えてjdk設定してるのでそこだけ変更。(デフォルトだと1.6)
project.jdk.name=1.6.0_22
他にもjava.language.level(デフォルトJDK_1_6)やらproject.output.pathやらあります。
sbt update
sbt updateを実行します。
$ sbt update [info] Recompiling plugin definition... [info] Source analysis: 1 new/modified, 0 indirectly invalidated, 0 removed. ... [success] Build completed successfully.
pluginをDLしてきます。
sbt idea
sbt idea実行。
$ sbt idea [info] Building project MyProject 1.0 against Scala 2.8.1 [info] using MyProject with sbt 0.7.4 and Scala 2.7.7 [info] [info] == idea == [info] Created D:\Project\MyProject\.idea [info] Created D:\Project\MyProject/project/sbt_project_definition.iml [info] Created D:\Project\MyProject/MyProject.iml [info] == idea == [success] Successful. ...
おー、IDEAのプロジェクトファイルが作成されました。
Animatorその1
全然Animatorじゃないけど。PartialFunctionで状態遷移だけ。
import scala.actors._ import javax.media.opengl.GLAutoDrawable class Animator extends Actor { private val drawables = scala.collection.mutable.Set[GLAutoDrawable]() private var action = stoped orElse pfallways def act() { loop { react(action) } } lazy val stoped : PartialFunction[Any, Unit] = { case Start => action = started orElse pfallways } lazy val started : PartialFunction[Any, Unit] = { case Stop => action = stoped orElse pfallways case Pause => action = paused orElse pfallways } lazy val paused : PartialFunction[Any, Unit] = { case Stop => action = stoped orElse pfallways case Resume => action = started orElse pfallways } lazy val pfallways = pfdrawable orElse pfexit lazy val pfdrawable : PartialFunction[Any, Unit] = { case Add(drawable) => drawables += drawable case Remove(drawable) => drawables -= drawable } lazy val pfexit : PartialFunction[Any, Unit] = { case Exit => exit() } }
名前考えるのがだるい。最後とかpfつけときゃいいやって思考になってて意味不明です。
これに色々肉付けしていって、ラッパーにGLAnimatorControl実装してー(def start()とか被るので)、とか考えてたけど、GLAnimatorControlにgetThreadとかあるわな。
詳しく見てないけど、描画中のスレッドを外部から取得できるようにするってActorとしてまずいんじゃなイカ。
そこんとこどーなのと思いつつ、あんまり触る時間が取れてない。
NEWTでウィンドウ作成
JOGLのdemosやチュートリアルから引っ張ってきてScalaの書式にしただけだけども。
import javax.media.opengl.{ GLAutoDrawable, GLProfile, GLCapabilities, GLEventListener } import com.jogamp.newt.event.{ WindowAdapter, WindowEvent } import com.jogamp.newt.opengl.GLWindow import com.jogamp.opengl.util.FPSAnimator object NewtTest { def main(args : Array[String]){ GLProfile.initSingleton() run() } def run() { try { val glp = GLProfile.getDefault val caps = new GLCapabilities(glp) val window = GLWindow.create(caps) window.setUndecorated(false) window.setSize(800, 600) val animator = new FPSAnimator(window, 60) window.addWindowListener(new WindowAdapter(){ override def windowDestroyNotify(e : WindowEvent){ animator.stop() System.exit(0) } }) window.addGLEventListener(listener) window.setVisible(true) window.setTitle("NEWT Window Test") animator.start() } catch { case e => e.printStackTrace() System.exit(1) } } object listener extends GLEventListener { def init(drawable : GLAutoDrawable){} def dispose(drawable : GLAutoDrawable){} def display(drawable : GLAutoDrawable){} def reshape(drawable : GLAutoDrawable, x : Int, y : Int, w : Int, h : Int){} } }
setVisibleやった後じゃないとsetTitleが効かないのは何故だろう?
次はActorの練習にAnimatorを自前で書いてみたいな。