表格是GUI編程中使用較多,但也是最麻煩的一個控制項之一。表格是用來顯示二維資料,提供編輯,選擇等功能。如果只是顯示資料,這還是非常easy的,只要在JTable中傳入二維數組或集合就可以了,eg
public class SimpleTable<br />{<br />JFrame jf = new JFrame("簡單表格");<br />JTable table;<br />//定義二維數組作為表格式資料<br />Object[][] tableData =<br />{<br />new Object[]{"李清照" , 29 , "女"},<br />new Object[]{"蘇格拉底", 56 , "男"},<br />new Object[]{"李白", 35 , "男"},<br />new Object[]{"弄玉", 18 , "女"},<br />new Object[]{"虎頭" , 2 , "男"}<br />};<br />//定義一維資料作為欄位標題<br />Object[] columnTitle = {"姓名" , "年齡" , "性別"};<br />public void init()<br />{<br />//以二維數組和一維數組來建立一個JTable對象<br />table = new JTable(tableData , columnTitle);<br />//將JTable對象放在JScrollPane中,並將該JScrollPane放在視窗中顯示出來<br />jf.add(new JScrollPane(table));<br />jf.pack();<br />jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />jf.setVisible(true);<br />}<br /> public static void main(String[] args)<br /> {<br />new SimpleTable().init();<br /> }<br />}<br />
下面舉個JTable表格調整和選擇方式的例子,eg
public class AdjustingWidth<br />{<br />JFrame jf = new JFrame("調整表格列寬");<br />JMenuBar menuBar = new JMenuBar();<br />JMenu adjustModeMenu = new JMenu("調整方式");<br />JMenu selectUnitMenu = new JMenu("選擇單元");<br />JMenu selectModeMenu = new JMenu("選擇方式");</p><p>//定義5個單選框按鈕,用以控製表格的寬度調整方式<br />JRadioButtonMenuItem[] adjustModesItem = new JRadioButtonMenuItem[5];<br />//定義3個單選框按鈕,用以控製表格的選擇方式<br />JRadioButtonMenuItem[] selectModesItem = new JRadioButtonMenuItem[3];</p><p> JCheckBoxMenuItem rowsItem = new JCheckBoxMenuItem("選擇行");<br /> JCheckBoxMenuItem columnsItem = new JCheckBoxMenuItem("選擇列");<br /> JCheckBoxMenuItem cellsItem = new JCheckBoxMenuItem("選擇儲存格");<br />ButtonGroup adjustBg = new ButtonGroup();<br />ButtonGroup selectBg = new ButtonGroup();<br />//定義一個int類型的數組,用於儲存表格所有的寬度調整方式<br />int[] adjustModes = new int[]{<br />JTable.AUTO_RESIZE_OFF,<br />JTable.AUTO_RESIZE_NEXT_COLUMN,<br />JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS,<br />JTable.AUTO_RESIZE_LAST_COLUMN,<br />JTable.AUTO_RESIZE_ALL_COLUMNS<br />};<br />int[] selectModes = new int[]{<br />ListSelectionModel.MULTIPLE_INTERVAL_SELECTION ,<br />ListSelectionModel.SINGLE_INTERVAL_SELECTION ,<br />ListSelectionModel.SINGLE_SELECTION<br />};<br />JTable table;<br />//定義二維數組作為表格式資料<br />Object[][] tableData =<br />{<br />new Object[]{"李清照" , 29 , "女"},<br />new Object[]{"蘇格拉底", 56 , "男"},<br />new Object[]{"李白", 35 , "男"},<br />new Object[]{"弄玉", 18 , "女"},<br />new Object[]{"虎頭" , 2 , "男"}<br />};<br />//定義一維資料作為欄位標題<br />Object[] columnTitle = {"姓名" , "年齡" , "性別"};</p><p>public void init()<br />{<br />//以二維數組和一維數組來建立一個JTable對象<br />table = new JTable(tableData , columnTitle);</p><p>//-----------為視窗安裝設定表格調整方式的菜單-----------<br />adjustModesItem[0] = new JRadioButtonMenuItem("只調整表格");<br />adjustModesItem[1] = new JRadioButtonMenuItem("只調整下一列");<br />adjustModesItem[2] = new JRadioButtonMenuItem("平均調整餘下列");<br />adjustModesItem[3] = new JRadioButtonMenuItem("只調整最後一列");<br />adjustModesItem[4] = new JRadioButtonMenuItem("平均調整所有列");<br />menuBar.add(adjustModeMenu);<br />for (int i = 0; i < adjustModesItem.length ; i++)<br />{<br />//預設選中第三個功能表項目,即對應表格預設的寬度調整方式<br />if (i == 2)<br />{<br />adjustModesItem[i].setSelected(true);<br />}<br />adjustBg.add(adjustModesItem[i]);<br />adjustModeMenu.add(adjustModesItem[i]);<br />final int index = i;<br />//為設定調整方式的功能表項目添加監聽器<br />adjustModesItem[i].addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent evt)<br />{<br />//如果當前功能表項目處於選中狀態,表格使用對應的調整方式<br />if (adjustModesItem[index].isSelected())<br />{<br />table.setAutoResizeMode(adjustModes[index]);<br />}<br />}<br />});<br />}<br />//-----------為視窗安裝設定表格選擇方式的菜單-----------<br />selectModesItem[0] = new JRadioButtonMenuItem("無限制");<br />selectModesItem[1] = new JRadioButtonMenuItem("單獨的連續區");<br />selectModesItem[2] = new JRadioButtonMenuItem("單選");<br />menuBar.add(selectModeMenu);<br />for (int i = 0; i < selectModesItem.length ; i++)<br />{<br />//預設選中第一個功能表項目,即對應表格預設的選擇方式<br />if (i == 0)<br />{<br />selectModesItem[i].setSelected(true);<br />}<br />selectBg.add(selectModesItem[i]);<br />selectModeMenu.add(selectModesItem[i]);<br />final int index = i;<br />//為設定選擇方式的功能表項目添加監聽器<br />selectModesItem[i].addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent evt)<br />{<br />//如果當前功能表項目處於選中狀態,表格使用對應的選擇方式<br />if (selectModesItem[index].isSelected())<br />{<br />table.getSelectionModel().setSelectionMode(selectModes[index]);<br />}<br />}<br />});<br />}<br />menuBar.add(selectUnitMenu);<br />//-----------為視窗安裝設定表格選擇單元的菜單-----------<br />rowsItem.setSelected(table.getRowSelectionAllowed());<br />columnsItem.setSelected(table.getColumnSelectionAllowed());<br />cellsItem.setSelected(table.getCellSelectionEnabled());</p><p>rowsItem.addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />table.clearSelection();<br />//如果該功能表項目處於選中狀態,設定表格的選擇單元是行<br />table.setRowSelectionAllowed(rowsItem.isSelected());<br />//如果選擇行、選擇列同時被選中,其實質是選擇儲存格<br />cellsItem.setSelected(table.getCellSelectionEnabled());<br />}<br />});<br />selectUnitMenu.add(rowsItem);<br />columnsItem.addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />table.clearSelection();<br />//如果該功能表項目處於選中狀態,設定表格的選擇單元是列<br />table.setColumnSelectionAllowed(columnsItem.isSelected());<br />//如果選擇行、選擇列同時被選中,其實質是選擇儲存格<br />cellsItem.setSelected(table.getCellSelectionEnabled());<br />}<br />});<br />selectUnitMenu.add(columnsItem);<br />cellsItem.addActionListener(newActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />table.clearSelection();<br />//如果該功能表項目處於選中狀態,設定表格的選擇單元是儲存格<br />table.setCellSelectionEnabled(cellsItem.isSelected());<br />//該選項的改變會同時影響選擇行、選擇列兩個菜單<br />rowsItem.setSelected(table.getRowSelectionAllowed());<br />columnsItem.setSelected(table.getColumnSelectionAllowed());<br />}<br />});<br />selectUnitMenu.add(cellsItem);</p><p>jf.setJMenuBar(menuBar);<br />//分別擷取表格的三個表格列,並設定三列的最小寬度,最佳寬度和最大寬度<br />TableColumn nameColumn = table.getColumn(columnTitle[0]);<br />nameColumn.setMinWidth(40);<br />TableColumn ageColumn = table.getColumn(columnTitle[1]);<br />ageColumn.setPreferredWidth(50);<br />TableColumn genderColumn = table.getColumn(columnTitle[2]);<br />genderColumn.setMaxWidth(50);</p><p>//將JTable對象放在JScrollPane中,並將該JScrollPane放在視窗中顯示出來<br />jf.add(new JScrollPane(table));<br />System.out.println(table.getModel());<br />jf.pack();<br />jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />jf.setVisible(true);<br />}</p><p> public static void main(String[] args)<br /> {<br />new AdjustingWidth().init();<br /> }<br />}<br />
和JList,JTree類似,JTable採用TableModel來儲存表格中的所有狀態資料,採用TableColumnModel來儲存所有列的資料。eg
public class TestDefaultTableModel<br />{<br />JFrame mainWin = new JFrame("管理資料行、資料列");<br />final int COLUMN_COUNT = 5;<br />DefaultTableModel model;<br />JTable table;<br />//用於儲存被隱藏列的List集合<br />ArrayList<TableColumn> hiddenColumns = new ArrayList<TableColumn>();<br />public void init()<br />{<br />model = new DefaultTableModel(COLUMN_COUNT ,COLUMN_COUNT);<br />for (int i = 0; i < COLUMN_COUNT ; i++ )<br />{<br />for (int j = 0; j < COLUMN_COUNT ; j++ )<br />{<br />model.setValueAt("老儲存格值 " + i + " " + j , i , j);<br />}<br />}</p><p>table = new JTable(model);</p><p>mainWin.add(new JScrollPane(table), BorderLayout.CENTER);</p><p>//為視窗安裝菜單<br />JMenuBar menuBar = new JMenuBar();<br />mainWin.setJMenuBar(menuBar);<br />JMenu tableMenu = new JMenu("管理");<br />menuBar.add(tableMenu);</p><p>JMenuItem hideColumnsItem = new JMenuItem("隱藏選中列");<br />hideColumnsItem.addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />//擷取所有選中列的索引<br />int[] selected = table.getSelectedColumns();<br />TableColumnModel columnModel = table.getColumnModel();<br />//依次把每一個選中的列隱藏起來,並使用List把這些列儲存起來<br />for (int i = selected.length - 1; i >= 0; i--)<br />{<br />TableColumn column = columnModel.getColumn(selected[i]);<br />table.removeColumn(column);<br />//把隱藏的列儲存起來,確保以後可以顯示出來<br />hiddenColumns.add(column);<br />}<br />}<br />});<br />tableMenu.add(hideColumnsItem);</p><p>JMenuItem showColumnsItem = new JMenuItem("顯示隱藏列");<br />showColumnsItem.addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />//把所有隱藏列依次顯示出來<br />for (TableColumn tc : hiddenColumns)<br />{<br />//依次把所有隱藏的列顯示出來<br />table.addColumn(tc);<br />}<br />//清空儲存隱藏列的List集合<br />hiddenColumns.clear();<br />}<br />});<br />tableMenu.add(showColumnsItem);</p><p>JMenuItem addColumnItem = new JMenuItem("插入選中列");<br />addColumnItem.addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />//擷取所有選中列的索引<br />int[] selected = table.getSelectedColumns();<br />TableColumnModel columnModel = table.getColumnModel();<br />//依次把選中的列添加到JTable之後<br />for (int i = selected.length - 1; i >= 0; i--)<br />{<br />TableColumn column = columnModel.getColumn(selected[i]);<br />table.addColumn(column);<br />}<br />}<br />});<br />tableMenu.add(addColumnItem);</p><p>JMenuItem addRowItem = new JMenuItem("增加行");<br />addRowItem.addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />//建立一個String數組作為新增行的內容<br />String[] newCells = new String[COLUMN_COUNT];<br />for (int i = 0; i < newCells.length; i++)<br />{<br />newCells[i] = "新儲存格值 " + model.getRowCount() + " " + i;<br />}<br />//向TableModel中新增一行。<br />model.addRow(newCells);<br />}<br />});<br />tableMenu.add(addRowItem);</p><p>JMenuItem removeRowsItem = new JMenuItem("刪除選中行");<br />removeRowsItem.addActionListener(new ActionListener()<br />{<br />public void actionPerformed(ActionEvent event)<br />{<br />//擷取所有選中行<br />int[] selected = table.getSelectedRows();<br />//依次刪除所有選中行<br />for (int i = selected.length - 1; i >= 0; i--)<br />{<br />model.removeRow(selected[i]);<br />}<br />}<br />});<br />tableMenu.add(removeRowsItem);</p><p>mainWin.pack();<br />mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />mainWin.setVisible(true);<br />}</p><p>public static void main(String[] args)<br />{<br />new TestDefaultTableModel().init();<br />}<br />}
但要注意列的增加,只是將原來隱藏的列顯示,而不是真正增加列,你要新增的話那就重新new個JTable
前面講的表格,儲存格都是字串,這是由於我們傳入的都是DefaultTableModel它最終調用toString方法來繪製表格,具體自訂儲存格的方法如下,eg
public class TestTableCellRenderer<br />{<br />JFrame jf = new JFrame("使用儲存格繪製器");<br />JTable table;<br />//定義二維數組作為表格式資料<br />Object[][] tableData =<br />{<br />new Object[]{"李清照" , 29 , "女" , new ImageIcon("icon/3.gif") , true},<br />new Object[]{"蘇格拉底", 56 , "男" , new ImageIcon("icon/1.gif") , false},<br />new Object[]{"李白", 35 , "男" , new ImageIcon("icon/4.gif") , true},<br />new Object[]{"弄玉", 18 , "女" , new ImageIcon("icon/2.gif") , true},<br />new Object[]{"虎頭" , 2 , "男" , new ImageIcon("icon/5.gif") , true}<br />};<br />//定義一維資料作為欄位標題<br />String[] columnTitle = {"姓名" , "年齡" , "性別" , "主頭像" , "是否中國人"};<br />public void init()<br />{<br />//以二維數組和一維數組來建立一個ExtendedTableModel對象<br />ExtendedTableModel model = new ExtendedTableModel(columnTitle , tableData);<br />//以ExtendedTableModel來建立JTable<br />table = new JTable( model);<br />table.setRowSelectionAllowed(false);<br />table.setRowHeight(40);<br />//擷取第三列<br />TableColumn lastColumn = table.getColumnModel().getColumn(2);<br />//對第三列採用自訂的儲存格繪製器<br />lastColumn.setCellRenderer(new GenderTableCellRenderer());</p><p>//將JTable對象放在JScrollPane中,並將該JScrollPane放在視窗中顯示出來<br />jf.add(new JScrollPane(table));<br />jf.pack();<br />jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br />jf.setVisible(true);<br />}<br /> public static void main(String[] args)<br /> {<br />new TestTableCellRenderer().init();<br /> }<br />}</p><p>class ExtendedTableModel extends DefaultTableModel<br />{<br />//重新提供一個構造器,該構造器的實現委託給DefaultTableModel父類<br />public ExtendedTableModel(String[] columnNames , Object[][] cells)<br />{<br />super(cells , columnNames);<br />}<br />//重寫getColumnClass方法,根據每列的第一個值來返回其真實的資料類型<br />public Class getColumnClass(int c)<br />{<br />return getValueAt(0 , c).getClass();<br />}<br />}</p><p>class GenderTableCellRenderer extends JPanel implements TableCellRenderer<br />{<br />private String cellValue;<br />//定義表徵圖的寬度和高度<br />final int ICON_WIDTH = 23;<br />final int ICON_HEIGHT = 21;<br />public Component getTableCellRendererComponent(JTable table, Object value,<br />boolean isSelected, boolean hasFocus, int row, int column)<br />{<br />cellValue = (String)value;<br />//設定選中狀態下繪製邊框<br />if (hasFocus)<br />{<br />setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));<br />}<br />else<br />{<br />setBorder(null);<br />}<br />return this;<br />}<br />//重寫paint方法,負責繪製該儲存格內容<br />public void paint(Graphics g)<br />{<br />//如果表格值為"男"或"male",則繪製一個男性表徵圖<br />if (cellValue.equalsIgnoreCase("男")<br />|| cellValue.equalsIgnoreCase("male"))<br />{<br />drawImage(g , new ImageIcon("icon/male.gif").getImage());<br />}<br />//如果表格值為"女"或"female",則繪製一個女性表徵圖<br />if (cellValue.equalsIgnoreCase("女")<br />|| cellValue.equalsIgnoreCase("female"))<br />{<br />drawImage(g , new ImageIcon("icon/female.gif").getImage());<br />}<br />}<br />//繪製表徵圖的方法<br />private void drawImage(Graphics g , Image image)<br />{<br />g.drawImage(image, (getWidth() - ICON_WIDTH ) / 2<br />, (getHeight() - ICON_HEIGHT) / 2 , null);<br />}<br />}
我這裡只是實現了每列不同的控制項,大家還可以自訂一個表格每行每列都是不同的控制項,那就要得到儲存格再setCellRender。