JTable的ToolTip提示和其它的组件提示是一样的,因为它们都是继承于Jcomponent,当我们需要为我们的单元格实现ToolTip的时候,只需要复写它的getToolTipText方法就可以了,
看看Sun官方的例子:
//Implement table cell tool tips.
@Override
public String getToolTipText(MouseEvent e) {
取得鼠标的行和列:
java.awt.Point p = e.getPoint();
int rowIndex = rowAtPoint(p);
int colIndex = columnAtPoint(p);
int ealColumnIndex = convertColumnIndexToModel(colIndex);
设置你需要显示的ToolTip,然后返回
tip = ……;
returntip;
同样的JTableHeader也是如此:
protected JTableHeader createDefaultTableHeader() {
returnnew JTableHeader(columnModel) {
这样不用其它设置,JTable的基本ToolTip就实现了,它虽然比较简单,但是最大的好处是不用自己考虑定位和显示的问题,很多时候也就可以了.
关于JTable的简单ToolTip提示就算是完成了,当我们只是简单的提示的时候,只需要复写JTable的getToolTipText和setToolTipText方法就可以了,上个例子就是这样;但是当我们需要使我们的ToolTip提示不像Sun提供的那么单调,我们就需要自己来实现了.
这时候的重点已经不在JTable上了,而在于ToolTip上面,我们可以把我们需要呈现的ToolTip实现为一个JPanel,这样就可以在它的上面放置各种组件了,设置放图标都可以,这个时候就需要实现这个ToolTip的UI和Manager,这方面有很多开源的实现,以后有时间的话开个专题专门来介绍ToolTip的,这里不写了.
对于已经实现好的我们自己的ToolTip,我们需要做的是把它注册到我们的JTable上面,再根据鼠标的位置显示它,如下图所示,它可以有Title,可以有图片,可以有正文,甚至可以再加别的组件.如下图所示:
我们需要的是增加监听:
addMouseListener(this)
根据监听的状态处理ToolTip:
publicvoid mouseExited(MouseEvent event) {
隐藏
publicvoid mousePressed(MouseEvent event) {
显示
publicvoid mouseMoved(MouseEvent event) {
判断状态,显示或者隐藏.
然后是判断位置:
// display directly below or above JTable band
location.x = screenLocation.x;
location.y = screenLocation.y + mouseEvent.getY() + 22;
location.x = screenLocation.x +mouseEvent.getX();
f ((location.y + size.height) > (sBounds.y + sBounds.height)) {
location.y = screenLocation.y - size.height;
最后是取得鼠标所在单元格的值传入显示:
Point p = mouseEvent.getPoint();
int row = rowAtPoint(p);
int col = columnAtPoint(p);
if (row == -1 || col == -1) {
returnnull;
}
Object data = getValueAt(row, col);
当然此时你可以对data做变换,从而显示需要的值.
使用很简单,注册就可以了.
setActionRichTooltip(new RichTooltip());
然后是另外一种ToolTip的效果,这个是一个开源的实现,只抓张图看看就算了,和前面的实现基本类似,还比那个简单,也是UI,Timer以及位置计算.如下图,代码在open就有:
ToolTip到这儿就算完了,但是实际使用中可能有这个问题,如下图:
这是因为我们经过设置Renderer渲染的单元格显示值和实际值不一样了.但我们很多时候需要看到的其实不是它的真实值,而是渲染后的值,可以通过渲染的实现类把它取回来:
先取得渲染类:
TableCellRenderer cellRenderer = table.getColumnModel().getColumn(column).getCellRenderer();
再去的渲染的控件:
Component component = cellRenderer.getTableCellRendererComponent(table,
table.getValueAt(row, column), false, false, row, column);
这个时候不知道这个控件是否有getText方法,通过反射判断,没有则设置为””
String text = "";
if (component != null) {
for (Method method : component.getClass().getMethods()) {
if (method.getName().equals("getText")) {
text = method.invoke(component).toString();
最后效果如图:
到此为止,所有关于JTable的ToolTip提示就完成了,当然我实现的都是一些基本的效果,比较复杂的效果,则需要你自己去绘制和实现ToolTip了,说句简单的,技术完成了,以后就是玩色彩和审美了,做程序也就这样了,很多时候后者重要.
JTableHeader的单个表头最复杂的操作也就是Renderer渲染和Editor编辑,然后增加事件处理和悬浮框提示,最多再加点特殊显示效果,这和JTable单元格的操作相同,在前面的例子里都已经讲过了,这里就剩下最后一个也是关于JTableHeader表头的操作了, 表头单元格的合并和拆分.
JTableHeader的单个表头可编辑时可以把它看做一个JTextField,不可操作时可以看做一个JLabel,对于表头的合并和拆分操作来说就是把JLabel或JTextField进行合并和拆分的过程.JTable表头的合并简单来说就是把你选定的要合并的表头的边线擦掉,然后调整宽度和高度,再在这几个合并的表头外围画一个新的边线,然后设置JTableHeader的UI,刷新就可以了,和JTable的单元格基本相同,唯一的区别就是JTableHeader的表头不像单元格那个容易得到和处理,我们需要定义数据结构来存储它.
先看完成后的效果:
首先是合并一行的多个单元格为一个的界面:
再就是多行多列的合并了:
这两个例子,实现是一样的只是因为数据结构不一样.
最后一个则是和前面单元格合并组成的例子,我们综合前面的单元格合并,结合这次的JTableHeader合并,做一个综合的合并的例子:
然后看工程的目录:
首先的定义一个数据结构,存储我们合并的JTableHeader.
需要理解的是,虽然看到的是一个大的单元格,但是其实它也是几个JTableHeader,只是去掉了其内的边框.所以对我们的合并的JTableHeader来说,需要定义一个数据结构来存储它们的最小分子,当然它们的Renderer也存储了,
/**
*thetableheaderthathavecolumngroup.
*/
publicclass ColumnGroup {
看它的属性:
/**headerrenderer.*/
private TableCellRenderer renderer = null;
这个是合并的JTableHeader的Renderer,这里我们简单化,我们就不像前面写Renderer和Editor那样分开存储了,我们假设这个JTableHeader使用同一类的Renderer,如果你想实现不一样的Renderer,你可以把它们定义成数组(PS:这样效果会比较怪异,一个合并的单元格包含了几个组件).
/**theheadergroup.*/
private Vector vector = null;这个是合并的单元格的各个实际的最小单元格存储结构. /**headervalue.*/ private String text = null;这个是合并后单元格显示的文本信息 /**thehiddenborderwidth*/ privateintmargin = 0;这个是合并的单元格内部两个最小JTableHeader的间隙,其实就是去掉线后那个Border.除了提供各个属性的Get和Set方法外,还提供了增加单元格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 enumTemp = v.elements(); while (enumTemp.hasMoreElements()) { TableColumn aColumn = (TableColumn) obj; width += aColumn.getWidth(); width += margin;最后取得这个合并的JTableHeader的大小: returnnew Dimension(width, height);还有一个比较重要的方法是根据JTable的某一列取得它的所有的包含列,这个主要用于绘制: public Vector getColumnGroups(TableColumn column, Vector 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;方法只是简单的Get和Set设置,设置了默认编辑与否和默认的JTableHeader的Editor.其实也是一个简单的类,主要是描述JTableHeader的Renderer的,这个在之前我们就介绍了,大概写下:publicclass MyHeaderRenderer extends JLabel implements TableCellRenderer {实现默认的方法:@Overridepublic 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 {它重写BasicTableHeaderUI的paint方法进行自己的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"public"duetoacompilerbug. *Thisclassshouldbetreatedasa"protected"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(); }同时提供setColumnMargin、addColumnGroup、setCellEditor等方法设置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);然后设置Renderer和UI: TableCellRenderer renderer = new MyHeaderRenderer(); model.getColumn(i).setHeaderRenderer(renderer);table.getTableHeader().setUI(new MyGroupTableHeaderUI());其它的就和一个普通的JTable一样了.我们可以综合单元格合并和JTableHeader合并,这样就可以作出复杂的JTable了,如上面最后那张图. source: http://www.blogjava.net/zeyuphoenix/archive/2010/04/18/318690.html 較新的文章 較舊的文章 首頁 訂閱: 文章 (Atom) 訂閱 發表文章 Atom 發表文章 所有留言 Atom 所有留言 我的網誌清單 Econ-StandUp (澳門)炒家、用家 樓市拉鋸戰 13 年前 IT-Standup HTML5 视频这滩浑水(1)基本概念 14 年前 En-StandUp Season's greetings 14 年前 我不能沈默 向阿sir揮手+我的恩人蔡蔡子 15 年前 標籤 Adobe Flex (4) ASP.NET (1) C# (7) css (1) Database (38) Design (2) Hibernate (2) IOS (8) Java (48) JS (5) Linux (2) MSSQL (4) oracle (1) report (2) System Design (1) 網誌存檔 ► 2011 (25) ► 11月 (4) ► 10月 (6) ► 8月 (1) ► 7月 (2) ► 6月 (2) ► 5月 (1) ► 4月 (2) ► 2月 (3) ► 1月 (4) ▼ 2010 (41) ► 12月 (9) ► 7月 (3) ► 6月 (7) ► 5月 (2) ▼ 4月 (2) JTable 表格(懸浮框提示) JTable的Header合併 ► 3月 (7) ► 2月 (4) ► 1月 (7) ► 2009 (44) ► 12月 (1) ► 11月 (5) ► 10月 (1) ► 9月 (2) ► 8月 (3) ► 7月 (4) ► 6月 (5) ► 5月 (3) ► 4月 (3) ► 3月 (12) ► 2月 (1) ► 1月 (4) ► 2008 (17) ► 12月 (5) ► 11月 (3) ► 10月 (9) 關於我自己 StandUp 澳門人 檢視我的完整簡介
这个是合并的单元格的各个实际的最小单元格存储结构.
/**headervalue.*/
private String text = null;
这个是合并后单元格显示的文本信息
/**thehiddenborderwidth*/
privateintmargin = 0;
这个是合并的单元格内部两个最小JTableHeader的间隙,其实就是去掉线后那个Border.
除了提供各个属性的Get和Set方法外,还提供了增加单元格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 enumTemp = v.elements(); while (enumTemp.hasMoreElements()) { TableColumn aColumn = (TableColumn) obj; width += aColumn.getWidth(); width += margin;最后取得这个合并的JTableHeader的大小: returnnew Dimension(width, height);还有一个比较重要的方法是根据JTable的某一列取得它的所有的包含列,这个主要用于绘制: public Vector getColumnGroups(TableColumn column, Vector 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;方法只是简单的Get和Set设置,设置了默认编辑与否和默认的JTableHeader的Editor.其实也是一个简单的类,主要是描述JTableHeader的Renderer的,这个在之前我们就介绍了,大概写下:publicclass MyHeaderRenderer extends JLabel implements TableCellRenderer {实现默认的方法:@Overridepublic 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 {它重写BasicTableHeaderUI的paint方法进行自己的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"public"duetoacompilerbug. *Thisclassshouldbetreatedasa"protected"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(); }同时提供setColumnMargin、addColumnGroup、setCellEditor等方法设置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);然后设置Renderer和UI: TableCellRenderer renderer = new MyHeaderRenderer(); model.getColumn(i).setHeaderRenderer(renderer);table.getTableHeader().setUI(new MyGroupTableHeaderUI());其它的就和一个普通的JTable一样了.我们可以综合单元格合并和JTableHeader合并,这样就可以作出复杂的JTable了,如上面最后那张图. source: http://www.blogjava.net/zeyuphoenix/archive/2010/04/18/318690.html 較新的文章 較舊的文章 首頁 訂閱: 文章 (Atom) 訂閱 發表文章 Atom 發表文章 所有留言 Atom 所有留言 我的網誌清單 Econ-StandUp (澳門)炒家、用家 樓市拉鋸戰 13 年前 IT-Standup HTML5 视频这滩浑水(1)基本概念 14 年前 En-StandUp Season's greetings 14 年前 我不能沈默 向阿sir揮手+我的恩人蔡蔡子 15 年前 標籤 Adobe Flex (4) ASP.NET (1) C# (7) css (1) Database (38) Design (2) Hibernate (2) IOS (8) Java (48) JS (5) Linux (2) MSSQL (4) oracle (1) report (2) System Design (1) 網誌存檔 ► 2011 (25) ► 11月 (4) ► 10月 (6) ► 8月 (1) ► 7月 (2) ► 6月 (2) ► 5月 (1) ► 4月 (2) ► 2月 (3) ► 1月 (4) ▼ 2010 (41) ► 12月 (9) ► 7月 (3) ► 6月 (7) ► 5月 (2) ▼ 4月 (2) JTable 表格(懸浮框提示) JTable的Header合併 ► 3月 (7) ► 2月 (4) ► 1月 (7) ► 2009 (44) ► 12月 (1) ► 11月 (5) ► 10月 (1) ► 9月 (2) ► 8月 (3) ► 7月 (4) ► 6月 (5) ► 5月 (3) ► 4月 (3) ► 3月 (12) ► 2月 (1) ► 1月 (4) ► 2008 (17) ► 12月 (5) ► 11月 (3) ► 10月 (9) 關於我自己 StandUp 澳門人 檢視我的完整簡介
while (enumTemp.hasMoreElements()) {
TableColumn aColumn = (TableColumn) obj;
width += aColumn.getWidth();
width += margin;
最后取得这个合并的JTableHeader的大小:
returnnew Dimension(width, height);
还有一个比较重要的方法是根据JTable的某一列取得它的所有的包含列,这个主要用于绘制:
public Vector getColumnGroups(TableColumn column,
Vector 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;
方法只是简单的Get和Set设置,设置了默认编辑与否和默认的JTableHeader的Editor.
其实也是一个简单的类,主要是描述JTableHeader的Renderer的,这个在之前我们就介绍了,大概写下:
publicclass MyHeaderRenderer extends JLabel implements
TableCellRenderer {
实现默认的方法:
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 {
它重写BasicTableHeaderUI的paint方法进行自己的UI绘制,
*Paintarepresentationofthetableinstancethatwasset
*ininstallUI().
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合并后的显示绘制就完成了,然后就是它的大小的显示:
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"public"duetoacompilerbug. *Thisclassshouldbetreatedasa"protected"innerclass.
*InstantiateitonlywithinsubclassesofBasicTableUI.
privateclass MouseInputHandler extends
BasicTableHeaderUI.MouseInputHandler {
它提供一个属性,
/**theshowcomponent.*/
private Component dispatchComponent = null;
然后在鼠标事件上加上我们自己的处理:
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:
publicvoid updateUI() {
setUI(new MyGroupTableHeaderUI());
resizeAndRepaint();
invalidate();
同时提供setColumnMargin、addColumnGroup、setCellEditor等方法设置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方法.编辑状态停止后设置显示:
publicvoid editingStopped(ChangeEvent e) {
TableCellEditor editor = getCellEditor();
if (editor != null) {
Object value = editor.getCellEditorValue();
int index = getEditingColumn();
columnModel.getColumn(index).setHeaderValue(value);
removeEditor();
publicvoid editingCanceled(ChangeEvent e) {
最后就是使用了,虽然JTableHeader设置已经很麻烦了,但是设置显示数据更麻烦,因此不到万不得已不要用了,它基本不支持,基本不可能通过后期数据生成,一般用也是做成报表之类,但报表的JasperReport做的更好,所以虽然在这里写,只是算一个思路.
使用首先要设置JTableHeader,构造JTableHeader的数据结构:
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);
然后设置Renderer和UI:
TableCellRenderer renderer = new MyHeaderRenderer();
model.getColumn(i).setHeaderRenderer(renderer);
table.getTableHeader().setUI(new MyGroupTableHeaderUI());
其它的就和一个普通的JTable一样了.
我们可以综合单元格合并和JTableHeader合并,这样就可以作出复杂的JTable了,如上面最后那张图.
source: http://www.blogjava.net/zeyuphoenix/archive/2010/04/18/318690.html