上一次寫的 JTable Editor Demo 只有新增功能,但是沒有刪除功能。原本想要弄一個 toolbar,但是看起來又很醜,所以就想到要用 row header 來做。

row header 從 google 找來的資料有分二種,一個是用 JList 來做,一個是用 JTable。由於 JTable 做 rowheader 還可以拖拉改變寬度,所以我主要以 JTable 來做 row header。

rowHeader = new JTable(); rowHeader.setBackground(table.getTableHeader().getBackground()); scrollPane.setRowHeaderView(rowHeader); scrollPane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, rowHeader.getTableHeader()); JViewport jv = scrollPane.getRowHeader(); jv.setPreferredSize(new Dimension(rowHeader.getTableHeader().getColumnModel().getColumn(0).getWidth(), rowHeader.getHeight()));

加入 rowheader 很簡單,只要依照前三行加入即可,第四行則是設定左上角的內容,沒有亦可。但是儘儘只有那四行雖然可以,但是在顯示時,使用 BorderLayout 會造成一開始就把 row header 佈滿所有畫面。所以必須加入最後二行,才能把 row header 的寬度固定住。如果只是單純修改 column width 是沒用的,也就是 rowHeader.getColumnModel().getColumn(0).setWidth(xx); 無效,而必須修改 scrollPane 位於 row header 部位的 JViewport。

rowHeader = new JTable();
JViewport jv = new JViewport(rowHeader);
scrollPane.setRowHeaderView(jv);

上面這段程式碼也是可以,但是卻有一個問題。也就是出現 vertical scroll bar 時,row header 的上下瀏覽無法正常顯示。不知什麼原因,檢視 jdk source code 發現 scrollPane.setRowHeaderView(rowHeader) 也就相當於上述三行指令,但不知為什麼就有問題,真是莫名奇妙。

class RowHeaderModel extends AbstractTableModel implements TableModelListener {
        JTable table;
        public RowHeaderModel(JTable table) {
                this.table = table;
                table.getModel().addTableModelListener(this);
        }
        public String getColumnName(int col) {
                return "test";
        }
        public int getColumnCount() {
                return 1;
        }
        public int getRowCount() {
                return table.getRowCount();
        }
        public Object getValueAt(int row, int col) {
                if (row < (table.getRowCount()-1))
                        return "刪除"+row;
                else
                        return "新增"+row;
        }
        public void tableChanged(TableModelEvent arg0) {
                this.fireTableDataChanged();
        }
}

接下來為了讓二個 table 同步,所以必須把 rowheader 的 tablemodel 掛勾在主 table 的 tablemodellistener 裏。只要主 table 有變動時,就會通知 rowheader 執行 tableChanged 來更新資料。在上述程式碼裏紅字的那幾行就是用來處理同步,當然還需要 getRowCount() { return table.getRowCount(); } 的配合才行。

rowHeader.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { ((JTableModel)table.getModel()).removeRow(rowHeader.rowAtPoint(e.getPoint())); } });

接下來為了實現 rowheader 上可以有個按鈕,按一下就可以刪除整行資料,就把 rowheader 的資料改成 JButton,結果發現按鈕的事件 actionPerformed 卻沒有作用。最後上網找到資料 Adding a JButton to the Cells of a Jtable,原來 JTable 不會把 mouse event 傳遞到儲存格的元件,才會使 JButton 失效。所以就變成自己要實做 mouse event 處理,再利用 table 的 rowAtPoint 函數來取得游標在那一行。另外由於 TableModel 沒有刪除資料的函數,只有在 DefaultTableModel 才有,所以必須另外實做 removeRow 函數。二者相組合,就可以逹到在 rowheaer 按一下就刪除該行資料的效果。

透過 jnlp 執行範例程式

台南小新 發表在 痞客邦 PIXNET 留言(0) 人氣()