二十七辟躏、Swing表格組件
- 表格是最常用的數(shù)據(jù)統(tǒng)計(jì)形式之一,在Swing中由JTable類實(shí)現(xiàn)表格吧秕。
1. 創(chuàng)建始赎、定制以及操縱表格
創(chuàng)建表格
- 在JTable類中除了默認(rèn)的構(gòu)造方法外,還提供了如下利用指定表格列名數(shù)組和表格數(shù)據(jù)數(shù)組創(chuàng)建表格的構(gòu)造方法这难。
JTable(Object[][] rowData, Object[] columnNames)
? rowData:封裝表格數(shù)據(jù)的數(shù)組
? columnNames:封裝表格列名的數(shù)組
- 在使用表格時(shí)舟误,通常將其添加到滾動(dòng)面板中,然后將滾動(dòng)面板添加到相應(yīng)的位置姻乓。
定制表格
表格創(chuàng)建完成后嵌溢,還需要對(duì)其進(jìn)行一系列的定義,以便適合于具體的使用情況蹋岩。默認(rèn)情況下通過雙擊表格中的單元格就可以對(duì)其進(jìn)行編輯赖草。
如果不需要提供該功能,可以通過重構(gòu)JTable類的isCellEditable(int row, int column)方法實(shí)現(xiàn)剪个。默認(rèn)情況下該方法返回boolean型值true秧骑,表示指定單元格可編輯,如果返回false則表示不可編輯扣囊。
如果表格只有幾列乎折,通常不需要表格列的可重新排列功能。在創(chuàng)建不支持滾動(dòng)條的表格時(shí)已經(jīng)使用了JTableHeader 類的對(duì)象侵歇,通過該類的setReorderingAllowed(boolean reorderingAllowed)方法即可設(shè)置表格是否支持重新排列功能骂澄,設(shè)為false表示不支持重新排列功能。
操縱表格
- 在編寫應(yīng)用表格的程序時(shí)惕虑,經(jīng)常需要獲得表格的一些信息酗洒,如表格擁有的行數(shù)和列數(shù)。下面是JTable類中三個(gè)經(jīng)常用來獲得表格信息的方法枷遂。
getRowCount():獲得表格擁有的行數(shù)樱衷,返回值為int型。
getColumnCount ():獲得表格擁有的列數(shù)酒唉,返回值為int型矩桂。
getColumnName(int column):獲得位于指定索引位置的列的名稱,返回值為String型。
getValueAt(row,column):獲得指定位置的數(shù)據(jù)侄榴。
下面看一個(gè)實(shí)例雹锣,該實(shí)例涉及到創(chuàng)建表格、定制表格以及操縱表格:
import javax.swing.*;
import java.awt.*;
public class biaoge1 extends JFrame
{
private JTable table;
public static void main(String[] args)
{
biaoge1 frame=new biaoge1();
frame.setVisible(true);
}
public biaoge1()
{
super();
setTitle("操作表格");
setBounds(100,100,500,375);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c=getContentPane();
String[] columnNames={"A","B","C","D","E","F","G"};
String[][] tableValus=new String[20][columnNames.length];
for (int row=0;row<tableValus.length;row++)
{
for (int column=0;column<columnNames.length;column++)
{
tableValus[row][column]=columnNames[column]+row;
}
}
JTable table=new JTable(tableValus,columnNames);
JScrollPane sc=new JScrollPane(table);
c.add(sc,BorderLayout.CENTER);
table.setSelectionBackground(Color.red);
table.setSelectionForeground(Color.yellow);
table.setRowHeight(20);
table.setSelectionMode(2);
table.setAutoResizeMode(4);
System.out.println("表格公有"+table.getRowCount()+"行"+table.getColumnCount()+"列");
System.out.println("第二列的名稱是:"+table.getColumnName(1));
System.out.println("第二行第二列的值為:"+table.getValueAt(1,1));
}
}
運(yùn)行結(jié)果:
- 由運(yùn)行結(jié)果可以看到:首先創(chuàng)建了一個(gè)表格癞蚕,實(shí)現(xiàn)了表格的創(chuàng)建蕊爵,該表格具有滾動(dòng)條;其次該表格可以隨意選中任意行桦山,也可以調(diào)整任意列的列寬攒射,表格高度也可以根據(jù)個(gè)人需要設(shè)置;最后能操縱表格恒水,在控制臺(tái)處可以得到表格的一些信息会放。
2. 表格模型與表格
利用表格模型創(chuàng)建表格
- 接口TableModel定義了一個(gè)表格模型,抽象類AbstractTableModel實(shí)現(xiàn)了TableModel接口的大部分方法钉凌,只有如下三個(gè)抽象方法沒有實(shí)現(xiàn)咧最。
public int getRowCount();
public int getColumnCount();
public Object getValueAt(int rowIndex, int columnIndex);
- 通過繼承AbstractTableModel類實(shí)現(xiàn)上面三個(gè)抽象方法可以創(chuàng)建自己的表格模型類。DefaultTableModel類是由Swing提供的繼承了AbstractTableModel類并實(shí)現(xiàn)了上面三個(gè)抽象方法的表格模型類御雕。
維護(hù)表格模型
在使用表格時(shí)矢沿,經(jīng)常需要對(duì)表格中的內(nèi)容進(jìn)行維護(hù),例如向表格中添加新的數(shù)據(jù)行酸纲、修改表格中某一單元格的值捣鲸、從表格中刪除指定的數(shù)據(jù)行……這些操作均可以通過維護(hù)表格模型來完成。
在向表格模型中添加新的數(shù)據(jù)行時(shí)有兩種情況:一種情況是添加到表格模型的尾部福青,另一種情況是插入到表格模型的指定索引位置。
(1)添加到表格模型的尾部脓诡,可以通過addRow()方法完成无午。
(2)添加到表格模型的指定位置,可以通過insertRow ()方法完成祝谚。
下面看一個(gè)實(shí)例:
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TableModelTest extends JFrame
{
private JTable table;
private JTextField aTextField,bTextField;
private JButton addButton,delButton,updButton;
private DefaultTableModel model;
public static void main(String args[])
{
TableModelTest frame1=new TableModelTest();
frame1.setVisible(true);
}
public TableModelTest()
{
super();
setTitle("維護(hù)表格");
setBounds(100,100,510,300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String[] columnNames={"A","B"};
String[][] tableValues={{"A1","B1"},{"A2","B2"},{"A3","B3"}};
model=new DefaultTableModel(tableValues,columnNames);
table =new JTable(model);
JScrollPane sc=new JScrollPane(table);
getContentPane().add(sc, BorderLayout.CENTER);
buttonInit();
addListener();
}
private void buttonInit()
{
final JPanel panel=new JPanel();
getContentPane().add(panel,BorderLayout.SOUTH);
panel.add(new JLabel("A:"));
aTextField=new JTextField("A4",10);
panel.add(aTextField);
panel.add(new JLabel("B:"));
bTextField=new JTextField("B4",10);
panel.add(bTextField);
addButton=new JButton("添加");
updButton=new JButton("修改");
delButton=new JButton("刪除");
panel.add(addButton);
panel.add(updButton);
panel.add(delButton);
}
private void addListener()
{
//添加按鈕事件
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String rowData[] ={aTextField.getText(),bTextField.getText()};
model.addRow(rowData);
int rowCount=table.getRowCount()+1;
aTextField.setText("A"+rowCount);
bTextField.setText("B"+rowCount);
}
});
//修改按鈕事件
updButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow=table.getSelectedRow();
if (selectedRow!=-1)
{
model.setValueAt(aTextField.getText(),selectedRow,0);
model.setValueAt(bTextField.getText(),selectedRow,1);
}
}
});
//刪除按鈕事件
delButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow=table.getSelectedRow();
if (selectedRow!=-1)
{
model.removeRow(selectedRow);
}
}
});
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
int type=e.getType();
int row=e.getFirstRow();
int column=e.getColumn();
row=row+1;
column=column+1;
if (type==TableModelEvent.INSERT)
{
System.out.println("此事件由\"插入\"行觸發(fā)");
System.out.println("此次插入的是"+row+"行");
}else if (type==TableModelEvent.UPDATE)
{
System.out.println("此事件由\"修改\"行觸發(fā)");
System.out.println("此次修改的是"+row+"行"+column+"列");
}
else if (type==TableModelEvent.DELETE)
{
System.out.println("此事件由\"刪除\"行觸發(fā)");
System.out.println("此次刪除的是"+row+"行");
}else
{
System.out.println("此事件是由其他原因觸發(fā)的");
}
}
});
}
}
運(yùn)行結(jié)果:
- 由運(yùn)行結(jié)果可以看到宪迟,可以實(shí)現(xiàn)對(duì)表格的維護(hù)(即添加、修改交惯、刪除)次泽,并且做了事件監(jiān)聽,在控制臺(tái)處可以看到對(duì)表格實(shí)行了哪些操作席爽。
3. 提供行標(biāo)題欄的表格
通過JTable類創(chuàng)建的表格的列標(biāo)題欄是永遠(yuǎn)可見的意荤,即使是向下滾動(dòng)了垂直滾動(dòng)條,這就大大增強(qiáng)了表格的可讀性只锻。但是當(dāng)不能顯示出表格的所有列時(shí)玖像,如果向右滾動(dòng)水平滾動(dòng)條則會(huì)導(dǎo)致表格左側(cè)的部分列不可見,如果能夠使表格左側(cè)的一列或幾列不隨著水平滾動(dòng)條滾動(dòng)齐饮,也能夠永遠(yuǎn)可見捐寥,就解決了上面的問題笤昨。
可以通過兩個(gè)并列顯示的表格實(shí)現(xiàn)這樣的效果,其中左側(cè)的表格用來顯示永遠(yuǎn)可見的一列或幾列握恳,右側(cè)的表格則用來顯示其他的表格列瞒窒。
Example:
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class ExampleFrame_07 extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
public static void main(String args[]) {
try {
ExampleFrame_07 frame = new ExampleFrame_07();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public ExampleFrame_07() {
super();
setTitle("提供行標(biāo)題欄的表格");
setBounds(100, 100, 500, 375);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Vector<String> columnNameV = new Vector<>();
columnNameV.add("日期");
for (int i = 1; i < 21; i++) {
columnNameV.add("商品" + i);
}
Vector<Vector<Object>> tableValueV = new Vector<>();
for (int row = 1; row < 31; row++) {
Vector<Object> rowV = new Vector<>();
rowV.add(row);
for (int col = 0; col < 20; col++) {
rowV.add((int) (Math.random() * 1000));
}
tableValueV.add(rowV);
}
final MFixedColumnTable panel = new MFixedColumnTable(columnNameV,
tableValueV, 1);
getContentPane().add(panel, BorderLayout.CENTER);
//
}
}
FixedTable:
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class MFixedColumnTable extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTable fixedColumnTable;// 固定列表格對(duì)象
private FixedColumnTableModel fixedColumnTableModel;// 固定列表格模型對(duì)象
private JTable floatingColumnTable;// 移動(dòng)列表格對(duì)象
// 移動(dòng)列表格模型對(duì)象
private FloatingColumnTableModel floatingColumnTableModel;
private Vector<String> columnNameV;// 表格列名數(shù)組
private Vector<Vector<Object>> tableValueV;// 表格數(shù)據(jù)數(shù)組
private int fixedColumn = 1;// 固定列數(shù)量
public MFixedColumnTable(Vector<String> columnNameV,
Vector<Vector<Object>> tableValueV, int fixedColumn) {
super();
setLayout(new BorderLayout());
this.columnNameV = columnNameV;
this.tableValueV = tableValueV;
this.fixedColumn = fixedColumn;
// 創(chuàng)建固定列表格模型對(duì)象
fixedColumnTableModel = new FixedColumnTableModel();
// 創(chuàng)建固定列表格對(duì)象
fixedColumnTable = new JTable(fixedColumnTableModel);
// 獲得選擇模型對(duì)象
ListSelectionModel fixed = fixedColumnTable.getSelectionModel();
// 選擇模式為單選
fixed.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// 添加行被選中的事件監(jiān)聽器
fixed.addListSelectionListener(new MListSelectionListener(true));
// 創(chuàng)建可移動(dòng)列表格模型對(duì)象
floatingColumnTableModel = new FloatingColumnTableModel();
// 創(chuàng)建可移動(dòng)列表格對(duì)象
floatingColumnTable = new JTable(floatingColumnTableModel);
// 關(guān)閉表格的自動(dòng)調(diào)整功能
floatingColumnTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
ListSelectionModel floating = floatingColumnTable
.getSelectionModel();// 獲得選擇模型對(duì)象
// 選擇模式為單選
floating.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// 添加行被選中的事件監(jiān)聽器
MListSelectionListener listener = new MListSelectionListener(false);
floating.addListSelectionListener(listener);
JScrollPane scrollPane = new JScrollPane();// 創(chuàng)建一個(gè)滾動(dòng)面版對(duì)象
// 將固定列表格頭放到滾動(dòng)面版的左上方
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
fixedColumnTable.getTableHeader());
// 創(chuàng)建一個(gè)用來顯示基礎(chǔ)信息的視口對(duì)象
JViewport viewport = new JViewport();
viewport.setView(fixedColumnTable);// 將固定列表格添加到視口中
// 設(shè)置視口的首選大小為固定列表格的首選大小
viewport.setPreferredSize(fixedColumnTable.getPreferredSize());
// 將視口添加到滾動(dòng)面版的標(biāo)題視口中
scrollPane.setRowHeaderView(viewport);
// 將可移動(dòng)表格添加到默認(rèn)視口
scrollPane.setViewportView(floatingColumnTable);
add(scrollPane, BorderLayout.CENTER);
}
private class FixedColumnTableModel extends AbstractTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
public int getColumnCount() {// 返回固定列的數(shù)量
return fixedColumn;
}
public int getRowCount() {// 返回行數(shù)
return tableValueV.size();
}
// 返回指定單元格的值
public Object getValueAt(int rowIndex, int columnIndex) {
return tableValueV.get(rowIndex).get(columnIndex);
}
@Override
public String getColumnName(int columnIndex) {// 返回指定列的名稱
return columnNameV.get(columnIndex);
}
}
private class FloatingColumnTableModel extends AbstractTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
public int getColumnCount() {// 返回可移動(dòng)列的數(shù)量
return columnNameV.size() - fixedColumn;// 需要扣除固定列的數(shù)量
}
public int getRowCount() {// 返回行數(shù)
return tableValueV.size();
}
// 返回指定單元格的值
public Object getValueAt(int rowIndex, int columnIndex) {
// 需要為列索引加上固定列的數(shù)量
return tableValueV.get(rowIndex)
.get(columnIndex + fixedColumn);
}
@Override
public String getColumnName(int columnIndex) {// 返回指定列的名稱
// 需要為列索引加上固定列的數(shù)量
return columnNameV.get(columnIndex + fixedColumn);
}
}
private class MListSelectionListener implements ListSelectionListener {
boolean isFixedColumnTable = true; // 默認(rèn)由選中固定列表格中的行觸發(fā)
public MListSelectionListener(boolean isFixedColumnTable) {
this.isFixedColumnTable = isFixedColumnTable;
}
public void valueChanged(ListSelectionEvent e) {
if (isFixedColumnTable) { // 由選中固定列表格中的行觸發(fā)
// 獲得固定列表格中的選中行
int row = fixedColumnTable.getSelectedRow();
// 同時(shí)選中右側(cè)可移動(dòng)列表格中的相應(yīng)行
floatingColumnTable.setRowSelectionInterval(row, row);
} else { // 由選中可移動(dòng)列表格中的行觸發(fā)
// 獲得可移動(dòng)列表格中的選中行
int row = floatingColumnTable.getSelectedRow();
// 同時(shí)選中左側(cè)固定列表格中的相應(yīng)行
fixedColumnTable.setRowSelectionInterval(row, row);
}
}
}
}
運(yùn)行結(jié)果:
- 由結(jié)果可看到,由兩個(gè)表格拼成了一個(gè)帶有行標(biāo)題的表格乡洼。