单元格合并

gjmptw012

gjmptw012

2016-02-19 15:34

图老师小编精心整理的单元格合并希望大家喜欢,觉得好的亲们记得收藏起来哦!您的支持就是小编更新的动力~

  最近在为学校做一个工资发放软件,要用JAVA SWING制作相应的工资表,这就涉及到多行表头及表格的合并。我足足花了3天的时间去找相关的资料,然而基本上都是E文的,而且所以例子的代码都没有注解,所以我决定将我所收集的资料整理公布出来,希望能给大家一些帮助。由于本人只是一名小学教师,水平有限,如果有什么不正确的地方,请多包涵。

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

  废话少说,转入正题吧!

  一、单元格合并。

  Jtable没有提供现成的合并单元格的方法,但是使用其所提供的方法仍然能做到这一点,只是复杂了一些。为了合并单元格,我们可以使用Jtable的三个方法:getCellRect(),columnAtPoint(),and rowAtPoint()。第一个方法返回一个单元格的边界(Rectangle类),第二、三个方法分别返回屏幕指定位置的列和行。为了实现单元格合并,我们需要重载(overwrite)这三个方法。

  另外,网上的资料提到,大部分的swing components 并不是直接由paint()方法来渲染(render),而是使用ComponentUI对象来完成渲染的。所以我们需要找出渲染Jtable的ComponentUI对象,并且修改它以达到我们的目的。

  由于要实现多行多列单元格合并需要多个类相互协作,直接写出来的话可能比较复杂,所以我先讲一下跨列的单元格合并的方法,然后再提供一个完整的例子。

  由于swing里没有可记录单元格合并情况的数据模型,所以我们需要一个新的类,它要包涵一个方法来取得单元格的所跨越的列数。另外,为了使用Jtable画(paint)起来更容易些,我们需要一个方法来确定指定单元格是否被其它单元格所覆盖,被哪个单元格覆盖。我们将这两种方法都集成在接口Cmap里:

  

package com.neuri.ctable;
public interface CMap
{
/**
* @参数row:指定单元格所在的逻辑行
* @参数column:指定单元格所在的逻辑列
* @返回指定单元格所跨越的列数
*/
int span (int row, int column);
/**
* @参数row:指定单元格所在的逻辑行
* @参数column:指定单元格所在的逻辑列
* @返回覆盖指定单元格的可视单元格的列值,如果单元格本来就是可视的话,返回自身的列值
*/
int visibleCell(int row, int column);
}

  现在我们开始重载上面提及过的三个方法。由于我们目前只关注于跨列单元格的合并,方法rowAtPoint()就不用重载了。然而,方法columnAtPoint()就必须重载了,我们会使用Jtable自身的方法来取得指定单元格的列值,并且计算出覆盖该单元格的可视单元格列值(如果该单元格本来就是可视的,则返回自身列值)。在单元格合并后,在合并区域内只有一个跨越多列的可视单元格,其它被覆盖的单元格则不会再被渲染。当使用getCellRect()方法取得被覆盖的单元格的大小时,都返回覆盖该单元格的可视单元格的大小。

  

package com.neuri.ctable;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
public class CTable extends JTable {
public CMap map;
public CTable(CMap cmp, TableModel tbl) {
super(tbl);
map=cmp;
setUI(new CTUI());//设置Jtable的渲染UI
}
public Rectangle getCellRect(int row, int column, boolean includeSpacing){
// 该方法是Jtable构建时所必须的
if (map==null) return super.getCellRect(row,column, includeSpacing);
// 指定单元格的可视单元格列值
int sk=map.visibleCell(row,column);
Rectangle r1=super.getCellRect(row,sk,includeSpacing);
// 如果指定单元格列宽不为1,累计出跨列单元格的宽度
if (map.span(row,sk)!=1)
for (int i=1; imap.span(row,sk); i++){
r1.width+=getColumnModel().getColumn(sk+i).getWidth();
}
return r1;
}
public int columnAtPoint(Point p) {
int x=super.columnAtPoint(p);
// 当指定位置不在Table内时,返回-1
if (x0) return x;
int y=super.rowAtPoint(p);
//获取指定位置可视单元格的列值
return map.visibleCell(y,x);
}
}

  现在剩下的就只有创建一个表格的渲染对象了。不同的用户接口管理器(user interface managers)使用不同的类来画表格。我们会继承子类 javax.swing.plaf.basic.BasicTableUI,并且重载其方法 paintComponent。

  在组件(component)画在屏幕上之前,它已经被初始化和设定好了,所以我们能使用其内部的属性 table 和 rendererPane。属性 table 就是将要被画在屏幕的表格,rendererPane 是用于将单元格画在表格中的特殊对象。使用RendererPane的目的是打破单元格和表格的直接依赖关系,并且防止当一个单元格被修改时重画整个表。

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

  BasicTableUI的方法getClipBounds是用于找出表格的哪一部分将会被画出来,所以我们首先要知道那些行是可视的,我们可以使用Jtable 的rowAtPoint方法。我们可以使用Rectangle类的intersects方法来确定这些行中的所以单元格是否将会被画在屏幕上。在我们画任何一个单元格前,我们必须检查一下当前单元格是否可视,如果该单元格是被其它单元格所覆盖的,就将覆盖它的单元格画出来。

  根据单元格是否正在被编辑,单元格将会被方法getCellEditor或getCellRenderer所返回的对象画出来。如果你查看一下BasicTableUI的源代码,你就会发现所以单元格会先被BasicTableUI调用table.prepareRenderer画(drawn)出来,然后再被BasicTableUI调用rendererPane.paintComponent来渲染(paint)。我们会采用同样的方法。

  

package com.neuri.ctable;
import javax.swing.table.*;
import javax.swing.plaf.basic.*;
import java.awt.*;
import javax.swing.*;
public class CTUI extends BasicTableUI
{
public void paint(Graphics g, JComponent c) {
Rectangle r=g.getClipBounds();
int firstRow=table.rowAtPoint(new Point(0,r.y));
int lastRow=table.rowAtPoint(new Point(0,r.y+r.height));
// -1 is a flag that the ending point is outside the table
if (lastRow0)
lastRow=table.getRowCount()-1;
for (int i=firstRow; i=lastRow; i++)
paintRow(i,g);
}
private void paintRow(int row, Graphics g)
{
Rectangle r=g.getClipBounds();
for (int i=0; itable.getColumnCount();i++)
{
Rectangle r1=table.getCellRect(row,i,true);
if (r1.intersects(r)) // at least a part is visible
{
int sk=((CTable)table).map.visibleCell(red,i);
paintCell(row,sk,g,r1);
// increment the column counter
i+=((CTable)table).map.span(row,sk)-1;
}
}
}
private void paintCell(int row, int column, Graphics g,Rectangle area)
{
int verticalMargin = table.getRowMargin();
int horizontalMargin = table.getColumnModel().getColumnMargin();
Color c = g.getColor();
g.setColor(table.getGridColor());
g.drawRect(area.x,area.y,area.width-1,area.height-1);
g.setColor(c);
area.setBounds(area.x + horizontalMargin/2,
area.y + verticalMargin/2,
area.width - horizontalMargin,
area.height - verticalMargin);
if (table.isEditing() && table.getEditingRow()==row &&
table.getEditingColumn()==column)
{
Component component = table.getEditorComponent();
component.setBounds(area);
component.validate();
}
else
{
TableCellRenderer renderer = table.getCellRenderer(row, column);
Component component = table.prepareRenderer(renderer, row, column);
if (component.getParent() == null)
rendererPane.add(component);
rendererPane.paintComponent(g, component, table, area.x, area.y,
area.width, area.height, true);
}
}
}

展开更多 50%)
分享

猜你喜欢

单元格合并

编程语言 网络编程
单元格合并

excel合并单元格在哪设置?exl合并单元格快捷键

excel
excel合并单元格在哪设置?exl合并单元格快捷键

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

巧妙提取合并单元格及对应单元格数据

电脑入门
巧妙提取合并单元格及对应单元格数据

excel合并单元格怎么操作以及合并单元格快捷键

电脑入门
excel合并单元格怎么操作以及合并单元格快捷键

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

excel怎么合并单元格

excel
excel怎么合并单元格

excel中怎么合并单元格

excel
excel中怎么合并单元格

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

连接SQLserver数据库注意事项

连接SQLserver数据库注意事项

全面为系统布设安全防线,让Windows 7更加安全

全面为系统布设安全防线,让Windows 7更加安全
下拉加载更多内容 ↓