Swing 使用 JTable詳解
示例 1 : 基本表格
顯示一個Table需要兩組數據
- 一維數組: String[]columnNames 表示表格的標題
- 二維數組: String[][] heros 表格中的內容
默認情況下,表格的標題是不會顯示出來了,除非使用了JScrollPane
package gui;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JTable;
public class TestGUI {
public static void main(String[] args) {
JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
// 表格上的title
String[] columnNames = new String[] { "id", "name", "hp", "damage" };
// 表格中的內容,是一個二維數組
String[][] heros = new String[][] { { "1", "蓋倫", "616", "100" },
{ "2", "提莫", "512", "102" }, { "3", "奎因", "832", "200" } };
JTable t = new JTable(heros, columnNames);
f.add(t, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
示例 2 : JScrollPane
JScrollPane: 帶滾動條的Panel
把table放進去就可以看到table的title
同樣的把textarea放進去,並且textarea內容夠長的話,就會看到滾動條
package gui;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TestGUI {
public static void main(String[] args) {
JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
String[] columnNames = new String[] { "id", "name", "hp", "damage" };
String[][] heros = new String[][] { { "1", "蓋倫", "616", "100" },
{ "2", "提莫", "512", "102" }, { "3", "奎因", "832", "200" } };
JTable t = new JTable(heros, columnNames);
// 根據t創建 JScrollPane
JScrollPane sp = new JScrollPane(t);
//或則創建一個空的JScrollPane,再通過setViewportView把table放在JScrollPane中
// JScrollPane sp = new JScrollPane(t);
// sp.setViewportView(t);
// 把sp而非JTable加入到JFrame上,
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
示例 3 : 列寬
設置列寬度
package gui;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TestGUI {
public static void main(String[] args) {
JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
String[] columnNames = new String[] { "id", "name", "hp", "damage" };
String[][] heros = new String[][] { { "1", "蓋倫", "616", "100" },
{ "2", "提莫", "512", "102" }, { "3", "奎因", "832", "200" } };
JTable t = new JTable(heros, columnNames);
JScrollPane sp = new JScrollPane(t);
// 設置列寬度
t.getColumnModel().getColumn(0).setPreferredWidth(10);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
示例 4 : TableModel
首先說下TableModel的設計思想,在Model這種思想的指導下,數據和顯示分離開來了。 比如對於JTable而言,有數據部分,也有顯示部分(比如列寬等信息)。 數據部分,專門做一個類,叫做TableModel,就用於存放要顯示的數據。
使用TableModel的方式存放Table需要顯示的數據
HeroTableModel 繼承AbstractTableModel ,進而實現了接口TableModel
在HeroTableModel 中提供一個table顯示需要的所有信息
- getRowCount 返回一共有多少行
- getColumnCount 返回一共有多少列
- getColumnName 每一列的名字
- isCellEditable 單元格是否可以修改
- getValueAt 每一個單元格里的值
當圖形界面需要渲染第一個單元格的數據的時候,就會調用方法TabelModel的getValueAt(0,0) ,把返回值拿到並顯示
package gui;
import javax.swing.table.AbstractTableModel;
public class HeroTableModel extends AbstractTableModel {
String[] columnNames = new String[] { "id", "name", "hp", "damage" };
String[][] heros = new String[][] { { "1", "蓋倫", "616", "100" },
{ "2", "提莫", "512", "102" }, { "3", "奎因", "832", "200" } };
// 返回一共有多少行
public int getRowCount() {
// TODO Auto-generated method stub
return heros.length;
}
// 返回一共有多少列
public int getColumnCount() {
// TODO Auto-generated method stub
return columnNames.length;
}
// 獲取每一列的名稱
public String getColumnName(int columnIndex) {
// TODO Auto-generated method stub
return columnNames[columnIndex];
}
// 單元格是否可以修改
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
// 每一個單元格里的值
public Object getValueAt(int rowIndex, int columnIndex) {
// TODO Auto-generated method stub
return heros[rowIndex][columnIndex];
}
}
.
package gui;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TestGUI {
public static void main(String[] args) {
JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
//創建一個TableModel
HeroTableModel htm= new HeroTableModel();
//根據 TableModel來創建 Table
JTable t = new JTable(htm);
JScrollPane sp = new JScrollPane(t);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
示例 5 : 進一步理解TableModel
在使用TableModel之前,是使用
String[] columnNames =。。。
String[][] heros = 。。。
JTable t = new JTable(heros, columnNames);
這樣的風格創建一個JTable的
所以實際上調用的是如下的構造方法:
JTable(Object[][] rowData, Object[] columnNames)
如圖所示,在JTable的的源代碼中,它就會根據rowData和columnNames去創建一個TableModel對象
示例 6 : TableModel 與DAO結合
通過TableModel與DAO結合顯示數據庫中Hero信息。
DAO使用HeroDAO
在TableModel中,使用從DAO返回的List作為TableModel的數據
只需要修改HeroTableModel,無需修改TestGUI。 這正好演繹了Model設計思想中的數據分離的好處,當只需要數據發生變化的時候,修改Model即可,界面GUI部分,不需要做任何改動
package gui;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import jdbc.HeroDAO;
import charactor.Hero;
public class HeroTableModel extends AbstractTableModel {
String[] columnNames = new String[] { "id", "name", "hp", "damage" };
// 使用從DAO返回的List作為TableModel的數據
public List<Hero> heros = new HeroDAO().list();
// heros.size返回一共有多少行
public int getRowCount() {
// TODO Auto-generated method stub
return heros.size();
}
public int getColumnCount() {
// TODO Auto-generated method stub
return columnNames.length;
}
public String getColumnName(int columnIndex) {
// TODO Auto-generated method stub
return columnNames[columnIndex];
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
// 先通過heros.get(rowIndex)獲取行對應的Hero對象
// 然后根據columnIndex返回對應的屬性
public Object getValueAt(int rowIndex, int columnIndex) {
Hero h = heros.get(rowIndex);
if (0 == columnIndex)
return h.id;
if (1 == columnIndex)
return h.name;
if (2 == columnIndex)
return h.hp;
if (3 == columnIndex)
return h.damage;
return null;
}
}
示例 7 : TableSelectionModel
通過table可以獲取一個 TableSelectionModel,專門用於監聽jtable選中項的變化
package gui;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import charactor.Hero;
public class TestGUI {
public static void main(String[] args) {
JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
final HeroTableModel htm = new HeroTableModel();
final JTable t = new JTable(htm);
// 准備一個Panel上面放一個Label用於顯示哪條被選中了
JPanel p = new JPanel();
final JLabel l = new JLabel("暫時未選中條目");
p.add(l);
JScrollPane sp = new JScrollPane(t);
// 使用selection監聽器來監聽table的哪個條目被選中
t.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
// 當選擇了某一行的時候觸發該事件
public void valueChanged(ListSelectionEvent e) {
// 獲取哪一行被選中了
int row = t.getSelectedRow();
// 根據選中的行,到HeroTableModel中獲取對應的對象
Hero h = htm.heros.get(row);
// 更新標簽內容
l.setText("當前選中的英雄是: " + h.name);
}
});
f.add(p, BorderLayout.NORTH);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
示例 8 : 更新Table
以新增數據到數據庫中,然后更新Table為例
package gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import jdbc.HeroDAO;
import charactor.Hero;
public class TestGUI {
public static void main(String[] args) {
JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
final HeroTableModel htm = new HeroTableModel();
final JTable t = new JTable(htm);
// 增加 一個 panel用於放置名稱,血量輸入框和增加 按鈕
JPanel p = new JPanel();
final JLabel lName = new JLabel("名稱");
final JTextField tfName = new JTextField("");
final JLabel lHp = new JLabel("血量");
final JTextField tfHp = new JTextField("");
JButton bAdd = new JButton("增加");
tfName.setPreferredSize(new Dimension(80, 30));
tfHp.setPreferredSize(new Dimension(80, 30));
p.add(lName);
p.add(tfName);
p.add(lHp);
p.add(tfHp);
p.add(bAdd);
// 為增加按鈕添加監聽
bAdd.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
HeroDAO dao = new HeroDAO();
// 根據輸入框數據創建一個Hero對象
Hero h = new Hero();
h.name = tfName.getText();
h.hp = Integer.parseInt(tfHp.getText());
// 通過dao把該對象加入到數據庫
dao.add(h);
// 通過dao更新tablemodel中的數據
htm.heros = dao.list();
// 調用JTable的updateUI,刷新界面。
// 刷新界面的時候,會到tablemodel中去取最新的數據
// 就能看到新加進去的數據了
t.updateUI();
}
});
JScrollPane sp = new JScrollPane(t);
f.add(p, BorderLayout.NORTH);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
示例 9 : 輸入項驗證
如果用戶輸入的名稱為空,或者血量不是小數,在提交數據的時候都會報錯。
“感覺上” 界面就卡住了。 這是不友好的人機交互行為。
所以需要加上輸入項的驗證,如果輸入的數據不合格,應該彈出對話框提示用戶具體原因。
package gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import jdbc.HeroDAO;
import charactor.Hero;
public class TestGUI {
public static void main(String[] args) {
final JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
final HeroTableModel htm = new HeroTableModel();
final JTable t = new JTable(htm);
JPanel p = new JPanel();
final JLabel lName = new JLabel("名稱");
final JTextField tfName = new JTextField("");
final JLabel lHp = new JLabel("血量");
final JTextField tfHp = new JTextField("");
JButton bAdd = new JButton("增加");
tfName.setPreferredSize(new Dimension(80, 30));
tfHp.setPreferredSize(new Dimension(80, 30));
p.add(lName);
p.add(tfName);
p.add(lHp);
p.add(tfHp);
p.add(bAdd);
bAdd.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
HeroDAO dao = new HeroDAO();
Hero h = new Hero();
String name = tfName.getText();
// 通過name長度判斷 名稱是否為空
if (name.length() == 0) {
// 彈出對話框提示用戶
JOptionPane.showMessageDialog(f, "名稱不能為空");
// 名稱輸入框獲取焦點
tfName.grabFocus();
return;
}
String hp = tfHp.getText().trim();
try {
// 把hp轉換為浮點型,如果出現異常NumberFormatException表示不是浮點型格式
Float.parseFloat(hp);
} catch (NumberFormatException e1) {
JOptionPane.showMessageDialog(f, "血量只能是小數 ");
tfHp.grabFocus();
return;
}
h.name = name;
h.hp = Float.parseFloat(hp);
dao.add(h);
htm.heros = dao.list();
t.updateUI();
}
});
JScrollPane sp = new JScrollPane(t);
f.add(p, BorderLayout.NORTH);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
示例 10 : 選中指定行
- table初始化后,應該默認選中第一行
- 增加數據后,也應該選中新增的這一條
package gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import jdbc.HeroDAO;
import charactor.Hero;
public class TestGUI {
public static void main(String[] args) {
final JFrame f = new JFrame("LoL");
f.setSize(400, 300);
f.setLocation(200, 200);
f.setLayout(new BorderLayout());
final HeroTableModel htm = new HeroTableModel();
final JTable t = new JTable(htm);
// 設置選擇模式為 只能選中一行
t.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// 選中第一行 (基本0)
t.getSelectionModel().setSelectionInterval(0, 0);
JPanel p = new JPanel();
final JLabel lName = new JLabel("名稱");
final JTextField tfName = new JTextField("");
final JLabel lHp = new JLabel("血量");
final JTextField tfHp = new JTextField("");
JButton bAdd = new JButton("增加");
tfName.setPreferredSize(new Dimension(80, 30));
tfHp.setPreferredSize(new Dimension(80, 30));
p.add(lName);
p.add(tfName);
p.add(lHp);
p.add(tfHp);
p.add(bAdd);
bAdd.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
HeroDAO dao = new HeroDAO();
Hero h = new Hero();
String name = tfName.getText();
if (name.length() == 0) {
JOptionPane.showMessageDialog(f, "名稱不能為空");
tfName.grabFocus();
return;
}
String hp = tfHp.getText().trim();
try {
Float.parseFloat(hp);
} catch (NumberFormatException e1) {
JOptionPane.showMessageDialog(f, "血量只能是小數 ");
tfHp.grabFocus();
return;
}
h.name = name;
h.hp = Float.parseFloat(hp);
dao.add(h);
htm.heros = dao.list();
t.updateUI();
// 選中 第一行 ,因為 DAO是按照 ID倒排序查詢,所以第一行就是新加入的數據
t.getSelectionModel().setSelectionInterval(0, 0);
}
});
JScrollPane sp = new JScrollPane(t);
f.add(p, BorderLayout.NORTH);
f.add(sp, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
更多內容,點擊了解: Swing 使用 JTable詳解