Java Scala GUI-事件处理

Java Scala GUI-事件处理,java,swing,scala,events,user-interface,Java,Swing,Scala,Events,User Interface,我对Scala很陌生,但它似乎是一门非常有趣的语言,我很想学习。目前,我一直在开发各种简单的应用程序来学习这门语言。从基本语法到网络等等,我只是想牢牢掌握语言和库是如何工作的 现在,我正在使用一个简单的GUI计算器。构建GUI相当简单,我对它的实际可视化组件没有任何疑虑。问题在交互部分。出于某种原因,我不知道如何通过按键来实现某种全球关注。这可能是一个糟糕的表达方式,但这就是我的意思。我无法让程序响应我的按键,除非程序第一次打开。我相信问题在于焦点在哪里,但我不明白 以下是我的(稍微精简)代码:

我对Scala很陌生,但它似乎是一门非常有趣的语言,我很想学习。目前,我一直在开发各种简单的应用程序来学习这门语言。从基本语法到网络等等,我只是想牢牢掌握语言和库是如何工作的

现在,我正在使用一个简单的GUI计算器。构建GUI相当简单,我对它的实际可视化组件没有任何疑虑。问题在交互部分。出于某种原因,我不知道如何通过按键来实现某种全球关注。这可能是一个糟糕的表达方式,但这就是我的意思。我无法让程序响应我的按键,除非程序第一次打开。我相信问题在于焦点在哪里,但我不明白

以下是我的(稍微精简)代码:

我很抱歉代码太草率,但正如我所说的,我只是快速地做了一些事情。这方面的工作已经进行了几天,只需测试各种代码选项并搜索互联网

有什么帮助吗


编辑:作为一个简要说明,我意识到listenTo方法在其他一些问题中没有填充参数,但这是在经过了一些令人恼火的尝试和错误时刻之后,我认为可能不需要发布多个版本。

您的方法通常是正确的。但是,在使用
listenTo
方法时,必须使用正确的发布者。例如,如果您编写以下内容,则当标签为“1”的按钮处于焦点时,您将能够键入“1”:

listenTo(calculator.btn1.keys)
密钥事件由特殊发布者
.keys
而不是组件本身发送

因此,这里最简单的方法是聆听计算器的每个组件(所有按钮和面板)


在Swing中,键事件不会自动在组件层次结构中冒泡,而只会被分派到具有焦点的组件。在(Java)Swing中还有另一种方法,称为键绑定。有关概述,请参阅:

您可以使用第二种方法在活动窗口中的任意位置收听按键。但是,作为Scala初学者,这可能会让人困惑,因为您将不得不使用JavaSwing而不是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()

我从你的帖子中得到:1。要拥有“全局”侦听器,必须列出框架中的每个组件。2.要进行键绑定,您必须创建一个包含输入源的映射以及一个指定要执行的操作的键。每次调用操作时,它都会检查按下了什么键,并使用相关键执行操作。我在多个大学课程中对Java的使用有着非常广泛的了解。我唯一的问题是将它集成到Scala中。我以前没有“跨语言”的经验,所以混合代码有点吓人。非常感谢你的帮助@斯大林时间是正确的。如果您不想深入研究javaxswing,那么您将不得不倾听可能获得关注的每个组件。另一种方法是只侦听最顶层的组件,但随后必须使用键绑定(输入映射)。目前,输入映射功能没有直接在Scala包装层中实现。
listenTo(calculator.btn1.keys, calculator.btn2.keys, ...)
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()