GWT文本框的即时值变化处理程序

27

当输入GWT文本框时,我希望能即时更新一个文本字段。我的问题是ValueChangeEvent和ChangeEvent处理程序只有在文本框失去焦点时才会触发。我考虑使用KeyPressEvent,但当使用鼠标进行复制粘贴操作时,什么也不会发生。

那最简单的方法是什么?

6个回答

36

您可以捕获 ONPASTE 事件并手动触发 ValueChangeEvent。类似以下代码:

public void onModuleLoad() {
    final Label text = new Label();
    final ExtendedTextBox box = new ExtendedTextBox();
    box.addValueChangeHandler(new ValueChangeHandler<String>() {

        @Override
        public void onValueChange(ValueChangeEvent<String> event) {
            text.setText(event.getValue());
        }

    });
    box.addKeyUpHandler(new KeyUpHandler() {

        @Override
        public void onKeyUp(KeyUpEvent event) {
            text.setText(box.getText());
        }
    });

    RootPanel.get().add(box);
    RootPanel.get().add(text);
}

private class ExtendedTextBox extends TextBox {

    public ExtendedTextBox() {
        super();
        sinkEvents(Event.ONPASTE);
    }

    @Override
    public void onBrowserEvent(Event event) {
        super.onBrowserEvent(event);
        switch (DOM.eventGetType(event)) {
            case Event.ONPASTE:
                Scheduler.get().scheduleDeferred(new ScheduledCommand() {

                    @Override
                    public void execute() {
                        ValueChangeEvent.fire(ExtendedTextBox.this, getText());
                    }

                });
                break;
        }
    }
}

在 Firefox 3.6.1 上进行了测试。


1
谢谢。这对我有用。需要注意的一件事是,延迟命令是必需的,因为在处理粘贴事件时,文本框尚未包含感兴趣的文本。如果您正在尝试过滤文本框的内容(在我的情况下,是有效字符),请注意用户会瞬间看到已粘贴的文本。有人知道如何解决这个问题吗?从我所读的资料来看,FF不允许剪贴板检查,但IE和Webkit都可以? - ShabbyDoo
你可以在验证完成之前隐藏TextBox的内容。这确实是一种hack方法,但是color: transparent可以解决问题... - z00bs
@z00bs 这个能否在不扩展TextArea和使用UiBinder的情况下完成? - alexandroid
我怀疑这一点,因为你需要在onBrowserEvent()中扩展行为。 - z00bs
2
很好的答案,但在最近的GWT版本中,DeferredCommand已被弃用,推荐使用Scheduler.get().scheduleDeferred(...)。 - Renato
不必扩展 TextBox,您可以像这样简单地使用 JSNI: https://dev59.com/UlHTa4cB1Zd3GeqPRGU7#4018317 - kroiz

4

作为一种通用解决方案,对我有用的是(感谢gal-bracha评论):

一般来说,GWT没有处理输入事件的类(在此描述herehere)。所以我们需要自己实现它:

处理程序类:

import com.google.gwt.event.shared.EventHandler;

public interface InputHandler extends EventHandler {

  void onInput(InputEvent event);

}

事件类:

import com.google.gwt.event.dom.client.DomEvent;

public class InputEvent extends DomEvent<InputHandler> {

    private static final Type<InputHandler> TYPE = new Type<InputHandler>("input", new InputEvent());

    public static Type<InputHandler> getType() {
        return TYPE;
    }

    protected InputEvent() {
    }

    @Override
    public final Type<InputHandler> getAssociatedType() {
        return TYPE;
    }

    @Override
    protected void dispatch(InputHandler handler) {
        handler.onInput(this);
    }

}

使用方法:

box.addDomHandler(new InputHandler() {

    @Override
    public void onInput(InputEvent event) {
        text.setText(box.getText());
    }
},InputEvent.getType());

它适用于每次文本框值的更改,包括使用上下文菜单粘贴。它不会对箭头、Ctrl、Shift等做出反应...


在 new Type<InputHandler> 之后缺少“(”符号。 - Alicia
在创建过程中我遇到了这个错误:异常2(字符串):尝试接收未知的事件类型输入。 - Joseph Larson
非常好的回答!谢谢。 - Sir Hackalot

1
这在过去对我来说一直是一个重要的问题。 keyupHandler不起作用,因为复制粘贴需要在粘贴选项上进行第二次按键,这不会触发事件。我能做到的最好的办法是使用旧的changelistener,虽然不理想但它确实可以工作。

1
最好使用“input”事件,但我不确定如何从gwt中访问它。 它处理粘贴和键盘,因为当值实际更改时引发该事件。 https://developer.mozilla.org/en/DOM/DOM_event_reference/input - Gal Bracha

1

我更喜欢使用元素而不是小部件,所以这是我的处理方式。

    Element input = Document.get().getElementById("my-input");
    DOM.sinkBitlessEvent(input, "input");
    DOM.setEventListener(input, event -> GWT.log("Event!"));

0
Just saw this question. Because I was facing the similar problem. 

做了一些黑客行为,对我起作用了。 您可以使用KeyUpHandler,但使用它时需要添加if块来检查文本框的长度。 如果文本框的长度大于0,请执行你要做的事情。 示例:

textBox.addKeyUpHandler(new KeyUpHandler() {
    @Override
    public void onKeyUp(KeyUpEvent keyUpEvent) {
    if (textBox.getText().length() > 0) {
    //do your stuff`enter code here`

    }
    }

这并不考虑将值拖入框中的情况,也会在释放左/右键和ctrl键时触发。 - WORMSS
true,这将适用于包含文本的打字。我猜这对这个问题有用。这只是一个hack ;) - Bikas Katwal

0
为什么不在文本框上同时使用KeyUpHandler和ChangeHandler的组合呢? 这样可以在每次按键时提供即时反馈,也可以处理复制粘贴的情况。

正如我所说,ChangeHandler 只有在 TextBox 失去焦点时才会触发,但我希望能够在用户输入时立即更新我的字段。 - Jla
嗯...你想出方法了吗?请在你找到解决方案后分享 :) 谢谢 - Ashwin Prabhu
最终,我正在处理的应用程序接受了失去焦点时的行为更改。因此,我从未找到解决方案,并将其暂时搁置。但如果我找到了解决方案,我将会更新这个问题。 - Jla
最好的方法是使用input事件,但我不确定如何从gwt中访问它。 它可以处理粘贴和键盘输入,并在值实际改变时触发。 https://developer.mozilla.org/en/DOM/DOM_event_reference/input - Gal Bracha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接