Получение данных из динамически создаваемых переменных в JFrame - PullRequest
1 голос
/ 15 июня 2019

У меня есть Jframe, который включает Jspinner. Когда JSpinner увеличивается, новый JTextField создается в моей панели headerPanel. Сценарий создает текстовые поля с целым числом, прикрепленным к имени их переменной (tFrame0, tFrame1 и т. Д.).

Исходный код и все старые правки перемещены в Это 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();

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 Listener Document

/**
 * 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);
            }
        }
    }
}

1 Ответ

0 голосов
/ 18 июня 2019

Вы не можете «добавить цикл for i int i к имени переменной», если только вы не хотите использовать отражения (https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html). Отражения позволят вам искать в java- Object его поля и на основе их имя (если оно открыто), доступ к ним.

К счастью, это не то, что вам действительно нужно здесь. Вы на самом деле ищете способ идентифицировать дочерние элементы (Component s) вашей J? Panel как по типу, так и по имени, а затем получить индекс, который вы ранее добавили. Я предлагаю сделать следующее:

// 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, но приведенный выше код проще).

Приведенный выше код «находит» ваши существующие компоненты, и вы можете оттуда работать, например, сортируя их по их именам, а затем печатая.

Проблема, по которой вы получаете только часть ваших текстовых полей, кажется, реагирует на изменения, потому что вы (вероятно) не передаете один и тот же массив inputData различным созданным вами DocumentListener. если вы установите точку останова и проверьте, я уверен, что у 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. Это можно сделать с помощью петли, которую вы получили.

Редактировать

Проблема, как оказалось, возникла из множества полей экземпляров, используемых вместо локальных переменных. Поскольку код был опубликован лишь частично, это было трудно или невозможно определить только из одного вопроса.

...