有才華的人,別忘記給滋潤(rùn)你的那塊土壤施肥

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            28 隨筆 :: 5 文章 :: 147 評(píng)論 :: 0 Trackbacks

                  
                    當(dāng)很表格中有很多列的時(shí)候出現(xiàn)Scrollbar的時(shí)候,當(dāng)用戶拖動(dòng)Scrollbar那么有的列就會(huì)看不見,而用戶需
          要輸入數(shù)據(jù)的時(shí)候,需要對(duì)照第一列或前幾列以方便輸入數(shù)據(jù),則需要固定前幾列的需求了。像Excle表格
          中可以固定前幾列,而在JTable中沒有直接的方法實(shí)現(xiàn),網(wǎng)上比較流行的方法是用兩個(gè)JTable,如下圖(一)其中
          一個(gè)talbe渲染固定列的數(shù)據(jù),另外一個(gè)主table渲染其他數(shù)據(jù),然后把渲染固定列數(shù)據(jù)的表格當(dāng)做裝載主table的
          JScrollPane的Row Header。這樣實(shí)現(xiàn)就要把表格中的數(shù)據(jù)拆分成兩個(gè)TableModel用于其渲染。
          其中實(shí)現(xiàn)的效果如圖二,其詳細(xì)的代碼見  Fixed Demo


              圖一

                                                                 圖二                                                     

                   很顯然這種實(shí)現(xiàn)方式有一下缺點(diǎn):
                   1)、當(dāng)用戶對(duì)于自己的表格有自己實(shí)現(xiàn)的自定義的列頭,比如行的序列號(hào)或增加了選擇框等等這樣就會(huì)有沖突。
                   2)、如上所說當(dāng)拆分成兩個(gè)TableModel的時(shí)候,那么要很好的維護(hù)兩個(gè)表格一些屬性保持一致將很麻煩,比如
                            選擇,排序等。
                    3)、最重要的一點(diǎn)就是如果在其原有的項(xiàng)目中增加這一需求,那么這種方法就要修改很多地方,侵入性太強(qiáng)。
                  
                  基于上述缺點(diǎn),Elie Levy 用了另外一種方法,盡管也有些缺點(diǎn)(暫且后面再說),他實(shí)現(xiàn)的方法很簡(jiǎn)單(效果如圖三),
          就是將要固定的列的內(nèi)容畫在一個(gè)另外一個(gè)組件上然后將這個(gè)組件放在JTable之上,其總是占據(jù)其表格的指定需要固定
          的列上,這表格的前幾列看起來就是固定了的,如圖三,我們需要固定前三列,那么我們將前三列的內(nèi)容畫在一個(gè)
          JLabel上如圖中黑色部分,這時(shí)候的關(guān)鍵技術(shù)就是利用JLayeredPane的原理了,獲得JTable的JLayeredPane,然后將這個(gè)
          畫出所要固定列的內(nèi)容的JLabel加進(jìn)JLayeredPane,就能忽悠成固定了。


          圖三

                主要實(shí)現(xiàn)代碼分析,實(shí)現(xiàn)主要監(jiān)聽鼠標(biāo)事件,捕捉所要固定的列的內(nèi)容予以即時(shí)更新,這個(gè)類FixTableManager
          為了方便我們繼承于JTableHeader,那么在這里我們重寫paint()方法:以更新拖動(dòng)Scrollbar的時(shí)候列頭的現(xiàn)實(shí)信息,
          代碼如:
           @Override
           
          public void paint(Graphics g) {
            
          super.paint(g);
            
          //int division = mouseListener.getDivision();
            int division = mouseListener.getDivision();
            
          if (division > 0){
             Rectangle r 
          = getVisibleRect();
             BufferedImage image 
          = new BufferedImage(division, r.height,
               BufferedImage.TYPE_INT_ARGB);
             Graphics g2 
          = image.getGraphics();
             g2.setClip(
          00, division, r.height);
             g2.setColor(Color.WHITE);
             g2.fillRect(
          00, division, r.height);
             
          super.paint(g2);
             g.drawImage(image, r.x, r.y, division, r.height, 
          null);
             g2.dispose();
            }

           }
               畫完了固定的列的列頭,我們就要畫表格中的內(nèi)容了,這里我們就是把這些內(nèi)容畫在一個(gè)JLabel上,如下:
           private class FixedColumnsDelegate extends JLabel{
            
          public void paintComponent(Graphics g) {
             Rectangle r 
          = table.getBounds();
             
          if (division > 0{
              table.invalidate();
              table.validate();
              Rectangle visibleRect 
          = table.getVisibleRect();
              BufferedImage image 
          = new BufferedImage(division, r.height,
                BufferedImage.TYPE_INT_ARGB);
              Graphics g2 
          = image.getGraphics();

              g2.setClip(
          0, visibleRect.y, division,
                table.getBounds().height);
              
              g2.setColor(Color.RED);
              g2.fillRect(
          00, division, table.getBounds().height);
              
              table.paint(g2);
              g.drawImage(image, 
          00, division,
                table.getBounds().height, 
          0, visibleRect.y,
                division, visibleRect.y 
          + table.getBounds().height,
                
          null);
          //    g.setColor(Color.BLACK);
          //    for (int i = 0; i < visibleRect.y
          //      + table.getBounds().height; i += 8) {
          //     g.drawLine(division - 1, i, division - 1, i + 4);
          //     g.drawLine(division - 2, i, division - 2, i + 4);
          //    }
              g2.dispose();
             }

            }

           }
             
                接下來就是鼠標(biāo)等一些事件來監(jiān)聽畫出固定列的信息了。當(dāng)捕捉到需要將固定的列固定住,就調(diào)用如下方法:
          /**
            *固定列
            *利用JLayeredPane使其顯示在JTable之上
            *
          */

            
          public void freeze() {
             JLayeredPane pane 
          = table.getRootPane().getLayeredPane();
             
          if (added) {
              pane.remove(fixedColumns);
             }
           
             pane.add(fixedColumns, JLayeredPane.POPUP_LAYER);
             setBoundsOnFrozenColumns();
             added 
          = true;
             fixedColumns.setVisible(
          true);
            }

              還有一些繁雜的計(jì)算ixedColumns的位置大小大家可以下載代碼自己看了,大致原理就是如此簡(jiǎn)單,就是利用JLayeredPane
          層的概念,用起來也很方便,只需要在原有的代碼傳入JTable,以及裝在這個(gè)JTable的JScrollPane,如
           JTable table = new JTable(data, columnNames);
            JScrollPane scrollPane 
          = new JScrollPane(table);
            FixTableManager tableHeader 
          = new FixTableManager(table,scrollPane);
            
          //固定前三列
            tableHeader.setFixCol(2);
             
              總之這樣能忽悠成看起來像是固定了,那它也有感覺不帶勁的地方,大家如有興趣,可以在下面的鏈接中下載代碼,
          運(yùn)行其看看效果  ,效果是Scrollbar不會(huì)的最小值停留的位置不是在固定列的最后位置,隨之scrollbar的拖動(dòng),我們可以看到
          有的列會(huì)被固定的列擋住,正如前面所說,這個(gè)所謂的固定是個(gè)假象。還有一些缺點(diǎn)如有的皮膚可能算出來的結(jié)果會(huì)和原有
          的Table看起來不一致等。
               代碼我在Elie Levy的基礎(chǔ)上做了一些修改更容易使用,以及修復(fù)了一些bug,可以點(diǎn)擊這里下載:Source Download
          posted on 2009-08-12 23:22 kissjava 閱讀(3315) 評(píng)論(4)  編輯  收藏 所屬分類: swing

          評(píng)論

          # re: 固定JTable中的前幾列 2009-08-13 13:10 iSwing
          layeredpanel絕對(duì)是Swing的經(jīng)典設(shè)計(jì)之一  回復(fù)  更多評(píng)論
            

          # re: 固定JTable中的前幾列[未登錄] 2012-09-06 20:51 lovejava
          謝謝,非常好!  回復(fù)  更多評(píng)論
            

          # re: 固定JTable中的前幾列 2015-01-29 19:27 founder
          行數(shù)很多時(shí)(如2W行,30列),paintComponent會(huì)導(dǎo)致內(nèi)存溢出  回復(fù)  更多評(píng)論
            

          # re: 固定JTable中的前幾列 2015-01-29 19:35 founder
          Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
          at java.awt.image.DataBufferInt.<init>(Unknown Source)
          at java.awt.image.Raster.createPackedRaster(Unknown Source)
          at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
          at java.awt.image.BufferedImage.<init>(Unknown Source)
          at com.ykxd.wage.ui.common.FixTableManager$1.paintComponent(FixTableManager.java:59)  回復(fù)  更多評(píng)論
            

          主站蜘蛛池模板: 西充县| 如东县| 新乐市| 四子王旗| 汝南县| 石景山区| 宕昌县| 衢州市| 溆浦县| 甘孜| 巨野县| 澜沧| 专栏| 日土县| 临江市| 崇仁县| 铜梁县| 康定县| 开原市| 北宁市| 武汉市| 安福县| 兴安盟| 马关县| 恩施市| 衢州市| 南投市| 阿勒泰市| 沂南县| 余江县| 泗水县| 右玉县| 梓潼县| 余姚市| 西藏| 濉溪县| 东乡县| 张家界市| 昆山市| 明光市| 潍坊市|