从 JFrame 中动态创建的变量获取数据

Getting data from dynamically created variables in JFrame

我有一个包含 Jspinner 的 Jframe。当 JSpinner 增加时,会在我的面板 headerPanel 中创建一个新的 JTextField。该脚本创建文本框,并在其变量名称(tFrame0、tFrame1 等)上附加一个整数。

原始代码和所有旧编辑已移至 This pastebin。

链接 pastebin 以防它在将来对任何人有帮助,并且不要弄乱当前相关的代码。

TreffnonX 的帮助下解决了这个问题!感谢您在评论和聊天中对我非常耐心。

这是工作代码,以防以后有人遇到此类问题。

全局变量

private JPanel headerPanel;
private JSpinner spinner;

public List<JTextField> findTextFields() {
    List<JTextField> fields = new LinkedList<>();

    Component[] children = headerPanel.getComponents();
    for (Component child : children) {
        if (child instanceof JTextField) {
            JTextField childField = (JTextField) child;

            // check, if the name is prefixed correctly.
            String name = childField.getName();
            if (name.startsWith(nameTField)) {
                fields.add(childField);
            }
        }
    }

    return fields;
}

JSpinner

spinner = new JSpinner();
spinner.setModel(new SpinnerNumberModel(1, 1, 100, 1));
    spinner.addContainerListener(new ContainerAdapter() {
    @Override
    public void componentAdded(ContainerEvent arg0) {
        adaptBoxes();
    }
});
spinner.addChangeListener(new ChangeListener() {
    public void stateChanged(ChangeEvent arg0) {
        int spinnerValue = (Integer) spinner.getValue();
        if (spinnerValue == headerPanel.getComponentCount()) {
            System.out.println("Error, spinner shouldn't change to same alue");
        }
        adaptBoxes();
        frame.revalidate();
        frame.repaint();
    }
});
adaptBoxes();

自适应框();方法

public void adaptBoxes() {
    // Find value of spinner.
    int spinnerValue = (Integer) spinner.getValue();

    List<JTextField> textFields = findTextFields();
    int numTextFields = textFields.size();

    if (numTextFields > spinnerValue) {
        // if we have too many fields.
        for (JTextField textField : textFields) {
            String name = textField.getName();
            Matcher matcher = POSTFIX_PATTERN.matcher(name);
            if (matcher.matches()) {
                String strPostfix = matcher.group(1);
                int postFixNumeric = Integer.parseInt(strPostfix);

                System.out.println("for postFix = " + postFixNumeric + ": " + textField.getText());
                if (postFixNumeric >= spinnerValue) {
                    System.out.println("PFN: " + postFixNumeric);
                    System.out.println("FTF: " + numTextFields);
                    headerPanel.remove(textField);
                }
            }
        }
    } else {
        while (numTextFields < spinnerValue) {
            // if we have too few fields.
            int hp = headerPanel.getComponentCount();

            JTextField tField = new JTextField();
            tField.setName(nameTField + hp);

            tField.getDocument().addDocumentListener(new TextFieldDocumentListener());

            headerPanel.add(tField);

            textFields = findTextFields();
            numTextFields = textFields.size();
        }
    }
}

JTextField 文档监听器

/**
 * Inner class
 */
private final class TextFieldDocumentListener implements DocumentListener {
    @Override
    public void changedUpdate(DocumentEvent e) {
        warn();
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
        warn();
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        warn();
    }

    /**
     * Actual sysout to inform the user...
     */
    public void warn() {
        List<JTextField> textFields = findTextFields();
        for (JTextField textField : textFields) {
            String name = textField.getName();

            Matcher matcher = POSTFIX_PATTERN.matcher(name);
            System.out.println(name);

            if (matcher.matches()) {
                String strPostfix = matcher.group(1);
                int postfixNumeric = Integer.parseInt(strPostfix);

                System.out.println("for postfix = " + postfixNumeric + ": " + textField.getText());
            } else {
                System.out.println("matcher error: " + matcher);
            }
        }
    }
}

你不能 'append my for loop int i to a variable name',除非你想使用反射 (https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html)。反射将允许您搜索 java-Object 的字段,并根据它们的名称(如果公开)访问它们。

幸运的是,这不是您真正需要的。您实际上正在寻找一种方法来按类型和名称识别 J?Panel 的子项 (Components),然后推断出您以前附加的索引。我的建议是执行以下操作:

// This pattern can be anywhere in the Class-file:
public static final Pattern POSTFIX_PATTERN = Pattern.compile("tFrame(\d+)");

// This should be in your exposed GUI class (supposedly the Panel), but can be anywhere it can access headerPanel.
public List<JTextField> findTextFields() {
    List<JTextField> fields = new LinkedList<>();

    Component[] children = headerPanel.getComponents();
    // this is your 'search-loop':
    for (Component child : children) {
        if (child instanceof JTextField) {
            JTextField childField = (JTextField) child;
            String name = childField.getName();
            if (name.startsWith("tFrame")) {
                fields.add(childField);
            }
        }
    }

    return fields;
}

(这也可以像Stream一样完成,但上面的代码更简单)。

上面的代码 'finds' 您现有的组件,您可以从那里开始工作,例如根据它们的名称对它们进行排序,然后进行打印。

您只收到部分文本字段似乎对修改有反应的问题是因为您(可能)没有将相同的 inputData-array 传递给不同的 DocumentListeners你创造。如果您设置断点并检查,我敢打赌 inputData-Arrays 具有不同的哈希值。也就是说,我不能 100% 推断出这个,​​因为周围的代码不完整。

我建议更改:

if (tField.getText() != null) {
    Object[] currentData = new Object[getFieldNum + 1];
    currentData[getFieldNum] = tField.getText();

    inputData[getFieldNum] = tField.getText();

    for (int i = 0; i < inputData.length; i++) {
        if (inputData[i] != null) {
            System.out.println("for i = " + i + ": " + inputData[i]);
        }

    }
}

for (JTextField textField : findTextFields()) {
    String name = textField.getName();
    Matcher matcher = POSTFIX_PATTERN.matcher(name);
    if (matcher.matches()) {
        String strPostfix = matcher.group(1);
        int postfixNumeric = Integer.parseInt(strPostfix);

        System.out.println("for postfix = " + postfixNumeric + ": " + textField.getText());
    }
}

这样,您就可以在用户实际做出您想要响应的更改的时间点获取组件。

另外附注: 一旦您减少或增加 JSpinner 上的数字,您真的想要替换所有现有的文本字段及其当前状态吗?

可以考虑去掉postfixNumeric >= getTextFields().size()的元素,或者增加元素的个数而不去掉JSpinner上小于前一个个数的元素。这可以用你得到的循环来完成。

编辑

问题原来是由于使用了大量 instance-fields 而不是局部变量。由于只发布了部分代码,因此很难甚至不可能仅从问题中确定。