Редактировать выбранный элемент в JComboBox

Моя цель - создать список с длиной, контролируемой другим компонентом, где можно редактировать значение каждого элемента.

В моей попытке используется редактируемый JComboBox с определенным количеством элементов. Однако в приведенном ниже коде выбранный индекс продолжает меняться на -1, что не позволяет мне изменять элемент. Есть ли способ выбрать и отредактировать элемент с помощью JComboBox?

//cb is a JComboBox with elements of type ComboItem. idx is defined elsewhere.
cb.addItemListener(new ItemListener() {
    @SuppressWarnings("unchecked")
    @Override
    public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED)
            idx = ((JComboBox<ComboItem>) e.getSource()).getSelectedIndex();
        System.out.println("idx:"+idx);
    }
});
//Pressing enter should commit changes.
cb.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
    @Override
    public void keyReleased(KeyEvent e) {
        if (e.getKeyChar() == KeyEvent.VK_ENTER) {
            String parse = ((JTextComponent) cb.getEditor().getEditorComponent()).getText();
            parse = parse.substring(parse.lastIndexOf(":")+1).replaceAll("[^0-9]+", ""); //Processes edits.
            cb.getItemAt(idx).change("Layer "+idx, Integer.parseInt(parse)); //This method should change the
            System.out.println("selected item:"+cb.getSelectedItem());      // data for each item.
        }
    }
});
//Editing the text in the JComboBox and pressing the enter key should update the selected item.

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
170
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После целого дня проб и ошибок я наконец нашел работающее решение. Вместо использования JComboBox, который, вероятно, не предназначен для выполнения желаемой задачи, я сделал JScrollPane, который добавляет дочерний JPanel каждый раз, когда нажимается кнопка. Каждая панель имеет объект текстового поля, который можно настроить, и кнопку для его удаления. В моем случае я добавил DocumentFilter, который позволяет использовать положительные <5-значные целые числа.

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

Панель прокрутки

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.JLabel;

@SuppressWarnings("serial")
public class TestScrollPane extends JPanel {

    private int w,h;
    private JPanel content;
    private JScrollPane scroll;
    private JButton add;
    private JLabel getTextLabel;
    private JButton getTextBtn;

    /**
     * Create the panel.
     */
    public TestScrollPane(int width, int height) {
        setLayout(null);

        w = width; h = height;

        scroll = new JScrollPane();
        scroll.setBounds(0, 0, w, h);
        scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        add(scroll);

        content = new JPanel();
        scroll.setViewportView(content);
        content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));

        add = new JButton("+");
        add.setBounds(0, h, 89, 23);
        add(add);

        getTextLabel = new JLabel("");
        getTextLabel.setBounds(10, 425, 215, 14);
        add(getTextLabel);

        getTextBtn = new JButton("Get Text");
        getTextBtn.setBounds(225, 425, 215, 14);
        getTextBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String a[] = getText(),
                       b = "";
                b += "[";
                for(int i = 0; i < a.length - 1; i++)
                    b += a[i]+", ";
                b += a[a.length-1]+"]";
                System.out.println(b);
                getTextLabel.setText(b);
            }
        });
        add(getTextBtn);

        add.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("adding "+content.getComponentCount());
                content.add(new ScrollItem(content.getComponentCount()));
                validate();
                repaint();
            }
        });
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(w, h);
    }

    public String[] getText() {
        String out[] = new String[content.getComponentCount()],s;
        for(int i = 0; i < out.length; i++)
            out[i] = (s = ((ScrollItem) content.getComponent(i)).out) == null ? "0" : s;
        return out;
    }

    private class ScrollItem extends JPanel {

        private JTextField text;
        private JButton del;
        private int idx;
        private String out;

        public ScrollItem(int id) {
            idx = id;
            setBounds(0, idx*20, w-5, 20);
            setLayout(null);
            text = new JTextField();
            text.setBounds(0, 0, (w-5)*3/4, 20);
            text.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    out = text.getText();
                }
            });

            AbstractDocument d = (AbstractDocument) text.getDocument();
            d.setDocumentFilter(new TextFilter(4));

            del = new JButton("X");
            del.setBounds((w-5)*3/4, 0, (w-5)/4, 20);
            del.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    content.remove(idx);
                    for(int i = idx; i < content.getComponentCount(); i++)
                        ((ScrollItem) content.getComponent(i)).moveUp();
                    content.validate();
                    content.repaint();
                    System.out.println("Removed "+idx);
                }
            });
            add(text);
            add(del);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(w-5, 20);
        }

        public void moveUp() {
            idx--;
            content.validate();
            content.repaint();
        }
    }

    private class TextFilter extends DocumentFilter {
        private int max;

        public TextFilter(int maxChars) {
            max = maxChars;
        }

        @Override
        public void insertString(FilterBypass fb, int offs, String str, AttributeSet a) throws BadLocationException {
            System.out.println("insert");
            if ((fb.getDocument().getLength() + str.length()) <= max && str.matches("\\d+"))
                super.insertString(fb, offs, str, a);
            else
                showError("Length: "+((fb.getDocument().getLength() + str.length()) <= max)+" | Text: "+str.matches("\\d+")+" | Str: "+str);
        }

        @Override
        public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a) throws BadLocationException {
            System.out.println("replace");
            if ((fb.getDocument().getLength() + str.length() - length) <= max && str.matches("\\d+"))
                super.replace(fb, offs, length, str, a);
            else
                showError("Length: "+((fb.getDocument().getLength() + str.length() - length) <= max)+" | Text: "+str.matches("\\d+")+" | Str: "+str);
        }

        private void showError(String cause) {
            JOptionPane.showMessageDialog(null, cause);
        }
    }
}

Тестовое окно

import java.awt.EventQueue;
import javax.swing.JFrame;

public class TestWindow {
    private JFrame frame;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TestWindow window = new TestWindow();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public TestWindow() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 435, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new TestScrollPane(430, 247));
    }
}

Другие вопросы по теме