2014-02-12 47 views
2

我對Scala很新,但它似乎是一種非常有趣的語言,我想學習。目前,我一直在研究各種簡單的應用程序來學習這門語言。從基本語法到網絡等,我只是想牢牢掌握語言和圖書館的工作方式。Scala GUI - 事件處理

截至目前,我正在一個簡單的GUI計算器。構建GUI非常簡單,我對它的實際可視化組件毫無疑問。問題出在互動部分。出於某種原因,我無法弄清楚如何通過按鍵來實現某種全球焦點。這可能是一個糟糕的方式來說話,但這就是我的意思。除了程序第一次打開時,我無法讓程序響應我的按鍵。我相信問題出在焦點所在,但我無法弄清楚。

這是我的(略剝)代碼:

package SimplePrograms 

import scala.swing._ 
import javax.swing.{BorderFactory, UIManager} 
import scala.swing.event.{Key, KeyPressed} 

/** 
* Created by Tony on 2/9/14. 
*/ 
object SimpleCalculator { 
    def main(args: Array[String]){ 
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel") 
    val calculator = new CalcGrid 
    val frame = new MainFrame{ 
     title = "Calculator" 
     contents = calculator.CalcPanel() 
     listenTo() 
     reactions += { 
     case KeyPressed(_,Key.Numpad1,_,_) 
     => calculator.numTxt.text += "1" 
     } 
     size = new Dimension(200,270) 
     centerOnScreen() 
     resizable = false 
    } 
    frame.open() 
    } 
} 

class CalcGrid(){ 
    var numTxt = new TextField(" "){ 
    font = new Font("Arial",0,40) 
    background = new Color(200,130,20) 
    opaque = true 
    border = BorderFactory.createCompoundBorder(
     BorderFactory.createLoweredBevelBorder(), 
     BorderFactory.createEmptyBorder(0,5,0,5)) 
    editable = false 
    horizontalAlignment = Alignment.Right 
    } 
    val btn1 = new Button("1"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn2 = new Button("2"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn3 = new Button("3"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn4 = new Button("4"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn5 = new Button("5"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn6 = new Button("6"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn7 = new Button("7"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn8 = new Button("8"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn9 = new Button("9"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btn0 = new Button("0"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btnPeriod = new Button("."){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btnEqual = new Button("="){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,60) 
    } 
    val btnMinus = new Button("-"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 
    val btnPlus = new Button("+"){ 
    font = new Font("Arial",0,20) 
    background = new Color(200,130,20) 
    preferredSize = new Dimension(40,35) 
    } 

    def CalcPanel(): GridBagPanel = { 
    val contents = new GridBagPanel(){ 
     var c = new Constraints() 
     c.gridx = 0 
     c.gridy = 0 
     c.gridwidth = 4 
     c.insets = new Insets(3,3,3,3) 
     c.fill = GridBagPanel.Fill.Horizontal 
     add(numTxt,c) 

     c.gridwidth = 1 
     c.fill = GridBagPanel.Fill.None 

     c.gridx = 0 
     c.gridy = 1 
     add(btn7,c) 

     c.gridx = 1 
     c.gridy = 1 
     add(btn8,c) 

     c.gridx = 2 
     c.gridy = 1 
     add(btn9,c) 

     c.gridx = 0 
     c.gridy = 2 
     add(btn4,c) 

     c.gridx = 1 
     c.gridy = 2 
     add(btn5,c) 

     c.gridx = 2 
     c.gridy = 2 
     add(btn6,c) 

     c.gridx = 0 
     c.gridy = 3 
     add(btn1,c) 

     c.gridx = 1 
     c.gridy = 3 
     add(btn2,c) 

     c.gridx = 2 
     c.gridy = 3 
     add(btn3,c) 

     c.gridx = 3 
     c.gridy = 1 
     add(btnMinus,c) 

     c.gridx = 3 
     c.gridy = 2 
     add(btnPlus,c) 

     c.gridx = 0 
     c.gridy = 4 
     c.gridwidth = 2 
     c.fill = GridBagPanel.Fill.Horizontal 
     add(btn0,c) 
     c.gridwidth = 1 
     c.fill = GridBagPanel.Fill.None 

     c.gridx = 2 
     c.gridy = 4 
     add(btnPeriod,c) 

     c.gridx = 3 
     c.gridy = 3 
     c.gridheight = 4 
     c.fill = GridBagPanel.Fill.Vertical 
     add(btnEqual,c) 
    } 
    contents 
    } 
} 

我的馬虎代碼道歉,但正如我所說,只是掀起了東西快。在測試各種代碼選項並搜索互聯網的過程中,我一直在爲此工作幾天。

任何幫助?

編輯:作爲一個快速筆記,我意識到listenTo方法在其他一些問題中沒有填充參數,但是這是在經歷了一些令人煩惱的試驗和錯誤時刻之後,我認爲發佈了多個版本可能不需要。

回答

2

您的方法通常是正確的。但是,使用listenTo方法時,您必須使用正確的發佈者。例如,如果你寫的下面,你將能夠輸入「1」時,用標有「1」按鈕的重點是:

listenTo(calculator.btn1.keys) 

的關鍵事件是由特殊的出版商.keys而不是組件調度本身。

因此,這裏最簡單的方法是傾聽每計算器的每個組件(所有的按鈕和麪板)

listenTo(calculator.btn1.keys, calculator.btn2.keys, ...) 

在Swing中,關鍵事件不會自動向上冒泡的組件層次結構,但只會分派給具有焦點的組件。 (Java)Swing中有另一種方法稱爲鍵綁定。有關概述,請參閱:

您可以使用第二種方法來監聽在活動窗口中任意按鍵。然而,作爲一名Scala初學者,這可能會令人困惑,因爲您將不得不使用Java Swing而不是Scala Swing包裝層。是完整的,我展示如何做到這一點一般都做:

import javax.swing.{JComponent, KeyStroke} // Java world 

val calculator = new CalcGrid 
val frame = new Frame{ 
    title = "Calculator" 
    val panel = calculator.CalcPanel()  
    contents = panel 
    val act1 = Action("key1") { 
    calculator.numTxt.text += "1" 
    } 
    // the mapping is done in your top component, so `panel`. 
    // you must use the input map which is active whenever the window 
    // in which the panel is located has focus: 
    val imap = panel.peer.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) 
    val amap = panel.peer.getActionMap 
    // you need to map a KeyStroke to an (arbitrarily chosen) action name, 
    // and that action name to the action itself. 
    imap.put(KeyStroke.getKeyStroke(Key.Numpad1.id, 0), "key1") 
    imap.put(KeyStroke.getKeyStroke(Key.Key1 .id, 0), "key1") // can map several keys 
    amap.put("key1", act1.peer) 

    size = new Dimension(200,270) 
    centerOnScreen() 
    resizable = false 
} 
frame.open() 
+0

我從您的文章得到什麼: 1.要具有「全球性」的聽衆,你必須列出幀中的每個組件。 2.要進行鍵綁定,您必須創建一個包含輸入源的映射以及指定要執行的操作的鍵。每次調用某個動作時,都會檢查按下了哪個按鍵,並使用關聯的按鍵執行動作。 我對來自多個大學課程的Java使用有非常一般的知識。我唯一的問題是將其集成到Scala中。我之前沒有「跨語言」的經驗,所以混合代碼有點嚇人。 非常感謝您的幫助! – Stalin4Time

+1

@ Stalin4Time是正確的。如果您不想深入到Javax Swing中,您將不得不傾聽可能獲得焦點的每個組件。另一種方法是僅偵聽最上面的組件,但是必須使用鍵綁定(輸入映射)。目前的輸入映射功能並不是直接在Scala包裝層中實現的。 –