Scala Swing Box订阅多个事件

Scala Swing Box订阅多个事件,swing,events,scala,foreach,Swing,Events,Scala,Foreach,我正在用Scala编写GUI,在尝试在foreach语句中注册按钮事件时遇到了一个奇怪的问题:应该是对于对象列表(object0…objectn)中的每个元素objecti,检索对应的按钮x=buttoni,并使用Box.listenTo(x)订阅给定的框。按下按钮时,应执行一些与objecti相关的操作(在本例中为“事件触发:+事件”): 但是,我发现了一些非常奇怪的行为,点击任何按钮都会触发所有此类对象操作——请参见程序输出: keypadEvents: List(1, 2) event:

我正在用Scala编写GUI,在尝试在
foreach
语句中注册按钮事件时遇到了一个奇怪的问题:应该是对于对象列表(object0…objectn)中的每个元素objecti,检索对应的按钮x=buttoni,并使用
Box.listenTo(x)订阅给定的框
。按下按钮时,应执行一些与objecti相关的操作(在本例中为“事件触发:+事件”):

但是,我发现了一些非常奇怪的行为,点击任何按钮都会触发所有此类对象操作——请参见程序输出:

keypadEvents: List(1, 2)
event: 1
keypadEventButton: scala.swing wrapper scala.swing.Button$$anon$1[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5,border=
javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@7633f09,flags=296,maximumSize=,minimumSize=,preferredSize=,de
faultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14]
,paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,te
xt=1,defaultCapable=true]
event: 2
keypadEventButton: scala.swing wrapper scala.swing.Button$$anon$1[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5,border=
javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@7633f09,flags=296,maximumSize=,minimumSize=,preferredSize=,de
faultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14]
,paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,te
xt=2,defaultCapable=true]
Key event button pressed: 1
Event triggered: 1
Event triggered: 2
Key event button pressed: 2
Event triggered: 1
Event triggered: 2
我完全不知道为什么会这样;我对Scala还是一个新手,所以这是一个非常陌生的领域,但我尝试过摆弄很多东西,并在Swing源代码中四处窥探,但仍然一无所知。。。如何在每次迭代中使用循环中引用的每个值?或者如何通过Swing一次触发每个事件?还是

编辑:这里有两个最小化版本,它们的行为都不同:

import scala.swing.SimpleSwingApplication

object ButtonEvents extends SimpleSwingApplication  {

import scala.swing.Button
import scala.swing.event.ButtonClicked
import scala.swing.Action
import scala.swing.MainFrame
import scala.swing.FlowPanel

override def top = new MainFrame {

    contents = new FlowPanel {

        val button1 = new Button(Action("1") {
        println("Button 1 pressed")

    })
        contents += button1
        val button2 = new Button(Action("2") {
        println("Button 2 pressed")

    })
        contents += button2
        val buttons = List(button1, button2)
        buttons.foreach({ button =>
            listenTo(button)
            reactions += {
                case ButtonClicked(button) => {
                    println("Event triggered: " + button.text)
                }
            }
        })


    }


}
}

印刷品:

Button 1 pressed
Event triggered: 1
Event triggered: 1
Button 2 pressed
Event triggered: 2
Event triggered: 2
和一个似乎表现正确的版本(但我不确定为什么):

打印(正确):

排队

reactions += {
  case ButtonClicked(keypadEventButton) => {
您正在创建一个新的
val keypadEventButton
,并将其分配给
ButtonClicked()中的任何内容。将行更改为
case按钮clicked(abstractButton)
仍将工作并显示相同的问题


我猜您希望这与前面几行中使用的
keypadEventButton
相匹配。您可能希望创建一个反应,然后使用
abstractButton
来判断按下了哪个按钮。

@andy是正确的。一个好的IDE想法会突出显示“变量模式的可疑阴影”,因为您在模式匹配中绑定了一个新变量。Scala允许您在嵌套代码块内对变量进行任意程度的阴影处理,例如:

scala> val a = 1; {val a = 2; println(a)}; println(a)
2
1
a: Int = 1
那么下面的返回是什么呢

val a = 1
2 match {
  case a => "it was 1"
  case _ => "something else"
}
它返回
“它是1”
,因为
a
是阴影。现在试试:

2 match {
  case `a` => "it was 1"
  case _ => "something else"
}
这将返回“something other”
,因为我们使用反勾号来引用先前定义的变量的值。(也可以在变量以大写字母开头时尝试此操作…)

因此,您只需要添加反勾号,即

case ButtonClicked(`button`) => {

tl;博士-你应该将代码归结为问题的本质问题是,当我试图“归结代码”时,我会得到不同(但相关)的行为,我不知道区别在哪里:这里有两个不同的版本,它们的行为与上面的不同:非常感谢阴影提示;然而,在ButtonClicked的给定情况下,我得到了一条“需要稳定的标识符,但找到了keypadEventButton”消息。尽管如此,我还是用这些信息和andy的(见上文)找到了一个解决方案。@erratlinguist这是因为您将
keypadEventButton
声明为
var
。除非您真的需要,否则不要使用
var
。将其声明为
val
,它应该是正常的。您也可以使用一个保护来更好地表达您上面写的内容:
caseB:ButtonClicked if b==keypadEventButton=>非常感谢您的帮助:我通过将
reactions
块替换为
reactions+={case ButtonClicked(abstractButton)=>{if(abstractButton==keypadEventButton){println(“事件触发:+Event”)来实现它的行为}}
val a = 1
2 match {
  case a => "it was 1"
  case _ => "something else"
}
2 match {
  case `a` => "it was 1"
  case _ => "something else"
}
case ButtonClicked(`button`) => {