java - 抽象输入 validator 和 JDialog 类

标签 java swing

我正在尝试理解我遇到的一个类 here验证我拥有的一些 JTextArea 上的输入。我已经让它工作得很好,但我对一些逻辑感到困惑,特别是使用 JDialog 作为父组件,并希望有人可以帮助我更好地理解它。

抽象 validator 类:

package gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.BorderFactory;
import javax.swing.InputVerifier;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.border.BevelBorder;

public abstract class AbstractValidator extends InputVerifier implements KeyListener{

private JDialog popup;
private Object parent;
private JLabel messageLabel;
private JLabel image;
private Point point;
private Dimension cDim;
private Color color;

private AbstractValidator(){
    color = new Color(243,255,159);
}

private AbstractValidator(JComponent c, String msg){
    this();
    c.addKeyListener(this);
    messageLabel = new JLabel(msg + " ");
    //image = new JLabel();         
}

public AbstractValidator(JDialog parent, JComponent c, String msg){
    this(c,msg);
    this.parent = parent;
    popup = new JDialog(parent);
    initComponents();
}

//implement the actual validation logic, returning false if the data is 
//invalid and true if it is not. you can also set the popup msg text with
//setMessage() before returning.
//param c is the component to be validated

protected abstract boolean validationCriteria(JComponent c);

//this method is called by Java when a component needs to be validated. 
//it should not be called directly. Don't override this unless you want to change
//validation behaviour. implement validationCriteria() instead.

@Override
public boolean verify(JComponent c){
    if(!validationCriteria(c)){
        if(parent instanceof Validatable)
            ((Validatable)parent).validateFailed();

        c.setBorder(BorderFactory.createLineBorder(Color.RED));
        popup.setSize(0,0);
        popup.setLocationRelativeTo(c);
        point = popup.getLocation();
        cDim = c.getSize();
        popup.setLocation(point.x-(int)cDim.getWidth()/2, point.y+(int)cDim.getHeight()/2);
        popup.pack();
        popup.setVisible(true);
        return false;
    }
    c.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
    if(parent instanceof Validatable)
        ((Validatable)parent).validatePassed();
    return true;
}

protected void setMessage(String msg){
    messageLabel.setText(msg);   
}

@Override
public void keyPressed(KeyEvent e){
    popup.setVisible(false);
}

@Override
public void keyTyped(KeyEvent e){
}
@Override
public void keyReleased(KeyEvent e){}

private void initComponents(){
    popup.getContentPane().setLayout(new FlowLayout());
    popup.setUndecorated(true);
    popup.getContentPane().setBackground(color);
    popup.getContentPane().add(messageLabel);
    popup.setFocusableWindowState(false);

}
}

具体类:

package gui;

import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JTextField;

public class NotEmptyValidator extends AbstractValidator{
    public NotEmptyValidator(JDialog parent, JTextField c, String msg){
        super(parent,c, msg);
    }

    protected boolean validationCriteria(JComponent c){
        if(((JTextField)c).getText().equals("")){
            return false;
        }
        return true;
    }
}

(未使用的)界面:

package gui;

public interface Validatable {
    void validateFailed();
    void validatePassed();
}

在主 JPanel 中的 JTextField 上使用具体类:

textField.setInputVerifier(new NotEmptyValidator(new JDialog(), textField, "msg"));    

首先(但不重要)我很困惑为什么作者将抽象类中的构造函数分开?但我认为这并不特别重要。

正如前面提到的,我对 JDialog 的使用更加困惑。 从上面链接中的描述以及使用instanceof然后调用接口(interface)方法的代码来看,它看起来像是在首先调用verify()(由java)然后调用实现的方法'validationCriteria( )'。

但令我困惑的是,它是一个 JDialog,为什么它不只是一个 JComponent?我认为我在这里缺少一些基础知识 - 这就是为什么我对具体类的实例化只使用"new"JDialog - 尽管我将阅读 inputverifier 上的 oracle 踪迹,因为我认为此类设计中的一些可能是也有点过分了......

最佳答案

As mentioned though, I'm more confused about the use of a JDialog thoughout. From the description in the above link, and the code that uses instanceof and then calls the interface methods, it looks like it is used to manipulate other components when first verify() is called (by java) followed by the implemented method 'validationCriteria()'.

他们似乎使用JDialog(或JFrame)作为自己内部JDialog的引用点,用于显示消息当验证失败时。这是 JDialog 的一个(可选)要求,它允许将其放置在调用它的父窗口上

根据示例代码,我想说他们只是作弊,虽然我没有测试过它,但您可以传递 null (但您必须将其转换为 JDialogJFrame)

可能也有点旧(或者他们不知道一些附加的 API 功能),因为他们可以使用 setLocationRelativeTo 而不是手动定位对话框

进入本质,validationCriteria 是您为组件提供验证的地方,正如您所描述的,这是由 verify 调用的。这提供了作者可以控制验证过程并实现其定制的方法。请记住,c 是对您尝试验证的JComponent 的引用(即JTextArea)

作者以WantsValidationStatus的形式提供了额外的自定义,可以通过parent(JDialogJFrame),它提供了一种通知验证过程状态的方法

Firstly (but unimportantly) I'm confused as to why the author has separated the constructors in the abstract class? I don't think it particularly matters though.

我的猜测是,他们想要提供灵活的安排,但不理解 Swing API 提供的一些功能,例如。您可以将构造函数的数量减少到 1 个并使用 SwingUtilities#windowForComponent获取对包含该组件的窗口的引用

But it's the fact that it's a JDialog that confuses me, why wouldn't it just be a JComponent? I think I'm missing some fundamental knowledge here - which is why my instantiation of the concrete class just uses a 'new' JDialog - although I am going to be reading the oracle trail on inputverifier because I think some of this class design might be a bit overkill too....

好吧,其他两条评论现在应该已经回答了这个问题:P

离别感想

在我看来,这有点错误。我没有通过构造函数将任何组件传递给类,它不负责显示消息或采取其他操作,它的工作只是验证组件并返回 true/ false(然后控制焦点横向)。

在我看来,InputVerifier 最好支持观察者模式,然后生成 validationFailed/validationPassed (或这样)事件并让其他一些代表决定应该做什么,但仅此而已;)

关于java - 抽象输入 validator 和 JDialog 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43742491/

相关文章:

java - 没有 print 语句的代码不执行

java - java中setFocusable的使用

java - 突出显示 JTable 中带有图标的单元格

java - 具有指定分辨率的独立于平台的全屏 JFrame?

java - Procmail 配方,管道到 Java 标准输入

java - 获取 Group 与 Asterisk 的匹配项?

java - 表的最后一列扭曲了查询结果

java - 如何让html改变java中变量的值?

java - 如何从另一个Java类中的JTextfield读取用户输入

java - 包之间的继承不存在?