用JTable实现Excel冻结列效果

本文介绍了一种在Java Swing中实现表格冻结列的方法,通过使用两个JTable和JScrollPane来确保部分列在水平滚动时保持固定。文章提供了详细的代码实现,并解释了同步选择和鼠标事件的具体方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
具体思路:
1.   我们可以考虑使用两个JTablefixTablemainTable
2.   定义一个JScrollPane,mainTable放在他的viewPort中,
3.   在新new一个JViewport,把fixTable放在他的上面
4.   利用JScrollPanesetRowHeaderView()方法,把这个JViewport作为他的RowHeader
5.   最后把fixTable tableHeader放在JScrollPane的左上方(利用setCorner方法
6.   实现选中的同步,因为是2table,所以我们要人工实现他的同步,使用户开着好象一个table.
7.   有的时候我们可能还要在表格上监听鼠标事件,那么这个我们如何同步呢,我的想法是我们增加鼠标事件时只给mainTable添加,而fixTable的鼠标事件默认调用mainTable的处理方法,从而实现事件的传递。
好了下面我们来看一下代码:
首先是我封装好的FixTable
(1)  import java.awt.event.MouseAdapter;
(2)  import java.awt.event.MouseEvent;
(3)  import java.awt.event.MouseListener;
(4)   
(5)  import javax.swing.JScrollPane;
(6)  import javax.swing.JTable;
(7)  import javax.swing.JViewport;
(8)  import javax.swing.ListSelectionModel;
(9)  import javax.swing.event.ListSelectionEvent;
(10) import javax.swing.event.ListSelectionListener;
(11) import javax.swing.table.AbstractTableModel;
(12)  
(13) publicclass FixTable {
(14)  private JTable mainTable;
(15)  private JTable fixTable;
(16)  private FixTableModel fixModel;
(17)  private MainTableModel mainModel;
(18)  privateintfixColumnCount;// 冻结的列数
(19)  private String[] columnHeader;// 表头
(20)  private JScrollPane mainScroll;//装载在父Container的组件
(21)  
(22)  // private Vector tableData = new Vector(); //表格中数据
(23)  private Object[][] tableData;
(24)  
(25)  public FixTable(int fixColumnCount, String[] columnHeader,
(26)          Object[][] tableData) {
(27)     this.fixColumnCount = fixColumnCount;
(28)     this.columnHeader = columnHeader;
(29)     this.tableData = tableData;//
(30)     this.initComponents();
(31)  }
(32)  
(33)  /**
(34)   *初始化界面
(35)   */
(36)  privatevoid initComponents() {
(37)     mainTable =new JTable();
(38)     fixTable =new JTable();
(39)     mainModel =new MainTableModel();
(40)     fixModel =new FixTableModel();
(41)     mainTable.setModel(mainModel);
(42)     mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
(43)     mainTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
(44)     fixTable.setModel(fixModel);
(45)     fixTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
(46)     fixTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
(47)  
(48)     mainTable.getSelectionModel().addListSelectionListener(
(49)            new ListSelectionListener() {
(50)  
(51)                @Override
(52)                publicvoid valueChanged(ListSelectionEvent e) {
(53)                   // TODO Auto-generated method stub
(54)                    checkSelection(false);
(55)                 }
(56)  
(57)             });
(58)     fixTable.getSelectionModel().addListSelectionListener(
(59)            new ListSelectionListener() {
(60)                @Override
(61)                publicvoid valueChanged(ListSelectionEvent e) {
(62)                   // TODO Auto-generated method stub
(63)                    checkSelection(true);
(64)                 }
(65)             });
(66)  
(67)     // 添加鼠标事件同步两个表的鼠标双击事件
(68)     mainTable.addMouseListener(new MouseAdapter() {
(69)         publicvoid mouseClicked(MouseEvent e) {
(70)            if (e.getClickCount() > 1) {
(71)                if (e.getSource().equals(mainTable)) {
(72)                    MouseListener[] mls = (MouseListener[])fixTable
(73)                           .getListeners(MouseListener.class);
(74)                   for (int i = 0; i < mls.length; i++)
(75)                        mls[i].mouseClicked(e);
(76)                 }
(77)  
(78)             }
(79)          }
(80)      });
(81)  
(82)     fixTable.addMouseListener(new MouseAdapter() {
(83)         publicvoid mouseClicked(MouseEvent e) {
(84)            if (e.getClickCount() > 1) {
(85)                if (e.getSource().equals(fixTable)) {
(86)                    System.out.println("首先点击了冻结列");
(87)                 }else {
(88)                    System.out.println("首先点击了内容列");
(89)                 }
(90)                // if (e.getSource().equals(fixTable)) {
(91)                // MouseListener[] mls = (MouseListener[]) mainTable
(92)                // .getListeners(MouseListener.class);
(93)                // for (int i = 0; i < mls.length; i++)
(94)                // mls[i].mouseClicked(e);
(95)                // }
(96)             }
(97)          }
(98)      });
(99)  
(100)       mainScroll =new JScrollPane();
(101)       mainScroll.getViewport().add(mainTable);
(102)  
(103)        JViewport fixPort =new JViewport();
(104)        fixPort.setPreferredSize(fixTable.getPreferredSize());
(105)        fixPort.add(fixTable);
(106)       mainScroll.setRowHeaderView(fixPort);
(107)       mainScroll.setCorner(JScrollPane.UPPER_LEFT_CORNER,fixTable
(108)               .getTableHeader());
(109)     }
(110)  
(111)    /**
(112)      *在表格中放入数据
(113)      *
(114)      *@paramtableData
(115)      */
(116)    publicvoid setData(Object[][] tableData) {
(117)       this.tableData = tableData;
(118)     }
(119)  
(120)    /**
(121)      *返回冻结表格的内容面板使用panel.add(table.getTableContentPane());才能使表格加到容器中
(122)      *
(123)      *@return
(124)      */
(125)    public JScrollPane getTableContentPane() {
(126)       returnmainScroll;
(127)     }
(128)  
(129)    /**
(130)      *使两个table同时响应选中事件
(131)      *
(132)      *@paramisFixedTable
(133)      */
(134)    privatevoid checkSelection(boolean isFixedTable) {
(135)       int fixedSelectedIndex =fixTable.getSelectedRow();
(136)       int selectedIndex =mainTable.getSelectedRow();
(137)       if (fixedSelectedIndex != selectedIndex) {
(138)           if (isFixedTable) {
(139)              mainTable.setRowSelectionInterval(fixedSelectedIndex,
(140)                      fixedSelectedIndex);
(141)            }else {
(142)              fixTable.setRowSelectionInterval(selectedIndex, selectedIndex);
(143)            }
(144)        }
(145)  
(146)     }
(147)  
(148)    /**
(149)      *冻结的列表模型
(150)      *
(151)      *@authorbenson
(152)      *
(153)      */
(154)    privateclass FixTableModelextends AbstractTableModel {
(155)  
(156)       @Override
(157)       publicint getColumnCount() {
(158)           // TODO Auto-generated method stub
(159)           returnfixColumnCount;
(160)        }
(161)  
(162)       @Override
(163)       publicint getRowCount() {
(164)           // TODO Auto-generated method stub
(165)           returntableData.length;
(166)        }
(167)  
(168)       @Override
(169)       public Object getValueAt(int rowIndex, int columnIndex) {
(170)           // TODO Auto-generated method stub
(171)           if (tableData[rowIndex][columnIndex] !=null)
(172)              returntableData[rowIndex][columnIndex];
(173)           return"";
(174)        }
(175)  
(176)       public String getColumnName(int column) {
(177)           returncolumnHeader[column];
(178)        }
(179)     }
(180)  
(181)    /**
(182)      *数据列表模型
(183)      *
(184)      *@authorbenson
(185)      *
(186)      */
(187)    privateclass MainTableModelextends AbstractTableModel {
(188)  
(189)       @Override
(190)       publicint getColumnCount() {
(191)           // TODO Auto-generated method stub
(192)           returncolumnHeader.length - fixColumnCount;
(193)        }
(194)  
(195)       @Override
(196)       publicint getRowCount() {
(197)           // TODO Auto-generated method stub
(198)           returntableData.length;
(199)        }
(200)  
(201)       @Override
(202)       public Object getValueAt(int rowIndex, int columnIndex) {
(203)           // TODO Auto-generated method stub
(204)           if (tableData[rowIndex][columnIndex +fixColumnCount] !=null)
(205)              returntableData[rowIndex][columnIndex +fixColumnCount];
(206)           return"";
(207)        }
(208)  
(209)       public String getColumnName(int column) {
(210)           returncolumnHeader[column +fixColumnCount];
(211)        }
(212)  
(213)     }
(214) }
 
测试主函数
 
import java.awt.BorderLayout;
import java.awt.Dimension;
 
import javax.swing.JFrame;
import javax.swing.JPanel;
 
publicclass FixTableFrameextends JFrame {
 
    private FixTabletable;
 
    /**
     *Launchtheapplication
     *
     *@paramargs
     */
    publicstaticvoid main(String args[]) {
       try {
           FixTableFrame frame =new FixTableFrame();
           frame.setVisible(true);
           frame.pack();
       } catch (Exception e) {
           e.printStackTrace();
       }
    }
 
    /**
     *Createtheframe
     */
    public FixTableFrame() {
       super("冻结表头");
       this.setPreferredSize(new Dimension(300, 200));
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
       final JPanel panel =new JPanel();
       panel.setLayout(new BorderLayout());
       getContentPane().add(panel, BorderLayout.CENTER);
 
       String[] columns =new String[] {"姓名","学号","英语","语文","数学","综合" };
 
       Object[][] data =new Object[][] {
              { "Benson","1","84","74","65","76" },
              { "Jim","2","63","77","88","99" },
              { "King","3","78","76","56","98" },
              { "Laura","4","98","76","87","66" },
              { "Fisher","5","76","46","86","45" },
              { "Mike","6","54","78","67","44" } };
       table =new FixTable(1, columns, data);
       // table.setData(data);
       //此方法一定调用
        //不能用panel.add(table);因为table已经不是一个Component而是一个合成组件
       panel.add(table.getTableContentPane());
    }
 
}
 
结束语:当然这个表格功能还不完善,还需要添加刷新,增加,删除等功能,实现起来并不复杂,那就大家自己来实现吧。
 
效果图:
 
 
 
 
其实滚动面板中还可以放其它面板来实现表格效果
JScrollPane有以下两个方法 setColumnHeaderView(Component view) setRowHeaderView(Component view) 你可以利用它们, 一个用来显示表行头,一个用来显示列头

 主要代码:    其中jpnlMain/jpnlRowHeader/jpnlRowHeader都是面板,注意主面板的PreferredSize大小是行和列所对应的大小.

jslPanel.getViewport().add(jpnlMain);
  JViewport vpColumHeader= new JViewport();
  vpColumHeader.setView(jpnlColumHeader);

 vpColumHeader.setPreferredSize(jpnlRowHeader.getPreferredSize());

  JViewport vpRowHeader= new JViewport();
  vpRowHeader.setView(jpnlRowHeader);
  vpRowHeader.setPreferredSize(jpnlRowHeader.getPreferredSize());

  jslPanel.setColumnHeader(vpColumHeader);
  jslPanel.setRowHeader(vpRowHeader);

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值