单元格合并

2016-02-19 15:34 2 1 收藏

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

【 tulaoshi.com - 编程语言 】

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

  废话少说,转入正题吧!

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

  一、单元格合并。

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

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

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

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

  由于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的目的是打破单元格和表格的直接依赖关系,并且防止当一个单元格被修改时重画整个表。

  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);
}
}
}

来源:https://www.tulaoshi.com/n/20160219/1609938.html

延伸阅读
横向合并单元格的方法 1.表格内的数字是随便打的,在这里主要是为了给大家演示效果。表格横排从A-D,竖排1-5,把鼠标移到A1单元格一直选到D1。 2.找到我图片上所画出来的红圈,将鼠标移到上面可以看到合并及居中五个字,点击。 3.弹出一个对话框,在这里我们点击确定,在回到EXCEL文件中就能看到这四个单元格合为一体了...
标签: excel
常用的Excel单元格合并技巧   整理了一些常用的Excel单元格合并技巧,工作的时候经常会用到哦!   excel表格怎么在一个图上画多条曲线?   一般情况,我们常用的都是直接插入一条曲线的图表。但有些时候,我们在完成实验后,需要对结果进行对比分析。那么,就会需要在一个图上画多条曲线,将这多条曲线进行对...
标签: 电脑入门
合并单元格方法 ①选择好多个需要合并的单元格,然后右键,在弹出的菜单中选择合并单元格即可。 ②同样选择好需要合并的单元格,点击表格与边框工具栏上的合并单元格图标即可合并。 拆分单元格方法 ①将光标定位到需要拆分的单元格中,然后右键选择拆分单元格在弹出的拆分单元格中输入要拆分的行数或列数确定即可。 一下是Word文档中...
标签: 电脑入门
笔者所在单位今年实行了全国计算机应用等级考试,根据晋升职务级别的不同,考生可选择2至4个模块应试。每个考生具有唯一的档案号,同一次考试合格1个及以上模块者,取得1个合格证书,合格证标注了考生合格的模块。 假如考生刘XX合格1科,有1科的合格证,考生王XX合格了3科,也同样取得了一个合格证书,合格证显示了合格的3个模块(图1)。为方便...
Excel怎么合并单元格 首先打开需要修改的excel表格。 再重现选择一个新的空白内容的单元格,然后在单元格里面输入字符”=“号。 输入等于号之后,然后在使用鼠标点击先选择班级列的第一个单元格,然后在空白单元格里面就会显示出”=B2“ 然后在”=B2“后面再输入符号”&“,也就是使用快捷键shift+数字7键。 最后就是在使用鼠标点击选...

经验教程

239

收藏

5
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部