Java SE 6之GUI:讓界面更加絢麗(下)
Java SE 6之GUI:讓界面更加絢麗( 上)
在上一篇中我介紹了Java SE 6在GUI上的部分改進(jìn)。在這篇 文章中我接著介紹另外幾種新的GUI功能。這些功能是:
1. 帶有排序和過(guò)濾功能的JTable。
2. 增強(qiáng)的JTabbedPane組件
3. 增強(qiáng)的打印功能
4. 增強(qiáng)的拖放功能
一、帶有排序和過(guò)濾功能的JTable。
在Java SE 6中除了 java.awt被更新外,javax.swing同時(shí)也有了很大的改進(jìn)。在 C/S程序中我們會(huì)經(jīng)常使用到 “表”。如我們可以在查詢數(shù)據(jù)庫(kù)后將查詢結(jié)果顯示在表格中。在Java中顯示表格使用的是JTable類。在以前的版本中,JTable只能簡(jiǎn)單地顯示數(shù)據(jù),并沒(méi)有什么附加的處理功能,而在Java SE 6中的JTable增加了排序和過(guò)濾功能。用戶可以單擊列頭進(jìn)行排序,也可以根據(jù)某一列來(lái)過(guò)濾表中的數(shù) 據(jù)。
為了使JTable可以對(duì)數(shù)據(jù)進(jìn)行,必須將< /span>RowSorter類和 JTable進(jìn)行關(guān)聯(lián)。 RowSorter是一個(gè)抽象類,它負(fù)責(zé)將 JTable中的數(shù)據(jù)映射成可排序的數(shù)據(jù)。在真正使用時(shí),我們將直接使用 RowSorter的子類TableRowSorter。下面的代碼顯示了如何將 TableRowSorter類和JTable相關(guān)聯(lián)。
JTable table = new JTable(model);
RowSorter sorter = new TableRowSorter(model);
table.setRowSorter(sorter);
上面代碼首先建立一個(gè)TableModel,然后將這個(gè) TableModel的實(shí)例同時(shí)傳遞給了JTable和 RowSorter。下面是一個(gè)使用 JTable排序的簡(jiǎn)單的例子。
import javax.swing.table.*;
import java.awt.*;
public class TestSortedTable
{
public static void main(String args[])
{
JFrame frame = new JFrame("JTable的排序測(cè)試");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 表格中顯示的數(shù)據(jù)
Object rows[][] =
{
{ " 王明 ", "中國(guó)", 44 },
{ " 姚明 ", "中國(guó)", 25 },
{ " 趙子龍 ", "西蜀", 1234 },
{ " 曹操 ", "北魏", 2112 },
{ " Bill Gates ", "美國(guó)", 45 },
{ " Mike", "< /span>英國(guó)", 33 } };
String columns[] =
{ " 姓名 ", "國(guó)籍", "年齡" };
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
分別是按“姓名”進(jìn)行升序和降序排列的顯示結(jié)果。
圖1 按“姓名”升序顯示
圖2 按“姓名”降序顯示
圖3顯示的是按“年齡”進(jìn)行降序排列。但我們發(fā)現(xiàn)一個(gè)奇怪的問(wèn)題 ,就是“年齡”字段并不是按數(shù)值類型進(jìn)行排序的,而是按字符類型進(jìn)行排序的。

圖3 按年齡降序顯示
出現(xiàn)這種情況是因?yàn)樵谀J(rèn)情況下DefaultTableModal的 列是Object類型。而要想使JTable按數(shù)值進(jìn)行排序,必須要覆蓋 DefaultTableModal的getColumnClass方法。
{
public Class getColumnClass(int column)
{
Class returnValue;
if ((column >= 0) && (column < getColumnCount()))
{
returnValue = getValueAt(0, column).getClass();
}
else
{
returnValue = Object.class;
}
return returnValue;
}
};
圖4顯示了按“年齡”進(jìn)行排序的界面,看看,是不是按數(shù)值進(jìn)行排序了。
圖4 按數(shù)值類型進(jìn)行排序
下面讓我們來(lái)看看來(lái)何使用JTable進(jìn)行過(guò)濾。我們可以 通過(guò)convertRowIndexToModel方法進(jìn)行過(guò)濾。下面的代碼加在一個(gè)按鈕中添加事件代碼調(diào)用JTable的過(guò)濾功能。
{
public void actionPerformed(ActionEvent e)
{
String text = filterText.getText();
if (text.length() == 0)
{
sorter.setRowFilter(null);
}
else
{
sorter.setRowFilter (RowFilter.regexFilter(text));
}
}
});
上面的代碼并沒(méi)有調(diào)用convertRowIndextoModel()方法,如果調(diào)用它,你就可以在 表中進(jìn)行相應(yīng)的操作。
在 JTable中通過(guò)抽象類 RowFilter類對(duì)行進(jìn)行過(guò)濾。和排序不同,你可以不建立它們的子類,而使用這個(gè)抽象類的6個(gè)靜態(tài)方法。
1. andFilter
2. dateFilter(RowFilter.ComparisonType type, Date date, int... indices)
3. notFilter(RowFilter<M,I> filter)
4. numberFilter(RowFilter.ComparisonType type, Number number, int... indices)
5. orFilter
6. regexFilter(String regex, int... indices)
其中andFilter()、orFilter()以及 notFilter()方法的功能是將當(dāng)前的過(guò)濾條件和其它的過(guò)濾條件進(jìn)行組合。如在同時(shí)比較日期和數(shù) 值時(shí)需要將日期過(guò)濾和數(shù)值過(guò)濾進(jìn)行組合。這些組合是非常簡(jiǎn)單的。
RowFilter的類型比較允許你進(jìn)行4種關(guān)系的比較,等于 、不等于、大于或小于。我們可以通過(guò)指定某一列進(jìn)行過(guò)濾,也可以對(duì)所有的列進(jìn)行過(guò)濾。這其中最為有趣的也許是正則表達(dá)式過(guò)濾(regular expression filter,或簡(jiǎn)稱為regex filter)。使用這個(gè)過(guò)濾器可以對(duì)表中數(shù)據(jù)進(jìn)行更高級(jí)的過(guò)濾。下面是實(shí)現(xiàn)一個(gè)簡(jiǎn) 單過(guò)濾器的代碼。
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的過(guò)濾測(cè)試");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Object rows[][] =
{
{ " 王明 ", "中國(guó)", 44 },
{ " 姚明 ", "中國(guó)", 25 },
{ " 趙子龍 ", "西蜀", 1234 },
{ " 曹操 ", "北魏", 2112 },
{ " Bill Gates ", "美國(guó)", 45 },
{ " Mike", "< /span>英國(guó)", 33 } };
String columns[] =
{ " 姓名 ", "國(guó)籍", "年齡" };
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("過(guò)濾");
panel.add(label, BorderLayout.WEST);
final JTextField filterText = new JTextField("");
panel.add(filterText, BorderLayout.CENTER);
frame.add(panel, BorderLayout.NORTH);
JButton button = new JButton("過(guò)濾");
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是上面程序的運(yùn)行界面。
二、增強(qiáng)的JTabbedPane組件
JTabbedPane組件為我們提供了一種非常好的方法在窗體上顯示很多的控件。我們可以將不同類別的控 件放到不同的Tab頁(yè)上,然后通過(guò)需要點(diǎn)擊相應(yīng)的Tab頁(yè)。在傳統(tǒng)的 Tab頁(yè)上只能防止文本的圖標(biāo)。而在 Java SE 6中使我們可以直接將控件放到 Tab上。我們可以通過(guò) setTabComponentAt方法將控件放到Tab上。這個(gè)方法有兩個(gè)參數(shù),一個(gè)是Tab的索引,另一個(gè)是要放置的對(duì)象。
pane.setTabComponentAt(1, component);
在JTabbedPane控件中有3個(gè)常用的方法,setTabComponentAt(int
index, Component comp), getTabComponentAt
(int index)和indexOfTabComponent(Component)。最后一個(gè)方法將替換Tab上的控件。下面的代碼是一個(gè)關(guān)于JTabbedPane控件的演示。
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上插入了一個(gè)文本控件,在Tab1至Tab5上各插入了一個(gè) 按鈕控件。

圖6 JTabbedPane演示
三、增強(qiáng)的打印功能
自從Java SE 5開(kāi)始, Sun就對(duì)控件的打印功能進(jìn)行了加強(qiáng)。如 JTextField、JTextArea等。在 Java
SE 6中Sun為打印增加了分頁(yè)功能。我們只需要調(diào)用 JtextField或 JTextArea的print方法就可以調(diào)用打印對(duì)話框。下面是一段測(cè)試代
碼。
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("打印測(cè)試");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JTextArea textArea = new JTextArea();
JScrollPane pane = new JScrollPane(textArea);
frame.add(pane, BorderLayout.CENTER);
textArea.setText("打印 內(nèi)容

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分別是打印對(duì)話框和設(shè)置對(duì)話框, 點(diǎn)擊“打印“按鈕后彈出如圖8的對(duì)話框。

圖7 打印界面

圖8 設(shè)置對(duì)話框
雖然提供了打印設(shè)置對(duì)話框,但我們并無(wú)法設(shè)置如頁(yè)眉(角)等信息,幸運(yùn)的是print的一個(gè)重載為我們提供了這個(gè)功能。下面是這個(gè)方法的參數(shù)。
public boolean print(MessageFormat headerFormat,
MessageFormat footerFormat,
boolean showPrintDialog,
PrintService service,
PrintRequestAttributeSet attributes,
boolean interactive)
四、增強(qiáng)的拖放功能
在 Java SE 6中的拖放功能得到了增強(qiáng),這主要表現(xiàn)在兩個(gè) 方面。
1. 可以定制拖放模式。
2. 可以在拖放的過(guò)程中加入其它的輔助信息。
首先需要通過(guò)JList、JTable等控件的 setDropMode()方法來(lái)設(shè)置一個(gè)拖動(dòng)模式。所有的控件都可以使用 USER_SELECTION模式。這個(gè)模式在以前的Java SE版本中就有。這也是默認(rèn)的拖放模式。
JList、JTable和Jlist都支持ON模式,這個(gè)模式允許你將對(duì)象拖到其它項(xiàng)的上方。而INSERT模式允許將 一個(gè)對(duì)象插入在其它項(xiàng)之間。而ON_OR_INSERT模式是前3種模式的組合。下面的代碼將演 示一個(gè)拖動(dòng)的例子。
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(" 拖放測(cè)試" );
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
.getDropLocat ion();
return dropLocation.getPath() != null;
}
public boolean importData (TransferHandler.TransferSupport support)
{
if (!canImport(support))
{
return false;
}
JTree.DropLocation dropLocation = (JTree.DropLocation) support
.getDropLocat ion();
TreePath path = dropLocation.getPath();
Transferable transferable = support.getTransferable();
String transferData;
try
{
transferData = (String) transferable
& nbsp; .getTransferData(DataFlavor.stringFlavor);
}
catch (IOException e)
{
return false;
}
catch (UnsupportedFlavorException e)
{
return false;
}
int childIndex = dropLocation.getChildIndex();
if (childIndex == -1)
{
childIndex = model.getChildCount(path
& nbsp; .getLastPathComponent());
}
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(
transferData) ;
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path
.getLastPathC omponent();
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為拖動(dòng)程序的運(yùn)行界面。在上面的文本框里輸入相應(yīng)的 文本,然后將其選擇再拖動(dòng)到下方的樹中。

圖 9 拖動(dòng)界面
《Android開(kāi)發(fā)完全講義(第2版)》(本書版權(quán)已輸出到臺(tái)灣)
http://product.dangdang.com/product.aspx?product_id=22741502
《Android高薪之路:Android程序員面試寶典 》http://book.360buy.com/10970314.html
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining
posted on 2008-04-30 20:19 銀河使者 閱讀(7923) 評(píng)論(6) 編輯 收藏 所屬分類: java 、 原創(chuàng)