Как использовать собственный редактор ячеек JTable и средство отображения ячеек

Я создал JTable с настраиваемым представлением таблицы и настраиваемым редактором ячеек, который дает результат в изображении

enter image description here

Я создал панель, показанную в первых ячейках таблицы, используя отдельный класс, который расширил JPanel. и добавьте значения таблиц как,

        tbl.setCellEditor(new customCell());
        tbl.getColumnModel().getColumn(0).setCellRenderer(new customCell());

        DefaultTableModel dtm = (DefaultTableModel) tbl.getModel();

        Vector v = new Vector();
        v.add(new Panel());
        v.add("Test");
        dtm.addRow(v);

        v.clear();
        v.add(new Panel());
        v.add("Test 2");
        dtm.addRow(v);

И это мой собственный пользовательский класс таблицы для создания этой таблицы,

class customCell extends DefaultTableModel implements TableCellRenderer, TableCellEditor {

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Panel p = new Panel();            
            table.setRowHeight(row, p.getHeight());
            return p;
        }

        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {

            return new Panel();
        }

        public Object getCellEditorValue() {
            return "";
        }

        public boolean isCellEditable(EventObject anEvent) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public boolean shouldSelectCell(EventObject anEvent) {
            return true;
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }

        public boolean stopCellEditing() {
            return true;
        }

        public void cancelCellEditing() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void addCellEditorListener(CellEditorListener l) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void removeCellEditorListener(CellEditorListener l) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }

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

Ответ 1

нужно добавить собственные свойства LayoutManager, Editable/non_Editable для уже видимых JPanel

позвольте наслаждаться

import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.table.*;

public class PanelInTable {

    private JFrame frame;
    private JTable compTable = null;
    private PanelTableModel compModel = null;
    private JButton addButton = null;

    public static void main(String args[]) {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception fail) {
        }
        SwingUtilities.invokeLater(() -> {
            new PanelInTable().makeUI();
        });
    }

    public void makeUI() {
        compTable = CreateCompTable();
        JScrollPane CompTableScrollpane = new JScrollPane(compTable, 
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        JPanel bottomPanel = CreateBottomPanel();
        frame = new JFrame("Comp Table Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(CompTableScrollpane, BorderLayout.CENTER);
        frame.add(bottomPanel, BorderLayout.SOUTH);
        frame.setPreferredSize(new Dimension(800, 400));
        frame.setLocation(150, 150);
        frame.pack();
        frame.setVisible(true);
    }

    public JTable CreateCompTable() {
        compModel = new PanelTableModel();
        compModel.addRow();
        JTable table = new JTable(compModel);
        table.setRowHeight(new CompCellPanel().getPreferredSize().height);
        table.setTableHeader(null);
        PanelCellEditorRenderer PanelCellEditorRenderer = new PanelCellEditorRenderer();
        table.setDefaultRenderer(Object.class, PanelCellEditorRenderer);
        table.setDefaultEditor(Object.class, PanelCellEditorRenderer);
        return table;
    }

    public JPanel CreateBottomPanel() {
        addButton = new JButton("Add Comp");
        addButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                Object source = ae.getSource();
                if (source == addButton) {
                    compModel.addRow();
                }
            }
        });
        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(addButton);
        return panel;
    }
}

class PanelCellEditorRenderer extends AbstractCellEditor implements 
        TableCellRenderer, TableCellEditor {

    private static final long serialVersionUID = 1L;
    private CompCellPanel renderer = new CompCellPanel();
    private CompCellPanel editor = new CompCellPanel();

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, 
            boolean isSelected, boolean hasFocus, int row, int column) {
        renderer.setComp((Comp) value);
        return renderer;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, 
            boolean isSelected, int row, int column) {
        editor.setComp((Comp) value);
        return editor;
    }

    @Override
    public Object getCellEditorValue() {
        return editor.getComp();
    }

    @Override
    public boolean isCellEditable(EventObject anEvent) {
        return true;
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        return false;
    }
}

class PanelTableModel extends DefaultTableModel {

    private static final long serialVersionUID = 1L;

    @Override
    public int getColumnCount() {
        return 1;
    }

    public void addRow() {
        super.addRow(new Object[]{new Comp(0, 0, "", "")});
    }
}

class Comp {

    public int type;
    public int relation;
    public String lower;
    public String upper;

    public Comp(int type, int relation, String lower, String upper) {
        this.type = type;
        this.relation = relation;
        this.lower = lower;
        this.upper = upper;
    }
}

class CompCellPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private JLabel labelWith = new JLabel("With ");
    private JComboBox typeCombo = new JComboBox(new Object[]
    {"height", "length", "volume"});
    private JComboBox relationCombo = new JComboBox(new Object[]
    {"above", "below", "between"});
    private JTextField lowerField = new JTextField();
    private JLabel labelAnd = new JLabel(" and ");
    private JTextField upperField = new JTextField();
    private JButton removeButton = new JButton("remove");

   public CompCellPanel() {
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        relationCombo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                enableUpper(relationCombo.getSelectedIndex() == 2);
            }
        });
        enableUpper(false);
        removeButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) SwingUtilities.getAncestorOfClass(
                        JTable.class, (Component) e.getSource());
                int row = table.getEditingRow();
                table.getCellEditor().stopCellEditing();
                ((DefaultTableModel) table.getModel()).removeRow(row);
            }
        });
        add(labelWith);
        add(typeCombo);
        add(relationCombo);
        add(lowerField);
        add(labelAnd);
        add(upperField);
        add(Box.createHorizontalStrut(100));
        add(removeButton);
    }

    private void enableUpper(boolean enable) {
        labelAnd.setEnabled(enable);
        upperField.setEnabled(enable);
    }

    public void setComp(Comp Comp) {
        typeCombo.setSelectedIndex(Comp.type);
        relationCombo.setSelectedIndex(Comp.relation);
        lowerField.setText(Comp.lower);
        upperField.setText(Comp.upper);
        enableUpper(Comp.relation == 2);
    }

    public Comp getComp() {
        return new Comp(typeCombo.getSelectedIndex(), 
                relationCombo.getSelectedIndex(), 
                lowerField.getText(), upperField.getText());
    }
}

Ответ 2

Я бы настоятельно рекомендовал повторно использовать функциональность, доступную в рендерерах и редакторах таблиц по умолчанию, так как в вашем коде есть много ошибок.

  • Разделите редактор, модель рендеринга и таблицу. Наличие их всех в одном классе просто странно.
  • Для вашего средства визуализации не создавайте новые экземпляры Component каждый раз. Вместо этого повторно используйте один и тот же компонент и просто измените это значение Component в методе getTableCellRendererComponent
  • То же самое касается редактора Component
  • Расширьте редактор по умолчанию вместо реализации методов с помощью UnsupportedOperationException или просто вернув пустой String s

Чтобы выполнить резервное копирование моего четвертого пункта, небольшая цитата из часть редакторов в учебнике JTable:

Что делать, если вы хотите указать редактор, отличный от текстового поля, флажок или поле со списком? Поскольку DefaultCellEditor не поддерживает другие типы компонентов, вы должны сделать немного больше работы. Вам необходимо создать класс, который реализует интерфейс TableCellEditor. Класс AbstractCellEditor - хороший суперкласс для использования. Он реализует суперинтерфейс TableCellEditor, CellEditor, избавляя вас от необходимости реализовать код запуска события, необходимый для редакторов ячеек.

Класс вашего класса редакторов должен определять как минимум два метода - getCellEditorValue и getTableCellEditorComponent. Метод getCellEditorValue, требуемый CellEditor, возвращает текущее значение ячейки. Метод getTableCellEditorComponent, требуемый TableCellEditor, должен настроить и вернуть компонент, который вы хотите использовать в качестве редактора.

Как ясно объяснено там, вы должны реализовать код активации события:

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

который вы явно пренебрегли. Поэтому советую начать с AbstractCellEditor вместо реализации интерфейса с нуля