2014-02-12 2 views
2

Я очень новичок в Scala, но мне кажется, что это очень интересный язык, который я хотел бы изучить. В настоящее время я изучаю различные простые приложения для изучения языка. От базового синтаксиса до сетей и т. Д. Я просто пытаюсь понять, как работают язык и библиотеки.Scala 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. –

Смежные вопросы