私はかなりの検索を行い、Eclipseで試行錯誤を繰り返しましたが、Swingを使用してScalaでGUIを作成する場合、リスナーと反応についての理解にギャップがあるようです。
各リスナーはリアクションブロックを取得しますか、それともイベントを生成する可能性のあるすべてのコンポーネントにリスナーを登録し、caseステートメントを使用して大きなリアクションブロックのそれぞれに反応しますか?
リスナーとリアクションブロックは正確にどこに属しますか。
これが私のGUIコードの短縮版です:
import scala.swing._
import scala.swing.event.ButtonClicked
import scala.swing.event.KeyTyped
import scala.swing.event.KeyPressed
object HumanGUI extends SimpleGUIApplication {
val basicPane = new java.awt.Dimension(800, 200)
val botPane = new java.awt.Dimension(400, 200)
val felt = new java.awt.Color(35, 125, 35)
def top = new MainFrame {
title = "Blackjack GUI"
val ConnectionPanel = new BoxPanel(Orientation.Vertical) {
background = felt
preferredSize = new java.awt.Dimension(155, 90)
minimumSize = preferredSize
maximumSize = preferredSize
val ipAddressLabel = new Label("House IP:")
ipAddressLabel.foreground = java.awt.Color.WHITE
ipAddressLabel.horizontalTextPosition = scala.swing.Alignment.Left
val portLabel = new Label("House port:")
portLabel.foreground = java.awt.Color.WHITE
portLabel.horizontalTextPosition = scala.swing.Alignment.Left
val ipAddressTextField = new TextField
val portTextField = new TextField
contents += ipAddressLabel
contents += ipAddressTextField
contents += portLabel
contents += portTextField
}
val DetailPanel = new BoxPanel(Orientation.Vertical) {
background = felt
preferredSize = new java.awt.Dimension(100, 160)
minimumSize = preferredSize
maximumSize = preferredSize
val nameLabel = new Label("Your name:")
nameLabel.foreground = java.awt.Color.WHITE
nameLabel.horizontalTextPosition = scala.swing.Alignment.Left
val bankrollLabel = new Label("Bankroll:")
bankrollLabel.foreground = java.awt.Color.WHITE
bankrollLabel.horizontalTextPosition = scala.swing.Alignment.Left
val betLabel = new Label("Bet:")
betLabel.foreground = java.awt.Color.WHITE
betLabel.horizontalTextPosition = scala.swing.Alignment.Left
val nameTextField = new TextField
val bankrollTextField = new TextField
val betTextField = new TextField
val goButton = new Button("Go!")
contents += nameLabel
contents += nameTextField
contents += bankrollLabel
contents += bankrollTextField
contents += betLabel
contents += betTextField
contents += goButton
}
val PlayPanel = new BoxPanel(Orientation.Vertical) {
background = felt
val hitButton = new Button("Hit")
val stayButton = new Button("Stay")
val doubleButton = new Button("Double")
val quitButton = new Button("Quit")
contents += hitButton
contents += stayButton
contents += doubleButton
contents += quitButton
}
val playerPanel = new BoxPanel(Orientation.Horizontal) {
background = felt
border = new javax.swing.border.LineBorder(java.awt.Color.WHITE)
preferredSize = basicPane
minimumSize = basicPane
maximumSize = basicPane
opaque = true
contents += ConnectionPanel
contents += DetailPanel
contents += PlayPanel
}
contents = new BoxPanel(Orientation.Vertical) {
contents += playerPanel
}
}
}
だから問題は、リスナーとリアクションブロックをどこに置くかです。
PlayPanelのボタン、およびConnectionPanelとDetailPanelの両方のテキストフィールドに反応したいと思います。
リスナーとリアクションブロックを関心のある要素のできるだけ近くに配置しますか、それともメインフレームセクションの最後にリスナーとリアクションの大きなブロックを配置しますか?
それも重要ですか?
編集
私は大きな進歩を遂げ、私が以前に得ていなかった概念のより良い理解とともに、私が働く必要があるものの多くを持っています。
Oderskyの「ProgramminginScala」からのこの抜粋は、私を最も助けてくれました。具体的には、このページの例:
http://www.artima.com/pins1ed/gui-programming.html
コードはテキストの初版のものなので、Scala 2.9にもっと良い方法があるかどうか疑問に思いますが、簡潔で、私が誤解していたことを要約しました。
単純な華氏から摂氏へのコンバーターである例から、リスナーとリアクションブロックがメインフレームのコンテンツブロックの後に属していることがわかりました。
だから私は結局:
object HumanGUI extends SimpleSwingGUIApplication {
def top = new MainFrame {
title = "My Blackjack GUI"
//The fields I want to work with are instantiated as object
object ipAddressTextField extends TextField { columns = 15 }
object portNumberTextField extends TextField {columns = 5 }
//other panels, objects, etc would go here
val OtherPanel = new BoxPanel(Orientation.Horizontal) {
label = "Other Panel"
}
//and here we have the contents += block for the mainframe, other panels, etc from
//above would be added to the main frame here
contents = new BoxPanel(Orientation.Vertical) {
contents += ipAddressTextField
contents += portNumberTextField
}
//here's the listen to, listening on the object created above, and it's enclosed in
//in backticks, a good explanation of that is found in the link below
listenTo(`ipAddressTextField`)
reactions += {
case EditDone('ipAddressTextField`) =>
//do something!
}
}
Scalaリテラル識別子(バックティック)を明確にする必要があります
したがって、私の質問に対する答えは、listenToブロックとreactionsブロックがMainFrameブロックに属しているようですが、そのcontents + ={//contents}ブロックの後に表示されるはずです。
Eclipseでの追加の試行錯誤は、このソリューションは私には有効ですが、私が理解していないことが明らかにはるかに多いことを示しています。たとえば
、上記のコードの
val OtherPanel = new BoxPanel(Orientation.Horizontal){}の部分でキープレスイベントのリスナーをリッスンして反応させようとすると、キープレスイベントのリスナーを機能させることができませんでしたが、
登録され、次のように機能するボタン:
val OtherPanel = new BoxPanel(Orientation.Horizontal) {
val betLabel = new Label("Bet:")
val betTextField = new TextField
val goButton = new Button("Go!")
listenTo(goButton)
reactions += {
case ButtonClicked(b) =>
betTextField.text = "Go!"
}
contents += betLabel
contents += betTextField
contents += goButton
}
なぜこれがうまくいったのか、しかし私の試みは
val OtherPanel = new BoxPanel(Orientation.Horizontal) {
val betLabel = new Label("Bet:")
val betTextField = new TextField
val goButton = new Button("Go!")
listenTo(betTextField)
reactions += {
case KeyTyped(betTextField, Enter, _, _) => {
println("Caught enter")
}
contents += betLabel
contents += betTextField
contents += goButton
}
うまくいかなかったのはまだ私を困惑させています。私はそれがうまくいくはずだと思っています、そして私はただ何か間違ったことをしています。おそらく、そのアプローチをケースKeyTyped(、、、)の代わりにケースEditDoneと融合させることはうまくいったでしょうが、私は今少し燃え尽きすぎてそれをフォローアップできません。
私はまだ答えを受け入れていません。これを見た人が私がまだ理解していない点を明らかにしてくれることを望んでいるからです。それが起こらず、質問が数日間答えられないままである場合、彼のコードは非常に役に立ったので、私はおそらく@som-snyttの答えを受け入れるでしょう。