zeyuphoenix

          愿我愛的人快樂,愿愛我的人快樂,為了這些,我愿意不快樂.

          JTable的表頭合并

          JTableHeader的單個表頭最復雜的操作也就是Renderer渲染和Editor編輯,然后增加事件處理和懸浮框提示,最多再加點特殊顯示效果,這和JTable單元格的操作相同,在前面的例子里都已經講過了,這里就剩下最后一個也是關于JTableHeader表頭的操作了, 表頭單元格的合并和拆分.

          JTableHeader的單個表頭可編輯時可以把它看做一個JTextField,不可操作時可以看做一個JLabel,對于表頭的合并和拆分操作來說就是把JLabelJTextField進行合并和拆分的過程.JTable表頭的合并簡單來說就是把你選定的要合并的表頭的邊線擦掉,然后調整寬度和高度,再在這幾個合并的表頭外圍畫一個新的邊線,然后設置JTableHeaderUI,刷新就可以了,JTable的單元格基本相同,唯一的區別就是JTableHeader的表頭不像單元格那個容易得到和處理,我們需要定義數據結構來存儲它.

          先看完成后的效果:

          首先是合并一行的多個單元格為一個的界面:

          再就是多行多列的合并了:

          這兩個例子,實現是一樣的只是因為數據結構不一樣.

          最后一個則是和前面單元格合并組成的例子,我們綜合前面的單元格合并,結合這次的JTableHeader合并,做一個綜合的合并的例子:

          然后看工程的目錄:

          首先的定義一個數據結構,存儲我們合并的JTableHeader.

          需要理解的是,雖然看到的是一個大的單元格,但是其實它也是幾個JTableHeader,只是去掉了其內的邊框.所以對我們的合并的JTableHeader來說,需要定義一個數據結構來存儲它們的最小分子,當然它們的Renderer也存儲了,

          /**

           *thetableheaderthathavecolumngroup.

          */

          publicclass ColumnGroup {

          看它的屬性:

              /**headerrenderer.*/

              private TableCellRenderer renderer = null;

          這個是合并的JTableHeaderRenderer,這里我們簡單化,我們就不像前面寫RendererEditor那樣分開存儲了,我們假設這個JTableHeader使用同一類的Renderer,如果你想實現不一樣的Renderer,你可以把它們定義成數組(PS:這樣效果會比較怪異,一個合并的單元格包含了幾個組件).

              /**theheadergroup.*/

              private Vector<Object> vector = null;

          這個是合并的單元格的各個實際的最小單元格存儲結構.

              /**headervalue.*/

              private String text = null;

          這個是合并后單元格顯示的文本信息

              /**thehiddenborderwidth*/

              privateintmargin = 0;

          這個是合并的單元格內部兩個最小JTableHeader的間隙,其實就是去掉線后那個Border.

          除了提供各個屬性的GetSet方法外,還提供了增加單元格add

              /**

               *addheaderorgrouptocolumngroup.

               */

              publicvoid add(Object obj) {

                 if (obj == null) {

                     return;

                 }

                 v.addElement(obj);

              }

          取得合并后的單元格的大小getSize:

              /**

               *getheadergroupsize.

               */

              public Dimension getSize(JTable table) {

          這個方法需要計算,首先是取得一個沒有合并的最小單元格的JTableHeader的大小,通過Renderer取得組件:

                 Component comp = renderer.getTableCellRendererComponent(table,

                        getHeaderValue(), false, false, -1, -1);

                 int height = comp.getPreferredSize().height;

          寬度需要計算合并的還要加上間隙:

          Enumeration<Object> enumTemp = v.elements();

                 while (enumTemp.hasMoreElements()) {

                        TableColumn aColumn = (TableColumn) obj;

                        width += aColumn.getWidth();

                        width += margin;

          最后取得這個合并的JTableHeader的大小:

                 returnnew Dimension(width, height);

          還有一個比較重要的方法是根據JTable的某一列取得它的所有的包含列,這個主要用于繪制:

              public Vector<ColumnGroup> getColumnGroups(TableColumn column,

                     Vector<ColumnGroup> group) {

          通過遞歸判斷列到底屬于那個ColumnGroup

              group.addElement(this);

                 if (v.contains(column)) {

                     return group;

                 }

          沒有找的則是Null.

          然后我們看的類是MyTableColumn,它繼承于TableColumn,主要是JTableHeader的編輯屬性和Editor.

          publicclass MyTableColumn extends TableColumn {

          主要屬性:

              /**tableheadereditor.*/

              private TableCellEditor headerEditor;

              /**isheadereditable.*/

              privatebooleanisHeaderEditable;

          方法只是簡單的GetSet設置,設置了默認編輯與否和默認的JTableHeaderEditor.

          其實也是一個簡單的類,主要是描述JTableHeaderRenderer,這個在之前我們就介紹了,大概寫下:

          publicclass MyHeaderRenderer extends JLabel implements

                  TableCellRenderer {

          實現默認的方法:

          @Override

          public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

          首先是取得JTableHeader:

                 // set some color font about header.

                 JTableHeader header = table.getTableHeader();

          設置屬性:

                 setForeground(fgColor);

                 setBackground(bgColor);

          setFont(header.getFont());

          還有設置高度,和前面的那個Renderer專題一樣:

                 setPreferredSize(new Dimension(getWidth(), headerHeight));

          最后就是兩個最重要的類,JTableHeader和它的UI的繪制:

          先看UI,我們繼承于BasicTableHeaderUI:

          /**

           *BasicTableHeaderUIimplementation.

          */

          publicclass MyGroupTableHeaderUI extends BasicTableHeaderUI {

          它重寫BasicTableHeaderUIpaint方法進行自己的UI繪制,

              /**

               *Paintarepresentationofthetableinstancethatwasset

               *ininstallUI().

               */

              @Override

              publicvoid paint(Graphics g, JComponent c) {

          首先取得舊的繪制邊框:

                 Rectangle oldClipBounds = g.getClipBounds();

                 Rectangle clipBounds = new Rectangle(oldClipBounds);

          然后根據JTable的寬度比較決定繪制的寬度,

                 int tableWidth = table.getColumnModel().getTotalColumnWidth();

                 clipBounds.width = Math.min(clipBounds.width, tableWidth);

                 g.setClip(clipBounds);

          取得行的邊框

                 ((MyTableHeader) header).setColumnMargin();

                 Dimension size = header.getSize();

          然后開始繪制行:

          先去的需要繪制的合并JTableHeader的屬性:

                 Enumeration<?> cGroups = ((MyTableHeader) header)

                            .getColumnGroups(aColumn);

          然后算出本行內那幾個列需要合并:

                 ColumnGroup cGroup = (ColumnGroup) cGroups.nextElement();

                            Rectangle groupRect = (Rectangle) h.get(cGroup);

                            if (groupRect == null) {

                               icount ++;

                               groupRect = new Rectangle(cellRect);

                               Dimension d = cGroup.getSize(header.getTable());

                               groupRect.width = d.width - icount;

                               groupRect.height = d.height;

                               h.put(cGroup, groupRect);

                            }

          最后就是繪制具體的單元格了:

                 Color c = g.getColor();

                 g.setColor(table.getGridColor());

                 g.drawRect(cellRect.x, cellRect.y, cellRect.width - 1,

                        cellRect.height - 1);

                 g.setColor(c);

                 cellRect.setBounds(cellRect.x + spacingWidth / 2, cellRect.y

                        + spacingHeight / 2, cellRect.width - spacingWidth,

                        cellRect.height - spacingHeight);

          不僅如此還需要控制編輯狀態和普通狀態有Renderer的顯示問題:

                 TableCellRenderer renderer = cGroup.getHeaderRenderer();

                Component component = renderer.getTableCellRendererComponent(header

                        .getTable(), cGroup.getHeaderValue(), false, false, -1, -1);

                 rendererPane.add(component);

                 rendererPane.paintComponent(g, component, header, cellRect.x,

                        cellRect.y, cellRect.width, cellRect.height, true);
          到這里JTableHeader合并后的顯示繪制就完成了,然后就是它的大小的顯示:

              @Override

              public Dimension getPreferredSize(JComponent c) {

                 long width = 0;

                 Enumeration<?> enumeration = header.getColumnModel().getColumns();

                 while (enumeration.hasMoreElements()) {

                     TableColumn aColumn = (TableColumn) enumeration.nextElement();

                     width = width + aColumn.getPreferredWidth();

                 }

                 return createHeaderSize(width);

              }

          JTableHeader和單元格合并不同的一點是它的事件比較復雜,我們需要重寫寫它的MouseInputHandler

          /**

             *Thisinnerclassismarked&quot;public&quot;duetoacompilerbug. * Thisclassshouldbetreatedasa&quot;protected&quot;innerclass.

              *InstantiateitonlywithinsubclassesofBasicTableUI.

              */

          privateclass MouseInputHandler extends

                     BasicTableHeaderUI.MouseInputHandler {

          它提供一個屬性,

                 /**theshowcomponent.*/

                 private Component dispatchComponent = null;

          然后在鼠標事件上加上我們自己的處理:

                 @Override

                 publicvoid mousePressed(MouseEvent e) {

          根據鼠標的位置取得我們合并后繪制的單元格:

                     Point p = e.getPoint();

                     TableColumnModel columnModel = header.getColumnModel();

                     int index = columnModel.getColumnIndexAtX(p.x);

                     if (index != -1) {

                        if (header.editCellAt(index, e)) {

                            setDispatchComponent(e);

          設置完我們的顯示后,再把事件下發:

                     MouseEvent e2 = SwingUtilities.convertMouseEvent(header, e,

                            dispatchComponent);

                     dispatchComponent.dispatchEvent(e2);

          其它的鼠標事件也一樣處理,添加我們自己的顯示.

          然后就是最重要的JTableHeader,我們重寫它:

          publicclass MyTableHeader extends JTableHeader implements CellEditorListener {

          重寫updateUI方法,設置我們自己的UI:

              @Override

              publicvoid updateUI() {

                 setUI(new MyGroupTableHeaderUI());

                 resizeAndRepaint();

                 invalidate();

              }

          同時提供setColumnMarginaddColumnGroupsetCellEditor等方法設置JTableHeader的屬性和Editor.

          然后就是設置JTableHeader編輯狀態和編輯后狀態的設置了:

          首先根據鼠標事件取得是否是需要編輯的JTableHeader.

              publicboolean editCellAt(int index, EventObject e) {

          在可編輯的JTableHeader的單元格增加事件:

          TableCellEditor editor = getCellEditor(index);

                 if (editor != null && editor.isCellEditable(e)) {

                     editorComp = prepareEditor(editor, index);

                     editorComp.setBounds(getHeaderRect(index));

                     add(editorComp);

                     editorComp.validate();

                     setCellEditor(editor);

                     setEditingColumn(index);

                     editor.addCellEditorListener(this);

                     returntrue;

                 }

          重寫editingStopped方法和editingCanceled方法.編輯狀態停止后設置顯示:

              @Override

              publicvoid editingStopped(ChangeEvent e) {

                 TableCellEditor editor = getCellEditor();

                 if (editor != null) {

                     Object value = editor.getCellEditorValue();

                     int index = getEditingColumn();

                     columnModel.getColumn(index).setHeaderValue(value);

                     removeEditor();

                 }

              }

              @Override

              publicvoid editingCanceled(ChangeEvent e) {

                 removeEditor();

              }

          最后就是使用了,雖然JTableHeader設置已經很麻煩了,但是設置顯示數據更麻煩,因此不到萬不得已不要用了,它基本不支持,基本不可能通過后期數據生成,一般用也是做成報表之類,但報表的JasperReport做的更好,所以雖然在這里寫,只是算一個思路.

          使用首先要設置JTableHeader,構造JTableHeader的數據結構:

          @Override

              protected JTableHeader createDefaultTableHeader() {

                  returnnew MyTableHeader(columnModel);

          }

          TableColumnModel cm = table.getColumnModel();

              ColumnGroup g_name = new ColumnGroup("Name");

              g_name.add(cm.getColumn(1));

          取得JTableHeader,設置合并的數據結構:

              MyTableHeader header = (MyTableHeader) table

                 .getTableHeader();

          header.addColumnGroup(g_name);

          然后設置RendererUI

              TableCellRenderer renderer = new MyHeaderRenderer();

              model.getColumn(i).setHeaderRenderer(renderer);

          table.getTableHeader().setUI(new MyGroupTableHeaderUI());

          其它的就和一個普通的JTable一樣了.

          我們可以綜合單元格合并和JTableHeader合并,這樣就可以作出復雜的JTable,如上面最后那張圖.


          posted on 2010-04-18 21:04 zeyuphoenix 閱讀(9683) 評論(0)  編輯  收藏 所屬分類: JTable的使用

          導航

          <2010年4月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          統計

          常用鏈接

          留言簿(52)

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 兴宁市| 繁昌县| 古丈县| 延津县| 和平县| 集贤县| 香港| 榆林市| 资阳市| 奈曼旗| 乌什县| 信宜市| 伊吾县| 白城市| 顺昌县| 团风县| 南部县| 吐鲁番市| 娱乐| 宝山区| 海淀区| 务川| 桐梓县| 西平县| 喜德县| 武穴市| 晋城| 汉阴县| 厦门市| 普洱| 崇州市| 家居| 西峡县| 拉萨市| 威信县| 乌鲁木齐县| 项城市| 独山县| 富平县| 民和| 龙游县|