提问者:小点点

SWT. KeyUp触发过于频繁


我在理解SWT中的关键事件时遇到了一些麻烦。我的程序在视窗8.1Java8下运行。
例如,我有一个文本字段,并尝试处理KeyUp:

textField.addListener(SWT.KeyUp, new Listener() {
  @Override
  public void handleEvent(Event e) {
  }
});

在handleEvent方法中,我将e. doit设置为false,然后尝试在箭头键、空格键或ALT字母等的某些组合之间进行区分。

我有点想知道,因为我的应用程序执行的任务不正确。所以我调试了coe,发现handleEvent方法每次都使用不同的事件对象执行三次。
这不好,因为在这种情况下,几乎不可能让它以预期的方式工作——每个调用都可以替换f. e.上一个调用的属性值。
我不知道原因:我按了一个键,处理程序方法被调用了三次。为什么?对我来说有点不合逻辑…

编辑

package mytest;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class Main {
  private static int i = 0;

  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    Text textField = new Text(shell, SWT.BORDER | SWT.READ_ONLY | SWT.SINGLE);
    textField.addListener(SWT.KeyUp, new Listener() {
      @Override
      public void handleEvent(Event e) {
        e.doit = false;
        System.out.println("Call #" + (++i) + ": keyCode=" + e.keyCode);
      }
    });

    shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}

您可以运行这个小示例,然后按f. e.ALT A、CTRL I或ARROW_DOWN,您会看到每次按都会调用句柄方法,这不是我对键侦听器的期望!


共2个答案

匿名用户

你要观察的是事件中的其他字段:

状态掩码:

生成事件时键盘修改键和鼠标掩码的状态。

关键位置:

根据事件,由keyCode或字符指定的键位置。此字段的可能值是SWT. LEFT、SWT.Right、SWT.KEYPAD或SWT.NONE,代表主键盘区域。

位置字段可用于区分具有相同键码和字符但由键盘上不同键生成的键事件。例如,键盘上的左右移位键可以生成键码等于SWT. SHIFT的下键事件。

位置字段只能用于确定键代码或字符在当前事件中的位置。它不包括有关状态掩码中修饰符位置的信息。

正确的预期行为是当每个键被释放时,您都会收到通知。将问题中的println替换为:

System.out.println("Call #" + (++i) + ": keyCode=" + e.keyCode + " stateMask=" + e.stateMask
        + " ctrlPressed=" + ((e.stateMask & SWT.CTRL) != 0) + " shiftPressed="
                + ((e.stateMask & SWT.SHIFT) != 0)+ " altPressed="
                        + ((e.stateMask & SWT.ALT) != 0));

您应该观察正确的行为。stateMask详细说明了状态(例如按下控制键)。

随着您的代码使用额外的打印进行更新,这就是您在控制台中看到的内容:

对于a

Call #11: keyCode=97 stateMask=0 ctrlPressed=false shiftPressed=false altPressed=false

对于ctrla,首先发布a

Call #14: keyCode=97 stateMask=262144 ctrlPressed=true shiftPressed=false altPressed=false
Call #15: keyCode=262144 stateMask=262144 ctrlPressed=true shiftPressed=false altPressed=false

对于ctrla,首先发布ctrl

Call #16: keyCode=262144 stateMask=262144 ctrlPressed=true shiftPressed=false altPressed=false
Call #17: keyCode=97 stateMask=0 ctrlPressed=false shiftPressed=false altPressed=false

对于ctrlshiftalta,首先发布a

Call #19: keyCode=97 stateMask=458752 ctrlPressed=true shiftPressed=true altPressed=true
Call #20: keyCode=65536 stateMask=458752 ctrlPressed=true shiftPressed=true altPressed=true
Call #21: keyCode=131072 stateMask=393216 ctrlPressed=true shiftPressed=true altPressed=false
Call #22: keyCode=262144 stateMask=262144 ctrlPressed=true shiftPressed=false altPressed=false

有很多地方您想知道是否只按下和/或释放了ctrl键。考虑将鼠标悬停在Eclipse中的方法或变量上并按下/释放ctrl

根据评论中提供的附加信息,OP希望允许用户创建加速器。

jface,SWT上面的层已经有这样一个类KeySequenceText(code: in git),

SWT文本小部件的包装器,用于捕获文字按键并将其转换为按键序列以供显示。显示的按键有两种类型:完整和不完整。完整的按键是带有自然键的按键,而不完整的按键没有自然键。不完整的按键只会显示,直到它们完成或释放其组件按键。

显然,我建议重用它,而不是旋转一个新的。它只是不到1000行已经被大量使用的代码,所以大概得到了很好的锻炼,而且(大部分!)bug免费的。

由于您在Eclipse平台之外使用SWT,如果您确实想采用这种方法,您也可以在平台之外使用jface。

匿名用户

通常添加了addListener的监听器几乎每次呼吸都会被非常频繁地调用。对于关键事件,使用

textField.addKeyListener( new KeyAdapter() 
{ 
   public void keyPressed( Event e ) 
} );