Java自學-圖形界面 表格


Swing 使用 JTable詳解

示例 1 : 基本表格

顯示一個Table需要兩組數據

  1. 一維數組: String[]columnNames 表示表格的標題
  2. 二維數組: 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內容夠長的話,就會看到滾動條

JScrollPane

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顯示需要的所有信息

  1. getRowCount 返回一共有多少行
  2. getColumnCount 返回一共有多少列
  3. getColumnName 每一列的名字
  4. isCellEditable 單元格是否可以修改
  5. 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對象

進一步理解TableModel
示例 6 : TableModel 與DAO結合

通過TableModel與DAO結合顯示數據庫中Hero信息。
DAO使用HeroDAO
在TableModel中,使用從DAO返回的List作為TableModel的數據

只需要修改HeroTableModel,無需修改TestGUI。 這正好演繹了Model設計思想中的數據分離的好處,當只需要數據發生變化的時候,修改Model即可,界面GUI部分,不需要做任何改動

TableModel 與DAO結合

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選中項的變化

TableSelectionModel

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 : 選中指定行

  1. table初始化后,應該默認選中第一行
  2. 增加數據后,也應該選中新增的這一條

選中指定行

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詳解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM