2011年11月3日木曜日
ScalaでSwingレイアウト(GridBagPanel編)
GridBagPanelはGridBagLayoutとJPanelクラスが合わさったクラスです。
GridBagPanelはレイアウトの自由度がかなり高いクラスとなっており、これを利用すれば、おおよその画面レイアウトは実装できてしまうのではないでしょうか?
主な使い方は以下の通りです。
ScalaでSwingレイアウト(BoxPanel編)
普段はWebプログラマ~な自分からすると、Swingのレイアウトマネージャーって、非常に使いづらい。「そんなんだから Adobe Airに・・・」なんてことが出掛ってしまうぐらい使いづらい。そんなSwingですが、Scalaを利用して実装すると少しはマシになるな~というのを実感する今日この頃なので、少しずつScalaでのSwingの利用方法を紹介できたらなんて思っています。そんでもって、まずはBoxPanelクラスを紹介しようと思います。
Scalaではパネルを設定するのにPanelクラスとレイアウトマネージャがセットになっている以下のクラスを利用するようになっています。
- BorderPanel
- BoxPanel
- FlowPanel
- GridBagPanel
- GridPanel
2011年9月3日土曜日
ScalaのAPIとプレースホルダー構文の関係についてわかったことをまとめてみた
Scalaのコレクションクラスなどで利用することができるプレースホルダ(「_」)について、ちょっと調べてみたのでまとめてみました。
2011年8月21日日曜日
ScalaのgroupByメソッドを使ってみた
最近Scalaのコレクションクラスに「groupBy」というメソッドがあることを知り、ちょっと使ってみました。
使ってみて改めて画期的なメソッドだな~と感じたのでちょっと紹介いたします。
groupbyメソッドは引数に渡した関数の戻り値をキーにしたマップを作成するメソッドです。同じキーを返した値がマップの値になります。
例として売上げを商品毎にまとめてみます。
2011年8月7日日曜日
2011年4月17日日曜日
ScalaでClassオブジェクトを利用したリフレクション
Scala: How do I dynamically instantiate an object and invoke a method using reflection?
にサンプルがあったのでメモ。
class Foo {
def hello(name: String): String = "Hello there, %s".format(name)
}
object FooMain {
def main(args: Array[String]) {
val foo = Class.forName("Foo").newInstance.asInstanceOf[{ def hello(name: String): String }]
println(foo.hello("Walter")) // prints "Hello there, Walter"
}
}
この方法を利用すると以前書いたAbstractFactoryのサンプルをこれで書きかえることができるので書きかえてみた。2011年1月26日水曜日
Scala Swingでデザインパターン[Command]
また昔買った「デザインパターン入門講座」本のサンプルを実装してみました。
- 「File」-「Open」からファイル選択ダイアログを開く
- 「File」-「Exit」からプログラムを終了する
- 「Red」ボタンを押下すると背景が赤になる
このサンプルを実装してみて思ったのですが、Scalaはこの方法でイベント処理を実装するのに不向きなような気がします。 サンプルで実装されているアクションの実行方法は、
- ボタン、メニューのコンポーネントオブジェクトにCommandオブジェクトを保持するためのインタフェースを追加する
- コンポーネントにCommandオブジェクトを追加する
- イベント発生時にイベントオブジェクトからイベント発生元のコンポーネントを取得する
- コンポーネントからコマンドを取り出し実行する
というものなのですが、4.のコンポーネントからコマンドを取り出すには、型キャスト(アンボクシング?)が必要になります。
ジェネリクスによる型認識を徹底的に駆使して、型付言語でありなが型を意識することなく実装していくことを意識して設計されているScalaなのに、型キャストをしなければいけないのはいかがなものかと思ってしまうわけです。
ScalaではScalaなりのアクションの実装方法があるような気がするんですが、それがなんだかは全く検討がつきません。
そのうち気付くかな?でも、そこまで Scala + Swing を追求していこうとも思っていなんですが・・・・。
型キャストはasInstanceOf[T]というメソッドで行うことができます。
実装例は下記のとおりになります。reactions += {
case ButtonClicked(a) => a.asInstanceOf[CommandHolder].command.execute
}
本サンプルのソースはこちら
2011年1月20日木曜日
Swingでデザインパターン[Bridge]
「デザインパターン入門講座」本から「Bridge」パターンのサンプルをScalaで実装してみました。 今回は一つのデータを利用して、一般顧客用とエグゼクティブ顧客用の2種類のビューを生成するというものです。 コンポーネント追加用のメソッドを持つ抽象クラスをつくり、それを実装するクラスに委譲の形でコンポーネントを持たせています。
そして、コンポーネントもインタフェースをかませることで抽象度を高くしています。個人的には、コンポーネント追加用の抽象クラスがBorderPanelを継承しているところがちょっと気になりました。 デスクトップアプリ(Swing)以外の方法で表示したくなったときにどうするのかな?と。「そこは、継承より委譲だろ」と思ってしまいました。Swing、デザパタに詳しい人とかはひょっとしたらもっと大きな問題に気付けたりするのかもしれないですが、自分ではこれが精一杯。
今回はまったのがずばりscala.swingパッケージにJTreeのラッパークラスがない!!ということでした。
なんで、JTreeのラッパーだけないんでしょう?実装漏れ?JTreeクラスに何か欠陥があるのか?「こんなコンポーネントいらね~よ」と実装者が思ったのでしょうか?まあ、考えてもしょうがないのですが・・・・。
かなり調べるのに時間がかかってしまったのですが、scala.swing.Componentクラスの中にコンポーネントを委譲させるように実装すれば言いということがわかりました。実装例は下記の通り
viewportView = new Component {
override lazy val peer = new JTree(root)
}
あまりいいサンプルじゃないので、もう一つ
class Tree extends Component {
override lazy val peer = new JTree(root)
}
遅延評価変数になっているところがミソ?なのかな・・・。
Scala Swing 独特のイベントリスナの実装も割と簡単にできるのですが、それはまた別の機会にということで(知りたい人はコメントとかくれるとありがたいです)。
あと今回、Javaのリフレクション機能を利用して文字列から動的にクラスを生成する方法を色々調べたのですが、結局わからずじまいとなってしまいました。Scalaという言語の特性上、基本的にやらないほうがいい処理なんでしょうか?
ちなみに、コップ本でもプログラム内で生成処理を分岐させて別のクラスの実装を返す方法しか紹介されていませんでした(27章)。
2011年1月18日火曜日
Scala Swingでデザインパターン[Abstract Factory]
ラジオボタンに対応する庭園クラスがあるのですが、それぞれの庭園クラスの親クラスを実装し、イベントアクション内では親クラスを操作するという形になっています。Factoryクラスは直感的だから、そんなに説明も必要ないとは思いますが・・・・
本サンプルのソースはこちら
2011年1月14日金曜日
setterと「_」(アンダースコア)の不思議
ScalaでSwingのプログラムを組もうとして、apiのドキュメントを見ていたら、ちょいちょい「_=」で終わるメソッド名が目についた。
気になって、調べて見たら
Getters and Setters in Scala | The Personal Blog of Dustin Martinを発見。
一番下のほうに
First, the method name is “age_=”. The underscore is a special character in Scala
and in this case, allows for a space in the method name which essentially makes
the name “age =”.
とあるんだけど訳すと
最初にメソッド名は "age_="となる。アンダースコアはScalaでは特別な文字で、この場合メソッド名に空白を許可し、メソッド名を実質的に "age =" とする
という意味になる。なんとなくこの文章読んで思ったのが
「文字列と"="の間に複数の空白が入ると実はエラーになるのでは」
と思って試してみた。
class SimpleTest {
var _simpleTest = ""
def test_=(strTest: String) = {_simpleTest = strTest}
def test = _simpleTest
}
これを下記のように実行すると
val hoge = new SimpleTest hoge.test = "Hello" // OK hoge.test = "Hello" //OK
という感じでどっちも問題なかった。
表記の仕方からするとエラーになった方が自然なような気がするんだけど、まあ、エラーにされると不便だからいいか。
でも不思議~~。
2011年1月2日日曜日
Scala Swingでデザインパターン[Simple Factory]
こちらのプログラムは画面上部のテキストボックスに名前を入力したら、名前を姓(Last Name)と名(First Name)に分割してそれぞれのテキストボックスに表示するという簡単なプログラムです。
1. 名前を半角空白区切りにすると前が名で後ろが姓
2. 名前をカンマ区切りにすると前が姓で後ろが名
というような分割ルールになっています。
2010年12月29日水曜日
はじめてのScala Swing ~SimpleGUIApplicationにはまる~
とりあえず何か楽しそうなところからということで、ScalaのGUIプログラミングから始めました。
import scala.swing._
object FirstSwingApp extends SimpleGUIApplication {
def top = new MainFrame {
title = "First Swing App"
contents = new Button {
text = "Click me"
}
}
}
これを
C:\Study\Scala>scala FirstSwingApp.scala
として実行しようとしたら、何もおきずにプログラムが終了してしまった。
最初に何かを間違えてしまったのかと色々調べても一向に解決策が見つからない・・・。
結局
C:\Study\Scala>scalac FirstSwingApp.scala C:\Study\Scala>scala FirstSwingApp
で無事実行することができた。
scalacでコンパイルしたプログラムはscalaコマンドで実行できるらしい。



