讓界面更加絢麗JavaSE6.0四種新功能
在上一篇中我介紹了Java SE 6在GUI上的部分改進。在這篇文章中我接著介紹另外幾種新的GUI功能。這些功能是:
·帶有排序和過濾功能的JTable。
·增強的JTabbedPane組件
·增強的打印功能
·增強的拖放功能
帶有排序和過濾功能的JTable
在Java SE 6中除了java.awt被更新外,javax.swing同時也有了很大的改進。在C/S程序中我們會經常使用到"表"。如我們可以在查詢數據庫后將查詢結果顯示在表格中。在Java中顯示表格使用的是JTable類。在以前的版本中,JTable只能簡單地顯示數據,并沒有什么附加的處理功能,而在Java SE 6中的JTable增加了排序和過濾功能。用戶可以單擊列頭進行排序,也可以根據某一列來過濾表中的數據。
為了使JTable可以對數據進行,必須將RowSorter類和JTable進行關聯。RowSorter是一個抽象類,它負責將JTable中的數據映射成可排序的數據。在真正使用時,我們將直接使用RowSorter的子類TableRowSorter。下面的代碼顯示了如何將TableRowSorter類和JTable相關聯。
上面代碼首先建立一個TableModel,然后將這個TableModel的實例同時傳遞給了JTable和RowSorter。下面是一個使用JTable排序的簡單的例子。
圖1和圖2分別是按"姓名"進行升序和降序排列的顯示結果。
圖3顯示的是按"年齡"進行降序排列。但我們發現一個奇怪的問題,就是"年齡"字段并不是按數值類型進行排序的,而是按字符類型進行排序的。
出現這種情況是因為在默認情況下DefaultTableModal的列是Object類型。而要想使JTable按數值進行排序,必須要覆蓋DefaultTableModal的getColumnClass方法。
圖4顯示了按"年齡"進行排序的界面,看看,是不是按數值進行排序了。
下面讓我們來看看來何使用JTable進行過濾。我們可以通過convertRowIndexToModel方法進行過濾。下面的代碼加在一個按鈕中添加事件代碼調用JTable的過濾功能。
上面的代碼并沒有調用convertRowIndextoModel()方法,如果調用它,你就可以在表中進行相應的操作。
在JTable中通過抽象類RowFilter類對行進行過濾。和排序不同,你可以不建立它們的子類,而使用這個抽象類的6個靜態方法。
·andFilter
·dateFilter(RowFilter.ComparisonType type, Date date, int... indices)
·notFilter(RowFilter<M,I> filter)
·numberFilter(RowFilter.ComparisonType type, Number number, int... indices)
·orFilter
·regexFilter(String regex, int... indices)
其中andFilter()、orFilter()以及notFilter()方法的功能是將當前的過濾條件和其它的過濾條件進行組合。如在同時比較日期和數值時需要將日期過濾和數值過濾進行組合。這些組合是非常簡單的。
RowFilter的類型比較允許你進行4種關系的比較,等于、不等于、大于或小于。我們可以通過指定某一列進行過濾,也可以對所有的列進行過濾。這其中最為有趣的也許是正則表達式過濾(regular expression filter,或簡稱為regex filter)。使用這個過濾器可以對表中數據進行更高級的過濾。下面是實現一個簡單過濾器的代碼。
圖5是上面程序的運行界面。
增強的JTabbedPane組件
JTabbedPane組件為我們提供了一種非常好的方法在窗體上顯示很多的控件。我們可以將不同類別的控件放到不同的Tab頁上,然后通過需要點擊相應的Tab頁。在傳統的Tab頁上只能防止文本的圖標。而在Java SE 6中使我們可以直接將控件放到Tab上。我們可以通過setTabComponentAt方法將控件放到Tab上。這個方法有兩個參數,一個是Tab的索引,另一個是要放置的對象。
在JTabbedPane控件中有3個常用的方法,setTabComponentAt(int index, Component comp), getTabComponentAt(int index)和indexOfTabComponent(Component)。最后一個方法將替換Tab上的控件。下面的代碼是一個關于JTabbedPane控件的演示。
圖6是顯示界面,其中在Tab4上插入了一個文本控件,在Tab1至Tab5上各插入了一個按鈕控件。
增強的打印功能
自從Java SE 5開始,Sun就對控件的打印功能進行了加強。如JTextField、JTextArea等。在Java SE 6中Sun為打印增加了分頁功能。我們只需要調用JtextField或JTextArea的print方法就可以調用打印對話框。下面是一段測試代碼。
圖7和圖8分別是打印對話框和設置對話框,點擊"打印"按鈕后彈出如圖8的對話框。
雖然提供了打印設置對話框,但我們并無法設置如頁眉(角)等信息,幸運的是print的一個重載為我們提供了這個功能。下面是這個方法的參數。
增強的拖放功能
在Java SE 6中的拖放功能得到了增強,這主要表現在兩個方面。
·可以定制拖放模式。
可以在拖放的過程中加入其它的輔助信息。 首先需要通過JList、JTable等控件的setDropMode()方法來設置一個拖動模式。所有的控件都可以使用USER_SELECTION模式。這個模式在以前的Java SE版本中就有。這也是默認的拖放模式。
JList、JTable和Jlist都支持ON模式,這個模式允許你將對象拖到其它項的上方。而INSERT模式允許將一個對象插入在其它項之間。而ON_OR_INSERT模式是前3種模式的組合。下面的代碼將演示一個拖動的例子。
圖9為拖動程序的運行界面。在上面的文本框里輸入相應的文本,然后將其選擇再拖動到下方的樹中。
·帶有排序和過濾功能的JTable。
·增強的JTabbedPane組件
·增強的打印功能
·增強的拖放功能
帶有排序和過濾功能的JTable
在Java SE 6中除了java.awt被更新外,javax.swing同時也有了很大的改進。在C/S程序中我們會經常使用到"表"。如我們可以在查詢數據庫后將查詢結果顯示在表格中。在Java中顯示表格使用的是JTable類。在以前的版本中,JTable只能簡單地顯示數據,并沒有什么附加的處理功能,而在Java SE 6中的JTable增加了排序和過濾功能。用戶可以單擊列頭進行排序,也可以根據某一列來過濾表中的數據。
為了使JTable可以對數據進行,必須將RowSorter類和JTable進行關聯。RowSorter是一個抽象類,它負責將JTable中的數據映射成可排序的數據。在真正使用時,我們將直接使用RowSorter的子類TableRowSorter。下面的代碼顯示了如何將TableRowSorter類和JTable相關聯。
TableModel model = new DefaultTableModel(rows, columns); JTable table = new JTable(model); RowSorter sorter = new TableRowSorter(model); table.setRowSorter(sorter); |
上面代碼首先建立一個TableModel,然后將這個TableModel的實例同時傳遞給了JTable和RowSorter。下面是一個使用JTable排序的簡單的例子。
import javax.swing.*; import javax.swing.table.*; import java.awt.*; public class TestSortedTable { public static void main(String args[]) { JFrame frame = new JFrame("JTable的排序測試"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 表格中顯示的數據 Object rows[][] = { { "王明", "中國", 44 }, { "姚明", "中國", 25 }, { "趙子龍", "西蜀", 1234 }, { "曹操", "北魏", 2112 }, { "Bill Gates", "美國", 45 }, { "Mike", "英國", 33 } }; String columns[] = { "姓名", "國籍", "年齡" }; TableModel model = new DefaultTableModel(rows, columns); JTable table = new JTable(model); RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model); table.setRowSorter(sorter); JScrollPane pane = new JScrollPane(table); frame.add(pane, BorderLayout.CENTER); frame.setSize(300, 150); frame.setVisible(true); } } |
圖1和圖2分別是按"姓名"進行升序和降序排列的顯示結果。
![]() 圖1 按"姓名"升序顯示 ![]() 圖2 按"姓名"降序顯示 |
圖3顯示的是按"年齡"進行降序排列。但我們發現一個奇怪的問題,就是"年齡"字段并不是按數值類型進行排序的,而是按字符類型進行排序的。
![]() 圖3 按年齡降序顯示 |
出現這種情況是因為在默認情況下DefaultTableModal的列是Object類型。而要想使JTable按數值進行排序,必須要覆蓋DefaultTableModal的getColumnClass方法。
TableModel model = new DefaultTableModel(rows, columns) { public Class getColumnClass(int column) { Class returnValue; if ((column >= 0) && (column < getColumnCount())) { returnValue = getValueAt(0, column).getClass(); } else { returnValue = Object.class; } return returnValue; } }; |
圖4顯示了按"年齡"進行排序的界面,看看,是不是按數值進行排序了。
![]() 圖4 按數值類型進行排序 |
下面讓我們來看看來何使用JTable進行過濾。我們可以通過convertRowIndexToModel方法進行過濾。下面的代碼加在一個按鈕中添加事件代碼調用JTable的過濾功能。
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String text = filterText.getText(); if (text.length() == 0) { sorter.setRowFilter(null); } else { sorter.setRowFilter(RowFilter.regexFilter(text)); } } }); |
上面的代碼并沒有調用convertRowIndextoModel()方法,如果調用它,你就可以在表中進行相應的操作。
在JTable中通過抽象類RowFilter類對行進行過濾。和排序不同,你可以不建立它們的子類,而使用這個抽象類的6個靜態方法。
·andFilter
·dateFilter(RowFilter.ComparisonType type, Date date, int... indices)
·notFilter(RowFilter<M,I> filter)
·numberFilter(RowFilter.ComparisonType type, Number number, int... indices)
·orFilter
·regexFilter(String regex, int... indices)
其中andFilter()、orFilter()以及notFilter()方法的功能是將當前的過濾條件和其它的過濾條件進行組合。如在同時比較日期和數值時需要將日期過濾和數值過濾進行組合。這些組合是非常簡單的。
RowFilter的類型比較允許你進行4種關系的比較,等于、不等于、大于或小于。我們可以通過指定某一列進行過濾,也可以對所有的列進行過濾。這其中最為有趣的也許是正則表達式過濾(regular expression filter,或簡稱為regex filter)。使用這個過濾器可以對表中數據進行更高級的過濾。下面是實現一個簡單過濾器的代碼。
import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; public class TestFilter { public static void main(String args[]) { JFrame frame = new JFrame("JTable的過濾測試"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Object rows[][] = { { "王明", "中國", 44 }, { "姚明", "中國", 25 }, { "趙子龍", "西蜀", 1234 }, { "曹操", "北魏", 2112 }, { "Bill Gates", "美國", 45 }, { "Mike", "英國", 33 } }; String columns[] = { "姓名", "國籍", "年齡" }; TableModel model = new DefaultTableModel(rows, columns) { public Class getColumnClass(int column) { Class returnValue; if ((column >= 0) && (column < getColumnCount())) { returnValue = getValueAt(0, column).getClass(); } else { returnValue = Object.class; } return returnValue; } }; final JTable table = new JTable(model); final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model); table.setRowSorter(sorter); JScrollPane pane = new JScrollPane(table); frame.add(pane, BorderLayout.CENTER); JPanel panel = new JPanel(new BorderLayout()); JLabel label = new JLabel("過濾"); panel.add(label, BorderLayout.WEST); final JTextField filterText = new JTextField(""); panel.add(filterText, BorderLayout.CENTER); frame.add(panel, BorderLayout.NORTH); JButton button = new JButton("過濾"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String text = filterText.getText(); if (text.length() == 0) { sorter.setRowFilter(null); } else { sorter.setRowFilter(RowFilter.regexFilter(text)); } } }); frame.add(button, BorderLayout.SOUTH); frame.setSize(300, 250); frame.setVisible(true); } } |
圖5是上面程序的運行界面。
![]() 圖 5 |
增強的JTabbedPane組件
JTabbedPane組件為我們提供了一種非常好的方法在窗體上顯示很多的控件。我們可以將不同類別的控件放到不同的Tab頁上,然后通過需要點擊相應的Tab頁。在傳統的Tab頁上只能防止文本的圖標。而在Java SE 6中使我們可以直接將控件放到Tab上。我們可以通過setTabComponentAt方法將控件放到Tab上。這個方法有兩個參數,一個是Tab的索引,另一個是要放置的對象。
JTabbedPane pane = new JTabbedPane(); pane.setTabComponentAt(1, component); |
在JTabbedPane控件中有3個常用的方法,setTabComponentAt(int index, Component comp), getTabComponentAt(int index)和indexOfTabComponent(Component)。最后一個方法將替換Tab上的控件。下面的代碼是一個關于JTabbedPane控件的演示。
import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; public class TestTabbedPane { static void addIt(JTabbedPane tabbedPane, String text) { JLabel label = new JLabel(text); JButton button = new JButton(text); JPanel panel = new JPanel(); panel.add(label); panel.add(button); tabbedPane.addTab(text, panel); if(text.equals("tab4")) tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new JTextField("插入了文本控件")); else tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1,button); } public static void main(String args[]) { JFrame f = new JFrame("JTabbedPane演示"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JTabbedPane tabbedPane = new JTabbedPane(); addIt(tabbedPane, "tab1"); addIt(tabbedPane, "tab2"); addIt(tabbedPane, "tab3"); addIt(tabbedPane, "tab4"); addIt(tabbedPane, "tab5"); f.add(tabbedPane, BorderLayout.CENTER); f.setSize(400, 200); f.setVisible(true); } } |
圖6是顯示界面,其中在Tab4上插入了一個文本控件,在Tab1至Tab5上各插入了一個按鈕控件。
![]() 圖6 JTabbedPane演示 |
增強的打印功能
自從Java SE 5開始,Sun就對控件的打印功能進行了加強。如JTextField、JTextArea等。在Java SE 6中Sun為打印增加了分頁功能。我們只需要調用JtextField或JTextArea的print方法就可以調用打印對話框。下面是一段測試代碼。
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.print.*; public class TextPrint { public static void main(final String args[]) { JFrame frame = new JFrame("打印測試"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final JTextArea textArea = new JTextArea(); JScrollPane pane = new JScrollPane(textArea); frame.add(pane, BorderLayout.CENTER); textArea.setText("打印內容...可以分頁!" ); JButton button = new JButton("打印"); frame.add(button, BorderLayout.SOUTH); ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { try { textArea.print(); } catch (PrinterException pe) { System.err.println("打印失敗..."); } } }; button.addActionListener(listener); frame.setSize(250, 150); frame.setVisible(true); } } |
圖7和圖8分別是打印對話框和設置對話框,點擊"打印"按鈕后彈出如圖8的對話框。
![]() 圖7 打印界面 ![]() 圖8 設置對話框 |
雖然提供了打印設置對話框,但我們并無法設置如頁眉(角)等信息,幸運的是print的一個重載為我們提供了這個功能。下面是這個方法的參數。
public boolean print(MessageFormat headerFormat, MessageFormat footerFormat, boolean showPrintDialog, PrintService service, PrintRequestAttributeSet attributes, boolean interactive) |
增強的拖放功能
在Java SE 6中的拖放功能得到了增強,這主要表現在兩個方面。
·可以定制拖放模式。
可以在拖放的過程中加入其它的輔助信息。 首先需要通過JList、JTable等控件的setDropMode()方法來設置一個拖動模式。所有的控件都可以使用USER_SELECTION模式。這個模式在以前的Java SE版本中就有。這也是默認的拖放模式。
JList、JTable和Jlist都支持ON模式,這個模式允許你將對象拖到其它項的上方。而INSERT模式允許將一個對象插入在其它項之間。而ON_OR_INSERT模式是前3種模式的組合。下面的代碼將演示一個拖動的例子。
import java.awt.*; import java.awt.datatransfer.*; import java.awt.event.*; import java.io.*; import javax.swing.*; import javax.swing.tree.*; public class TestDrapDrop { public static void main(String args[]) { JFrame f = new JFrame("拖放測試"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel top = new JPanel(new BorderLayout()); JLabel dragLabel = new JLabel("拖我:"); JTextField text = new JTextField(); text.setDragEnabled(true); top.add(dragLabel, BorderLayout.WEST); top.add(text, BorderLayout.CENTER); f.add(top, BorderLayout.NORTH); final JTree tree = new JTree(); final DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); tree.setTransferHandler(new TransferHandler() { public boolean canImport(TransferHandler.TransferSupport support) { if (!support.isDataFlavorSupported(DataFlavor.stringFlavor) || !support.isDrop()) { return false; } JTree.DropLocation dropLocation = (JTree.DropLocation) suppor.getDropLocation(); return dropLocation.getPath() != null; } public boolean importData(TransferHandler.TransferSupport support) { if (!canImport(support)) { return false; } JTree.DropLocation dropLocation = (JTree.DropLocation) support.getDropLocation(); TreePath path = dropLocation.getPath(); Transferable transferable = support.getTransferable(); String transferData; try { transferData = (String) transferable .getTransferData(DataFlavor.stringFlavor); } catch (IOException e) { return false; } catch (UnsupportedFlavorException e) { return false; } int childIndex = dropLocation.getChildIndex(); if (childIndex == -1) { childIndex = model.getChildCount(path.getLastPathComponent()); } DefaultMutableTreeNode newNode = new DefaultMutableTreeNode( transferData); DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent(); model.insertNodeInto(newNode, parentNode, childIndex); TreePath newPath = path.pathByAddingChild(newNode); tree.makeVisible(newPath); tree.scrollRectToVisible(tree.getPathBounds(newPath)); return true; } }); JScrollPane pane = new JScrollPane(tree); f.add(pane, BorderLayout.CENTER); JPanel bottom = new JPanel(); JLabel comboLabel = new JLabel("DropMode"); String options[] ={ "USE_SELECTION", "ON", "INSERT", "ON_OR_INSERT" }; final DropMode mode[] = {DropMode.USE_SELECTION, DropMode.ON, DropMode.INSERT, DropMode.ON_OR_INSERT }; final JComboBox combo = new JComboBox(options); combo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int selectedIndex = combo.getSelectedIndex(); tree.setDropMode(mode[selectedIndex]); } }); bottom.add(comboLabel); bottom.add(combo); f.add(bottom, BorderLayout.SOUTH); f.setSize(300, 400); f.setVisible(true); } |
圖9為拖動程序的運行界面。在上面的文本框里輸入相應的文本,然后將其選擇再拖動到下方的樹中。
![]() 圖9 拖動界面 |