FocusListener回调方法不适用于来自同一变量的单独实例化对象?

时间:2012-05-24 17:37:02

标签: java constructor callback focuslistener

我目前正在研究我们小组第一学期考试项目的GUI部分,我遇到了一个关于回调和事件处理的奇怪问题。

有点偏离主题:我已经搜索过这么难了,但实际上没有找到任何在Java中使用回调的具体例子,所以从我收集的内容......根据定义......我在做什么这里实际上是一个回调(如果你能解释原因会很棒,或者指向一个彻底解释它的页面)

以下是代码:

private FocusListener callback = new FocusListener(){
    @Override public void focusGained(FocusEvent e){
        if(hasBeenSet){}else{tfield.setText("");hasBeenSet=true;}
    } @Override public void focusLost(FocusEvent e){}};

    ...

    tfield = new JTextField("Insert CPR number", 8);
    constraint.gridx = 0;
    constraint.gridy = 1;
    constraint.gridwidth = 2;
    panel.add(tfield, constraint);

            tfield.addFocusListener(callback);

    tfield = new JTextField("Type new password", 8);
    constraint.gridx = 0;
    constraint.gridy = 2;
    panel.add(tfield, constraint);

            tfield.addFocusListener(callback);

    tfield = new JTextField("Retype new password", 8);
    constraint.gridx = 0;
    constraint.gridy = 3;
    panel.add(tfield, constraint);

            tfield.addFocusListener(callback);

当我启动GUI时,它有三(3)个文本字段,其目的是在用户关注文本字段时删除文本。这适用于所有三个文本字段,但显然,无论您单击哪个文本字段,只有最后一个文本字段被设置为空字符串。我对此非常好奇,因为每个对象都是单独实例化的。

这里显而易见的解决方法是将tfield重命名为“tfield [1-3]”,但如果你能用这个幽默我会很棒:)

另外:请注意,所有GUI代码实际上都在构造函数中。是的,我知道这是完全荒谬的,但是我们的设计表明所有的逻辑和数据处理都会在构造函数完成之后发生......所以每次说不应该有任何威胁,但我不知道这是否会以某种方式冲突了FocusListener的回调方法。

谢谢。 :)

P.S。对于“重新/输入新密码”字段,我确认JComponent JPasswordField,并且在修复此问题后将更改该字段。所以不需要安全警告:)

1 个答案:

答案 0 :(得分:2)

tfield变量保存对JTextField last 实例的引用。做你想做的事是这样的:

private FocusListener callback = new FocusListener() {
    @Override public void focusGained(FocusEvent e){
        JTextField jtf = (JTextField) e.getSource();
        if(hasBeenSet){}else{jtf.setText("");hasBeenSet=true;}
    }
    ...

注意:当您的代码正在读取时,hasBeenSet将在所有3个文本字段中共享。

<强>更新

Java不支持闭包,因此当focusGained运行时,它会看到tfield的最后一个值,而不是安装listerner时的值tfield

看起来hasBeenSet被定义为外部类的成员,因此focusGained正在检查所有3个文本字段的相同的变量。这是一种处理我认为你想要做的事情的方法:

tfield = new JTextField("Insert CPR number", 8);
tfield.putClientProperty("originalText", tfield.getText());

然后在焦点上:

    @Override public void focusGained(FocusEvent e){
        JTextField jtf = (JTextField) e.getSource();
        if(jtf.getClientProperty("originalText").equals(jtf.getText())){
             jtf.setText("");
        }
    }

putClientProperty/getClientProperty类在JComponent类中定义,因此这些方法在从JComponent继承的每个Swing GUI组件中都可用。它们存储/检索给定字符串的Object。在这种情况下,字符串“originalText”包含最初用于初始化JTextField的值。获得焦点后,如果该字段仍包含该值,则将其设置为空白。同样,您可以在focusLost中执行类似的操作,如果该字段为空,则将其设置为为“originalText”检索的值。