Вопрос по jtable клеточным редакторам в разгаре - PullRequest
2 голосов
/ 09 июля 2011

Я хочу реализовать компонент, который служит списком опций, которые пользователь может выбирать, выбирать или нет.
Визуально я подумал, что он будет лучше всего представлен в пользовательском интерфейсе (если есть лучший подход, пожалуйста,скажите мне) следующим образом:
enter image description here

В любом случае, я думал, что это можно реализовать через JTable (один столбец) и с использованием JCheckBox в качестве редактора ячеек.
Я попробовал это, но не сработало.
Пример кода:

public class ListRenderer extends JFrame {

    JCheckBox checkbox = new JCheckBox("Test");
    DefaultCellEditor dce1 = new DefaultCellEditor(checkbox);

    public ListRenderer(){          

        Object[][] data =  {   {"Test"} };
        String[] columnNames = {"Options"};

        DefaultTableModel model = new DefaultTableModel(data,columnNames);

        JTable table = new JTable(model){

            public TableCellEditor getCellEditor(int row, int column)            
            {               
                return dce1;                
            }

        };
        JScrollPane scrollPane = new JScrollPane( table );        
        getContentPane().add( scrollPane );
    }

Что происходит, когда появляется рамка, я вижу "Тест" в таблице, но он не выглядит как флажок (как в примере с изображением).
Если я щелкну по ячейке, она превратится в флажок (нажмите кнопку слева и не справа), но текст изменится и отобразит либо true , либо ложь !Не показывается «Test»
Более того, текст зависит от того, продолжаю ли я нажимать на ячейку или нет.
Если я изменю JCheckBox на JComboBox, поведение будет правильным, насколько ямогу сказать.
Может кто-нибудь сказать мне, что я здесь не так делаю?
Спасибо!

Ответы [ 2 ]

2 голосов
/ 09 июля 2011

здесь вы можете найти ответ, почему (JButtons JComponents) JCheckBox и JRadioButton ... немного отличаются для рендеринга в TableCell как другие JComponents (и вам придется играть с выбором строки JTable, потому что я изменил непрозрачность)

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

public class CheckboxInCellTest {

    private String[] columnNames = {"Boolean(Default)", "Boolean"};
    private Object[][] data = {{false, true}, {true, false}, {false, true}};
    private DefaultTableModel model = new DefaultTableModel(data, columnNames) {

        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };

    public JComponent makeUI() {
        JTable table = new JTable(model);
        table.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                JTable t = (JTable) e.getComponent();
                Point pt = e.getPoint();
                int row = t.rowAtPoint(pt), col = t.columnAtPoint(pt);
                if (t.convertColumnIndexToModel(col) == 1) {
                    t.getCellEditor(row, col).stopCellEditing();
                }
            }
        });
        table.setRowHeight(20);
        CheckBoxEditorRenderer1 cer = new CheckBoxEditorRenderer1();
        table.getColumnModel().getColumn(1).setCellRenderer(cer);
        table.getColumnModel().getColumn(1).setCellEditor(cer);
        JPanel p = new JPanel(new BorderLayout());
        p.add(new JScrollPane(table));
        return p;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new CheckboxInCellTest().makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class CheckBoxPanel1 extends JPanel {

    private static final long serialVersionUID = 1L;
    public final JCheckBox button = new JCheckBox();

    CheckBoxPanel1() {
        super(new GridBagLayout());
        add(button);
        button.setOpaque(false);
        setOpaque(false);
    }
}

class CheckBoxEditorRenderer1 extends AbstractCellEditor implements TableCellRenderer, TableCellEditor {

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

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean is, boolean hf, int row, int column) {
        renderer.button.setSelected(Boolean.TRUE.equals(value));
        renderer.button.setOpaque(is);
        return renderer;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        editor.button.setSelected(Boolean.TRUE.equals(value));
        renderer.button.setOpaque(isSelected);
        return editor;
    }

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

и с JButton в TableCell ... с Nimbus L & F (требуется Java> 1.6.17 ??? теперь у меня есть xxx.25)

import com.sun.java.swing.Painter;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.util.LinkedList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import sun.swing.table.DefaultTableCellHeaderRenderer;

public class TableButtonTest extends JFrame {

    private static final long serialVersionUID = 1L;

    public TableButtonTest() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JTable table = new JTable(new TestModel());
        table.getTableHeader().setReorderingAllowed(false);
        table.setRowHeight(20);
        table.getColumnModel().getColumn(1).setPreferredWidth(3);
        table.getColumnModel().getColumn(2).setPreferredWidth(3);
        table.getTableHeader().setDefaultRenderer(new WrappingRenderer(table.getTableHeader()));
        this.add(new JScrollPane(table));
        Action increase = new AbstractAction("+") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) e.getSource();
                int row = Integer.valueOf(e.getActionCommand());
                TestModel model = (TestModel) table.getModel();
                model.increment(row, 0);
                //model.fireTableCellUpdated(row, 0);
            }
        };
        ButtonColumn inc = new ButtonColumn(table, increase, 1);
        Action decrease = new AbstractAction("-") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                JTable table = (JTable) e.getSource();
                int row = Integer.valueOf(e.getActionCommand());
                TestModel model = (TestModel) table.getModel();
                model.decrement(row, 0);
            }
        };
        ButtonColumn dec = new ButtonColumn(table, decrease, 2);
        JTableHeader tbh = table.getTableHeader();
        tbh.setOpaque(false);
        Painter painter = new com.sun.java.swing.Painter() {

            public void paint(Graphics2D g, Object o, int w, int h) {
            }
        };
        javax.swing.UIDefaults defaults = new javax.swing.UIDefaults();
        defaults.put("TableHeader:\"TableHeader.renderer\"[Pressed].backgroundPainter", painter);
        defaults.put("TableHeader:\"TableHeader.renderer\"[Pressed].backgroundPainter",
                defaults.get(("TableHeader:\"TableHeader.renderer\"[Pressed].backgroundPainter")));
        tbh.putClientProperty("Nimbus.Overrides", defaults);
        tbh.putClientProperty("Nimbus.State", "Pressed");
        tbh.putClientProperty("JTree.lineStyle", "Angled");
        setLocation(200, 200);
        pack();
    }

    private static class WrappingRenderer implements TableCellRenderer {

        private DefaultTableCellHeaderRenderer delegate;
        private JTableHeader header;

        public WrappingRenderer(JTableHeader header) {
            this.header = header;
            this.delegate = (DefaultTableCellHeaderRenderer) header.getDefaultRenderer();
            header.setDefaultRenderer(this);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Component comp = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            TableColumn draggedColumn = table.getTableHeader().getDraggedColumn();
            if (isSelected) {
                comp.setBackground(table.getSelectionBackground());
            } else {
                comp.setBackground(table.getBackground());
            }

            if (draggedColumn != null) {
                if (table.convertColumnIndexToModel(column) == draggedColumn.getModelIndex()) {
                    setNimbusState("Pressed");
                } else {
                    setNimbusState(null);
                }
            } else {
                setNimbusState(null);
            }
            // do similar for resizing column
            return comp;
        }

        public void setNimbusState(String state) {
            delegate.putClientProperty("Nimbus.State", state);
        }
    }

    public static void main(String[] args) {
        try {
            // UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if (info.getName().equals("Nimbus")) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        new TableButtonTest().setVisible(true);
    }
}

class TestModel extends AbstractTableModel {

    private static final long serialVersionUID = 1L;
    private List<TestRecord> records = new LinkedList<TestRecord>();

    private static class TestRecord {

        private int val = 0;
    }

    public void increment(int row, int col) {
        records.get(row).val++;
        fireTableCellUpdated(row, col);
    }

    public void decrement(int row, int col) {
        records.get(row).val--;
        fireTableCellUpdated(row, col);
    }

    public TestModel() {
        records.add(new TestRecord());
        records.add(new TestRecord());
    }

    @Override
    public Class<?> getColumnClass(int col) {
        switch (col) {
            case 0:
                return Integer.class;
            case 1:
                return ButtonColumn.class;
            case 2:
                return Boolean.class;
            default:
                return String.class;
        }
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return true;
    }

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

    @Override
    public int getRowCount() {
        return records.size();
    }

    @Override
    public Object getValueAt(int row, int col) {
        if (col == 0) {
            return records.get(row).val;
        } else if (col == 1) {
            return "+";
        } else {
            return "-";
        }
    }
}
2 голосов
/ 09 июля 2011

Чтобы отобразить как JCheckBox по по умолчанию , модель таблицы должна вернуть Boolean.class в качестве типа для этого столбца. Если вы используете DefaultTableModel, вам придется соответственно переопределить getColumnClass(). Вот связанный пример .

Добавление: обратите внимание, в примере , что частный экземпляр редактора ValueRenderer может применять ItemEvent напрямую, вместо использования setValueAt().

Добавление: пример был обновлен, чтобы отразить правильный рабочий процесс просмотра модели.

setValueAt() вызывается в любом случае. Проверено с помощью отладки

Если вы войдете в setValueAt(), вы увидите, что «Эта пустая реализация предоставляется, поэтому пользователям не нужно реализовывать этот метод, если их модель данных не редактируемые ".

...