/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.montsuqi.widgets; /** * * @author mihara */ import java.awt.*; import java.awt.event.*; import java.awt.im.InputContext; import java.awt.im.InputSubset; import java.util.Locale; import javax.swing.*; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import org.montsuqi.util.SafeColorDecoder; import org.montsuqi.util.SystemEnvironment; public class PandaTable extends JTable { private class PandaTableModel extends DefaultTableModel { private final String[] types; private final String[] titles; public PandaTableModel() { super(); this.setColumnCount(1); this.setRowCount(1); types = new String[MAX_COLS]; titles = new String[MAX_COLS]; for (int i = 0; i < MAX_COLS; i++) { types[i] = "text"; titles[i] = "title" + i; } } public void setColumns(int cols) { if (cols < MAX_COLS) { this.setColumnCount(cols); } else { this.setColumnCount(MAX_COLS); } setRows(this.getRowCount()); } public void setRows(int rows) { this.setRowCount(rows); for (int i = 0; i < rows; i++) { int cols = this.getColumnCount(); for (int j = 0; j < cols; j++) { this.setValueAt("", i, j); } } } public void setTypes(String[] types) { for (int i = 0; i < this.types.length && i < types.length; i++) { this.types[i] = types[i]; } setColumns(this.getColumnCount()); } public String[] getTypes() { int cols = this.getColumnCount(); String[] ret = new String[cols]; System.arraycopy(this.types, 0, ret, 0, cols); return ret; } public void setTitles(String[] titles) { for (int i = 0; i < this.titles.length && i < titles.length; i++) { this.titles[i] = titles[i]; } setColumns(this.getColumnCount()); } public void setRow(int row, String[] rowdata) { if (0 <= row && row < this.getRowCount()) { for (int i = 0; i < this.getColumnCount(); i++) { setValueAt(rowdata[i], row, i); } } } @Override public boolean isCellEditable(int row, int col) { return !this.types[col].equals("label"); } @Override public String getColumnName(int column) { if (column < this.titles.length) { return this.titles[column]; } else { return ""; } } } private final int MAX_COLS = 100; private Color[][] fgColors; private Color[][] bgColors; private final PandaTableModel model; private boolean enterPressed; private int changedRow; private int changedColumn; private String changedValue; private boolean[] imControls; public int getChangedColumn() { return changedColumn; } public int getChangedRow() { return changedRow; } public String getChangedValue() { return changedValue; } public void setChangedColumn(int changedColumn) { this.changedColumn = changedColumn; } public void setChangedRow(int changedRow) { this.changedRow = changedRow; } public void setChangedValue(String changedValue) { this.changedValue = changedValue; } public boolean isEnterPressed() { return enterPressed; } public void setEnterPressed(boolean enterPressed) { this.enterPressed = enterPressed; } public void setImControls(String[] cs) { for (int i = 0; i < cs.length && i < imControls.length; i++) { imControls[i] = cs[i].startsWith("t") || cs[i].startsWith("T"); } } public PandaTable() { this.setRowSelectionAllowed(false); JTableHeader header = this.getTableHeader(); header.setVisible(true); this.setShowGrid(true); model = new PandaTableModel(); this.setModel(model); /* * magic number */ int rowheight = 25; if (System.getProperty("monsia.pandatable.rowheight") != null) { rowheight = Integer.parseInt(System.getProperty("monsia.pandatable.rowheight")); } this.setRowHeight(rowheight); enterPressed = false; imControls = new boolean[MAX_COLS]; for (int i = 0; i < MAX_COLS; i++) { imControls[i] = false; } final DefaultCellEditor ce = (DefaultCellEditor) this.getDefaultEditor(Object.class); /* * Enterでの更新はSendEventするため */ ce.getComponent().addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { PandaTable.this.setEnterPressed(true); } else if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_TAB) { Component parent = ((Component) e.getSource()).getParent(); KeyEvent pass = new KeyEvent(parent, e.getID(), e.getWhen(), e.getModifiers(), e.getKeyCode(), e.getKeyChar()); parent.dispatchEvent(pass); e.consume(); } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } }); /* * エディタをフォーカスアウトしたらセル編集キャンセルするため */ ce.getComponent().addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { // do nothing if (SystemEnvironment.isWindows()) { if (imControls[getSelectedColumn()]) { InputContext ic = getInputContext(); if (ic != null) { ic.setCharacterSubsets(new Character.Subset[]{InputSubset.KANJI}); ic.endComposition(); ic.selectInputMethod(Locale.JAPANESE); } } } } @Override public void focusLost(FocusEvent e) { if (SystemEnvironment.isWindows()) { InputContext ic = getInputContext(); if (ic != null) { ic.setCharacterSubsets(null); ic.endComposition(); ic.selectInputMethod(Locale.ENGLISH); } } ce.stopCellEditing(); } }); addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { //pns フォーカスを取ったら必ず編集する editCell(); } @Override public void focusLost(FocusEvent e) { // do nothing } }); changedRow = 0; changedColumn = 0; changedValue = ""; } //pns 選択が起きたら必ず編集する @Override public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { super.changeSelection(rowIndex, columnIndex, toggle, extend); if (isEditing()) { // selection が変わったので前の editor は消す getCellEditor().cancelCellEditing(); } else { // 非編集状態なら editor を立ち上げる editCell(); } } //pns セル編集時に CellEditor にフォーカスさせる editCell private void editCell() { editCellAt(getSelectedRow(), getSelectedColumn()); this.setChangedRow(this.getSelectedRow()); this.setChangedColumn(this.getSelectedColumn()); final DefaultCellEditor ce = (DefaultCellEditor) getDefaultEditor(Object.class); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { ce.getComponent().requestFocusInWindow(); } }); } public String getStringValueAt(int row, int col) { Object obj = getModel().getValueAt(row, col); if (obj == null) { return ""; } else { return obj.toString(); } } public int getRows() { return this.getModel().getRowCount(); } public void setRows(int rows) { model.setRows(rows); int columns = model.getColumnCount(); fgColors = new Color[rows][columns]; bgColors = new Color[rows][columns]; for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { fgColors[i][j] = Color.BLACK; bgColors[i][j] = Color.WHITE; } } } public int getColumns() { return model.getColumnCount(); } public void setColumns(int cols) { model.setColumns(cols); int rows = model.getRowCount(); fgColors = new Color[rows][cols]; bgColors = new Color[rows][cols]; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { fgColors[i][j] = Color.BLACK; bgColors[i][j] = Color.WHITE; } } } public void setTitles(String[] titles) { model.setTitles(titles); } public String[] getTypes() { return model.getTypes(); } public void setTypes(String[] types) { model.setTypes(types); } public void setFGColor(int row, int column, String _color) { if (0 <= row && row < model.getRowCount() && 0 <= column && column < model.getColumnCount()) { Color color = SafeColorDecoder.decode(_color); fgColors[row][column] = color != null ? color : Color.BLACK; } } public void setBGColor(int row, int column, String _color) { if (0 <= row && row < model.getRowCount() && 0 <= column && column < model.getColumnCount()) { Color color = SafeColorDecoder.decode(_color); bgColors[row][column] = color != null ? color : Color.WHITE; } } public void setCell(int row, int col, String data) { model.setValueAt(data, row, col); } @Override public Component prepareEditor(TableCellEditor editor, int row, int column) { Component c = super.prepareEditor(editor,row,column); if (fgColors != null) { c.setForeground(fgColors[row][column]); } if (bgColors != null) { c.setBackground(bgColors[row][column]); } return c; } @Override public Component prepareRenderer( TableCellRenderer renderer, int row, int column) { Component c = super.prepareRenderer(renderer, row, column); if (fgColors != null) { c.setForeground(fgColors[row][column]); } if (bgColors != null) { c.setBackground(bgColors[row][column]); } return c; } public static void main(String[] args) { JFrame frame = new JFrame("ProtoPandaTable"); Container container = frame.getContentPane(); container.setLayout(new BorderLayout(10, 5)); String[] types = {"text", "label"}; String[] titles = {"Text", "Label"}; final PandaTable table = new PandaTable(); table.setRows(100); table.setColumns(2); table.setTitles(titles); table.setTypes(types); table.setCell(0, 1, "hoge\nmoge\noge"); table.getModel().addTableModelListener( new TableModelListener() { @Override public void tableChanged(TableModelEvent te) { int row = te.getLastRow(); int col = te.getColumn(); System.out.println("[" + row + "," + col + "] " + table.getModel().getValueAt(row, col) + " " + table.getModel().getValueAt(row, col).getClass()); } }); JScrollPane scroll = new JScrollPane(table); scroll.setPreferredSize(new Dimension(400, 300)); container.add(scroll, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout()); container.add(buttonPanel, BorderLayout.SOUTH); JButton button3 = new JButton(new AbstractAction("output") { @Override public void actionPerformed(ActionEvent ev) { } }); buttonPanel.add(button3); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setSize(500, 500); frame.setVisible(true); table.changeSelection(2, 2, false, true); } }