简体   繁体   English

从内部类引用

[英]Referencing from an inner class

I have the following code我有以下代码

import javax.swing.*;
import java.awt.*;
import net.miginfocom.swing.MigLayout;
import Sorts.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.Color;

public class SortsGui
{
    JFrame myMainWindow = new JFrame("Sorts");

    JPanel sortPanel = new JPanel();

    //first panel components
    public int nextTextBox = 20;
    JTextField[] allField = new JTextField [25];
    //end first panel

    public void runGUI()
    {
        myMainWindow.setBounds(10, 10, 800, 800);
        myMainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        myMainWindow.setLayout(new GridLayout(1,1));

        createSortTestPanel();

        myMainWindow.getContentPane().add(sortPanel);

        myMainWindow.setVisible(true);
    }

    public void createSortTestPanel()
    {
        MigLayout layout = new MigLayout("" , "[grow]");
        sortPanel.setLayout(layout);

        refreshScreen();
    }

    public void refreshScreen()
    {
        sortPanel.removeAll();

        for(int i = 0; i<nextTextBox;i++)
        {
            int fix = i+1;
            allField[i] = new JTextField("");
            sortPanel.add(allField[i],"growx");
            allField[i].addKeyListener(new KeyListener ()
            {
                public void keyPressed(KeyEvent e)
                {

                }

                public void keyReleased(KeyEvent e)
                {

                }

                public void keyTyped(KeyEvent e)
                {
                    char c = e.getKeyChar();
                    if(Character.isDigit(c))
                    {

                    }

                    else 
                    {
                        e.consume();
                    }

                    try
                    {
                        int parseTest = Integer.parseInt(allField[i].getText());
                    }

                    catch(Exception exc)
                    {
                        allField[i].setBackground(Color.RED);
                    }
                }
            });
        }
    }

    public static void main(String[] args)
    {
        SortsGui sG = new SortsGui();
        sG.runGUI();
    }
}

My aim here is to create an array of JTextFields which have a keylistener on.我的目标是创建一个 JTextField 数组,其中有一个键侦听器。 This keylistener should prevent anything other than numbers being entered in the JTextField.此密钥侦听器应防止在 JTextField 中输入数字以外的任何内容。 It should also change the color of the JTextField's background if the number entered is not an int.如果输入的数字不是整数,它还应该更改 JTextField 背景的颜色。 For example 2147483647554. However when I compile this I get the error例如 2147483647554。但是当我编译这个时,我得到了错误

内部类错误

So how do I make this so that it is either final or effectively final on all the JTextFields?那么我如何做到这一点,以便它在所有 JTextField 上都是最终的或有效的最终结果?

My aim here is to create an array of JTextFields which have a keylistener on.我的目标是创建一个 JTextField 数组,其中有一个键侦听器。 This keylistener should prevent anything other than numbers being entered in the JTextField此密钥侦听器应防止在 JTextField 中输入数字以外的任何内容

The short answer to thus is, don't use KeyListener , it won't capture the use cases of the user pasting text into the field or if the field is updated programmatically因此,简短的回答是,不要使用KeyListener ,它不会捕获用户将文本粘贴到字段中的用例,或者该字段是否以编程方式更新

Instead you want to use a DocumentFilter , for example相反,您想使用DocumentFilter ,例如

public class IntFilter extends DocumentFilter {

    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {

        StringBuilder buffer = new StringBuilder(text.length());
        for (int index = 0; index < text.length(); index++) {
            if (Character.isDigit(text.charAt(index))) {
                buffer.append(text.charAt(index));
            }
        }
        super.insertString(fb, offset, buffer.toString(), attr);
        ValidationListener listener = getValidationListener();
    }

    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
        if (length > 0) {
            fb.remove(offset, length);
        }
        insertString(fb, offset, string, attr);
    }
}

See Implementing a Document Filter for more details and DocumentFilter Examples for more examples有关更多详细信息,请参阅实现文档过滤器,有关更多示例,请参阅DocumentFilter示例

It should also change the color of the JTextField's background if the number entered is not an int如果输入的数字不是 int,它还应该更改 JTextField 背景的颜色

You can do post validation using a InputVerifier , but that might not meet your needs.您可以使用InputVerifier进行后期验证,但这可能无法满足您的需求。

This creates a problem.这就产生了一个问题。 The DocumentFilter , shouldn't care about the field it's applied to, but since, it's doing the validation, it will know when something has gone wrong, so we need some way for the filter to provide notification when the validation fails... DocumentFilter不应该关心它应用到的字段,但是因为它正在执行验证,所以它会知道什么时候出现问题,所以我们需要某种方式让过滤器在验证失败时提供通知......

First, we need some callback which tells us when validation has failed or passed...首先,我们需要一些回调来告诉我们验证何时失败或通过...

public interface ValidationListener {

    public void validationFailed();

    public void validationPassed();
}

Then we need to update the filter to raise those notifications based on it's rules...然后我们需要更新过滤器以根据它的规则发出这些通知......

public class IntFilter extends DocumentFilter {

    private ValidationListener validationListener;

    public void setValidationListener(ValidationListener validationListener) {
        this.validationListener = validationListener;
    }

    public ValidationListener getValidationListener() {
        return validationListener;
    }

    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {

        boolean validationFailed = false;
        StringBuilder buffer = new StringBuilder(text.length());
        for (int index = 0; index < text.length(); index++) {
            if (Character.isDigit(text.charAt(index))) {
                buffer.append(text.charAt(index));
            } else {
                validationFailed = true;
            }
        }
        super.insertString(fb, offset, buffer.toString(), attr);
        ValidationListener listener = getValidationListener();
        if (listener != null) {
            if (validationFailed) {
                listener.validationFailed();
            } else {
                listener.validationPassed();
            }
        }
    }

    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
        if (length > 0) {
            fb.remove(offset, length);
        }
        insertString(fb, offset, string, attr);
    }
}

Then we need to define our implementation of the ValidationListener to perform the actions we need...然后我们需要定义ValidationListener的实现来执行我们需要的操作......

public class DefaultValidationHandler implements ValidationListener {

    private JTextField field;

    public DefaultValidationHandler(JTextField field) {
        this.field = field;
    }

    public JTextField getField() {
        return field;
    }

    @Override
    public void validationFailed() {
        getField().setBackground(Color.RED);
    }

    @Override
    public void validationPassed() {
        getField().setBackground(UIManager.getColor("TextField.background"));
    }

}

Here, the listener maintains a reference to the field which we want to control在这里,侦听器维护对我们要控制的字段的引用

Then we bind it altogether...然后我们将它完全绑定...

JTextField field = new JTextField(10);
DefaultValidationHandler handler = new DefaultValidationHandler(field);
IntFilter filter = new IntFilter();
filter.setValidationListener(handler);
((AbstractDocument)field.getDocument()).setDocumentFilter(filter);

筛选

This is all a bit crude, but it gets the basic idea across.这有点粗糙,但它传达了基本思想。

Some improvements might include passing the reference of the DocumentFilter back via the methods of the ValidationListener , you could then use this to lookup the field which triggered the event and update it, reducing the number of handlers you might need to create, for example.一些改进可能包括通过ValidationListener的方法将DocumentFilter的引用传回,然后您可以使用它来查找触发事件的字段并更新它,例如减少您可能需要创建的处理程序的数量。

For example例如

Updated ValidationListener更新的验证监听器

public interface ValidationListener {

    public void validationFailed(DocumentFilter filter);

    public void validationPassed(DocumentFilter filter);
}

Updated IntFilter更新的 IntFilter

public class IntFilter extends DocumentFilter {

    private ValidationListener validationListener;

    public void setValidationListener(ValidationListener validationListener) {
        this.validationListener = validationListener;
    }

    public ValidationListener getValidationListener() {
        return validationListener;
    }

    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {

        boolean validationFailed = false;
        StringBuilder buffer = new StringBuilder(text.length());
        for (int index = 0; index < text.length(); index++) {
            if (Character.isDigit(text.charAt(index))) {
                buffer.append(text.charAt(index));
            } else {
                validationFailed = true;
            }
        }
        super.insertString(fb, offset, buffer.toString(), attr);
        ValidationListener listener = getValidationListener();
        if (listener != null) {
            if (validationFailed) {
                listener.validationFailed(this);
            } else {
                listener.validationPassed(this);
            }
        }
    }

    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
        if (length > 0) {
            fb.remove(offset, length);
        }
        insertString(fb, offset, string, attr);
    }
}

Example implementation...示例实现...

public class TestPane extends JPanel {

    private Map<DocumentFilter, JTextField> fields;

    public TestPane() {

        fields = new HashMap<>(25);
        ValidationListener listener = new ValidationListener() {

            @Override
            public void validationFailed(DocumentFilter filter) {
                JTextField field = fields.get(filter);
                if (field != null) {
                    field.setBackground(Color.RED);
                }
            }

            @Override
            public void validationPassed(DocumentFilter filter) {
                JTextField field = fields.get(filter);
                if (field != null) {
                    field.setBackground(UIManager.getColor("TextField.background"));
                }
            }
        };

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        for (int index = 0; index < 10; index++) {
            JTextField field = new JTextField(10);
            IntFilter filter = new IntFilter();
            filter.setValidationListener(listener);
            ((AbstractDocument) field.getDocument()).setDocumentFilter(filter);
            fields.put(filter, field);
            add(field, gbc);
        }

    }

}

You have a scoping issue that's why getting this error:您有一个范围问题,这就是为什么会出现此错误:

for(int i = 0; i<nextTextBox;i++) //you are declaring i here

using inside KeyListener , This is prohibited.KeyListener内部使用,这是被禁止的。 Because local non-final variable cant be accessed from inner class to access it must be final.因为不能从内部类访问local non-final变量来访问它必须是最终的。 In your case I don't think it is possible to make i final在你的情况下,我认为不可能让i最终的

So, one quick fix is declare i in the class scope with the JFrame and JPanel因此,一个快速解决方法是在类范围内使用JFrameJPanel声明 i

JFrame myMainWindow = new JFrame("Sorts");

JPanel sortPanel = new JPanel();
int i; 

then use it any where然后在任何地方使用它

 for(i = 0; i<nextTextBox;i++)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM