2012-08-30 5 views
1

내가 스칼라에서 GUI를 쓰고 있어요, 그리고 foreach 문에서 버튼 이벤트를 등록하는 동안 나는 이상한 문제에 걸쳐 실행했습니다를 등록합니다 : 그것은 모든 요소 개체에 대해 그렇게해야 내가 객체의 목록 (객체 0 ... 객체 N)에, 해당 버튼 X = I 버튼 가 검색되고 주어진 상자 box.listenTo(x)으로 가입된다. 단추를 누르면, 액션의 내가 수행해야 객체 (이 경우, println("Event triggered: " + event)) 관련 : 그러나스칼라 스윙 상자 여러 이벤트

import scala.swing.ComboBox 
import scala.collection.mutable.Buffer 
import scala.swing.Button 
import scala.swing.event.ButtonClicked 
import scala.swing.Action 
import scala.swing.SimpleSwingApplication 
import scala.swing.MainFrame 
import scala.swing.GridPanel 
import scala.swing.BorderPanel 


object EventSet extends SimpleSwingApplication { 

    object PhoneKeyEvent extends Enumeration { 
     val Key1 = Value("1") 
     val Key2 = Value("2") 
    } 

    /* Constants */ 

    private val DisplayHistory = Buffer[String]() 

    private val KeypadKeyEvents = List(
     PhoneKeyEvent.Key1, PhoneKeyEvent.Key2) 

    private val PhoneKeyEventButtonNames = Map(
     PhoneKeyEvent.Key1 -> "1", 
     PhoneKeyEvent.Key2 -> "2" 
     ) 

    /* End constants */   


    private var PhoneKeyEventButtons = Map[PhoneKeyEvent.Value, Button]() 

    private def createDisplay() : ComboBox[String] = { 

     new ComboBox(DisplayHistory) { 
      // Listen to keypad keys 
      // Get the set of all keypad key events 
      val keypadEvents = List(PhoneKeyEvent.Key1, PhoneKeyEvent.Key2) 
      println("keypadEvents: " + keypadEvents) 
      keypadEvents.foreach({ event => 
       println("event: " + event) 
       // Listen to each button representing a keypad key event 
       var keypadEventButton = PhoneKeyEventButtons(event) 
       println("keypadEventButton: " + keypadEventButton) 
       listenTo(keypadEventButton) 
       reactions += { 
        case ButtonClicked(keypadEventButton) => { 
        // TODO: fix strange bug here: adds all possible inputs 
        println("Event triggered: " + event) 


//      selection.item = selection.item + event 
        } 

       } 


      }) 
     } 

    } 

    private def createPhoneControllerPanel() : BorderPanel = { 
     new BorderPanel() { 
      val keypadControlPanel = createPhoneKeyEventTypeControlPanel(KeypadKeyEvents) 
      add(keypadControlPanel, BorderPanel.Position.Center) 

      add(createDisplay(), BorderPanel.Position.North) 


      focusable = true 
      requestFocus 
     } 
    } 

    /** 
    * Creates a new {@link Button} for a given {@link PhoneKeyEvent} and adds 
    * the button to the global map of such buttons to their respective events; 
    * that means multiple buttons cannot be created for the same key event. 
    */ 
    private def createPhoneKeyEventButton(phoneKeyEvent: PhoneKeyEvent.Value) : Button = { 
     // Only one button can be created per key event 
     require(!PhoneKeyEventButtons.contains(phoneKeyEvent), 
      {System.err.println("A Button for the PhoneKeyEvent " + phoneKeyEvent + "has already been created.")}) 

     val keyEventButtonName = PhoneKeyEventButtonNames(phoneKeyEvent) 

     val result = new Button(Action(keyEventButtonName) { 
      println("Key event button pressed: " + phoneKeyEvent) 

     }) 

     // Add the button to the map of all created key event buttons 
     PhoneKeyEventButtons += phoneKeyEvent -> result 
     return result 

    } 

    private def createPhoneKeyEventTypeControlPanel(keyEvents : Iterable[PhoneKeyEvent.Value]) : GridPanel = { 
     new GridPanel(4, 3) { 


      // Get the intersection of all key events of the given type and the events with button names 
      keyEvents.foreach(phoneKeyEvent => contents += createPhoneKeyEventButton(phoneKeyEvent)) 
     } 

    } 

    override def top = new MainFrame { 

     contents = createPhoneControllerPanel() 


    } 

} 

, 나는 매우 이상한 행동을 얻을의 모든 버튼 결과를 클릭 한 경우 모든 같은 오브젝트 작업은 트리거 - 프로그램 출력 참조 :

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= 
[email protected]09,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= 
[email protected]09,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 

내가 왜 이런 일이에 관해서는 손실에서 완전히이야을; 어쨌든 스칼라에서는 꽤 익숙하지 않으므로 익숙지 않습니다. 그러나 많은 것들을 가지고 놀고, 스윙 소스 코드에서 놀아 봤지만, 아직 우둔한 ... 어떻게 할 수 있습니다 ... 참조 값 루프의 내부는 매 반복마다 사용됩니까? 또는 한 번에 모든 이벤트가 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 

그리고 제대로 동작하는 것 같습니다 버전 ( 여기 다르게 행동 둘 다이 최소화 버전입니다 하지만 이유는 확실하지 않습니다.)

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 = Map("1" -> button1, "2" -> button2) 
      buttons.foreach({ eventButton => 
       listenTo(eventButton._2) 
       reactions += { 
        case ButtonClicked(eventButton._2) => { 
         println("Event triggered: " + eventButton._1) 
        } 
       } 
      }) 


     } 


    } 

} 

인쇄 (올바른) : 라인

reactions += { 
    case ButtonClicked(keypadEventButton) => { 

val keypadEventButton 만들고 내부 ButtonClicked() 무엇이든에 할당되어에서

Button 1 pressed 
Event triggered: 1 
Button 2 pressed 
Event triggered: 2 
+0

TL; DR - 당신의 본질에 코드를 졸이다한다 문제 –

+0

문제는 "코드를 끓여서"다른 (그러나 관련된) 동작을 얻으 려 할 때 차이점을 알 수 없다는 것입니다. 위에서 두 가지 다른 버전이 있습니다 : – errantlinguist

답변

1

. 줄을 case ButtonClicked(abstractButton)으로 변경하면 같은 문제가 계속 발생합니다.

위의 행에서 keypadEventButton의 사용과 일치 할 것으로 예상됩니다. 하나의 반응을 생성 한 다음 abstractButton을 사용하여 어떤 버튼이 눌려 졌는지 알 수 있습니다.

+0

감사합니다. lot에 대한 도움말 : 반응 블록을 'reactions' 블록으로 대체하여 원하는 방식으로 작동하도록했습니다. react + = { case ButtonClicked (abstr actButton) => { \t (AbstractButton에 == keypadEventButton가) { \t \t에 println은 ("이벤트가 트리거 :"경우 + 이벤트) \t} \t 을} }' – errantlinguist

1

@andy가 정확합니다. IDEA와 같은 좋은 IDE는 패턴 일치에서 새 변수를 바인딩하기 때문에 "변수 패턴에 의한 의심스러운 그림자"를 강조 표시합니다. 스칼라에서는 중첩 된 코드 블록 내에서 원하는만큼 변수를 쉐도 잉 할 수 있습니다. 예를 들면 다음과 같습니다.

scala> val a = 1; {val a = 2; println(a)}; println(a) 
2 
1 
a: Int = 1 

그러면 다음과 같은 결과가 나타납니다.a이 그림자 때문에

val a = 1 
2 match { 
    case a => "it was 1" 
    case _ => "something else" 
} 

그것은 "it was 1" 반환합니다. 지금 시도 : 우리는 그가 이전에 정의 된 변수의 값을 참조 역 따옴표를 사용했기 때문에

2 match { 
    case `a` => "it was 1" 
    case _ => "something else" 
} 

"something else"를 반환합니다. ,

그래서 그냥 역 따옴표를 추가해야합니다 (변수가 대문자로 시작되는 곳도 ... 이것을 시도) 즉

case ButtonClicked(`button`) => { 
+0

덕분에 그림자 팁을위한 많은; 그러나 주어진 경우에 ButtonClicked를 사용하면 "stable identifier required, keypadEventButton found"메시지가 나타납니다. 아직도, 나는이 정보와 앤디 (위 참조)를 사용하여 해결책을 찾았다. – errantlinguist

+0

@errantlinguist 그것은'keypadEventButton'을'var'으로 선언했기 때문입니다. 꼭 필요하지 않으면'var'을 사용하지 마십시오. 그것을'val'으로 선언하면 괜찮을 것입니다. 당신은 guard를 사용하여 위에서 썼던 문구를 대신 사용할 수도 있습니다 :'case b : bClick == keypadEventButton => ...' –