自定义JTable,意外行为

时间:2013-12-19 17:41:05

标签: java swing jtable

尝试创建自定义JTable结构时,我从一个非常简单的项目开始,以便更好地理解。不幸的是,一旦我开始定制东西,我会得到奇怪的行为,我希望你帮助我理解它们。非常感谢你。

这是我的小项目:

public class Tableau extends JFrame {

    public Tableau() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800,600);
        setContentPane(new Panel());
        setVisible(true);
    }

    public static void main(String[] args) {
        new Tableau();
    }
    private static class Panel extends JPanel {
        private JTable table = new Table(4, 4);
        public Panel() {
            add(table);
        }
    }

    private static class Table extends JTable {
        private Renderer randerer = new Renderer();
        public Table(int row, int col) {
            super(new Model(row, col));
            setAutoResizeMode(AUTO_RESIZE_OFF);
            setDefaultRenderer(String.class, randerer);
            setDefaultEditor(String.class, randerer);
        }

        private class Renderer implements TableCellRenderer, TableCellEditor {
            String previousContent = "";
            JTextPane rendererComponent = new JTextPane();
            public Renderer() {
                super();setOpaque(true);
            }
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                rendererComponent.setText((String)value);
                rendererComponent.setBorder(hasFocus ? BorderFactory.createLineBorder(Color.RED) : null);
                rendererComponent.setBackground(isSelected ? Color.PINK : Color.GREEN);
                FontMetrics fm = rendererComponent.getFontMetrics(rendererComponent.getFont());
                if(((String)value).length()!=0) {rendererComponent.setPreferredSize(new Dimension(fm.stringWidth((String)value),fm.getHeight()));}
                else {rendererComponent.setPreferredSize(new Dimension(20, fm.getHeight()));}
                return rendererComponent;
            }

            @Override
            public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
                rendererComponent.setText((String)value);
                rendererComponent.setBackground(isSelected ? table.getSelectionBackground() : Color.MAGENTA);
                if(isSelected) {rendererComponent.selectAll();}
                previousContent = (String)value;
                return rendererComponent;
            }

            @Override
            public Object getCellEditorValue() {
                return rendererComponent.getText();
            }

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

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

            @Override
            public boolean stopCellEditing() {
                fireEditingStoppedEvent();
                return true;
            }

            @Override
            public void cancelCellEditing() {
                rendererComponent.setText(previousContent);
                fireEditingCanceledEvent();
            }

            protected void fireEditingStoppedEvent() {
                for(CellEditorListener l : listeners) {l.editingStopped(new ChangeEvent(this));}
            }

            protected void fireEditingCanceledEvent() {
                for(CellEditorListener l : listeners) {l.editingCanceled(new ChangeEvent(this));}
            }

            private List<CellEditorListener> listeners = new LinkedList<CellEditorListener>();
            @Override
            public void addCellEditorListener(CellEditorListener l) {
                listeners.add(l);
            }

            @Override
            public void removeCellEditorListener(CellEditorListener l) {
                listeners.remove(l);
            }

        }
    }

    private static class Model implements TableModel {
//        private ColumnModel colonnes = new ColumnModel();
        private List<List<Cellule>> colonnes = new LinkedList<List<Cellule>>();
        private int rowCount = 0;
//        private List<Cellule> cellules = new LinkedList<Cellule>();

        private static class Cellule {
            public Cellule() {}
            public Cellule(Object content) {this.content = content;}
            private Object content;
            private Object getContent() {return content;}
            private void setContent(Object newContent) {content = newContent;}
        }

        public Model(int row, int col) {
            for(int j=0; j<col; j++) {
                insertColumn(j);
            }
            for(int i=0; i<row; i++) {
                insertRow(i);
            }
        }

        @Override
        public int getRowCount() {
            return rowCount;
        }

        @Override
        public int getColumnCount() {
            return colonnes.size();
        }

        @Override
        public String getColumnName(int columnIndex) {
            String result = "";
            for (; columnIndex >= 0; columnIndex = columnIndex / 26 - 1) {
                result = (char)((char)(columnIndex%26)+'A') + result;
            }
            return result;
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return colonnes.isEmpty() ? Object.class : getValueAt(columnIndex, 0).getClass();
        }

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

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return colonnes.get(columnIndex).get(rowIndex).getContent();
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            colonnes.get(columnIndex).get(rowIndex).setContent(aValue);
            fireTableChanged(new TableModelEvent(this, rowIndex, rowIndex, columnIndex, TableModelEvent.UPDATE));
        }

        protected void fireTableChanged(TableModelEvent e) {
            for(TableModelListener l : listeners) {
                l.tableChanged(null);
            }
        }

        public void insertColumn(int index) {
            List<Cellule> newColumn = new LinkedList<Cellule>();
            for(int i = 0; i<getRowCount(); i++) {
                Cellule newCell = new Cellule("");
                newColumn.add(newCell);
            }
            colonnes.add(index, newColumn);
            fireTableChanged(new TableModelEvent(this, 0, getRowCount(), index, TableModelEvent.INSERT));
        }

        public void insertRow(int index) {
            for(List<Cellule> colonne : colonnes) {
                Cellule newCell = new Cellule("");
                colonne.add(index, newCell);
            }
            rowCount++;
            fireTableChanged(new TableModelEvent(this, index, index, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));
        }

        public void removeColumn(int index) {
            colonnes.remove(index);
            fireTableChanged(new TableModelEvent(this, 0, getRowCount(), index, TableModelEvent.DELETE));
        }

        public void removeRow(int index) {
            for(List<Cellule> row : colonnes) {
                row.remove(index);
            }
            rowCount--;
            fireTableChanged(new TableModelEvent(this, index, index, TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE));
        }

        private List<TableModelListener> listeners = new LinkedList<TableModelListener>();
        @Override
        public void addTableModelListener(TableModelListener l) {
            listeners.add(l);
        }

        @Override
        public void removeTableModelListener(TableModelListener l) {
            listeners.remove(l);
        }

    }

}

基本上,我们有一个JFrame(类Tableau),包含一个包含JTable(类Table)的JPanel(类Panel)。此表使用TableModel(类Model)和JTextPane(类Renderer),它们将用于呈现和编辑表内容。

以下是我的问题:

1)如果我单击一个单元格,它将变为白色(我不明白给定渲染器的代码可能如何...)。如果我写了一些内容,首先,单元格中没有任何内容,但是当我移动焦点时,文本会出现......

2)如果我单击一个单元格然后使用箭头键移动焦点,则只有这些选择似乎正确完成。正确显示红色边框等。当我单击时,为什么选择不正确而不使用箭头?

谢谢!

0 个答案:

没有答案