我在 Eclipse 中进行了相当多的搜索和一些试验和错误,但在使用 Swing 在 Scala 中编写 GUI 时,我对听众和反应的理解似乎存在差距。
每个侦听器是否都有一个反应块,或者我是否在所有可能生成事件的组件上注册侦听器并在带有案例语句的大型反应块中对每个组件做出反应?
听众和反应块到底属于哪里。
这是我的 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 中的文本字段做出反应。
我是将听众和反应块放置在尽可能靠近我感兴趣的元素的位置,还是在 MainFrame 部分的末尾放置一大块听众和反应?
这还重要吗?
编辑
我已经取得了重大进展,并且有很多我需要工作的东西,以及对我以前没有得到的概念的更好理解。
这段摘自 Odersky 的“Scala 编程”对我帮助最大。具体来说,此页面中的示例:
http://www.artima.com/pins1ed/gui-programming.html
代码来自文本的第一版,所以我质疑Scala 2.9中是否有更好的方法,但它很简洁,总结了我的误解。
从这个简单的华氏到摄氏度转换器的示例中,我了解到侦听器和反应块属于 MainFrame 的内容块之后。
所以我最终得到:
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!
}
}
所以看来我的问题的答案是 listenTo 和反应块属于 MainFrame 块,但应该出现在它的内容 += { //contents } 块之后。
eclipse 中的额外试验和错误表明,虽然这个解决方案对我有用,但显然还有很多我不明白的地方。例如,如果我尝试在上述代码的
val OtherPanel = new BoxPanel(Orientation.Horizontal) { }
部分中监听 KeyPress 事件并对其做出反应,我无法让监听器工作,但我能够得到一个按钮注册并像这样工作:
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
}
没有工作仍然让我感到困惑。我假设它应该可以工作,而我只是做错了。也许将这种方法与案例 EditDone 而不是案例 KeyTyped( , , , ) 融合会奏效,但我现在有点筋疲力尽,无法跟进。
我还没有接受答案,因为我希望看到这个的人可以澄清我仍然不明白的观点。如果这种情况没有发生并且几天内问题仍未得到解答,我可能会接受@som-snytt 的回答,因为他的代码非常有帮助。