<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="ProgId" content="Word.Document">
<meta name="Generator" content="Microsoft Word 12">
<meta name="Originator" content="Microsoft Word 12">
<link rel="File-List" href="file:///C:%5CDOCUME%7E1%5Cphoenix%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml">
<link rel="Edit-Time-Data" href="file:///C:%5CDOCUME%7E1%5Cphoenix%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_editdata.mso">
<!--[if !mso]>
<style>
v":* {behavior:url(#default#VML);}
o":* {behavior:url(#default#VML);}
w":* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style>
<![endif]--><link rel="themeData" href="file:///C:%5CDOCUME%7E1%5Cphoenix%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx">
<link rel="colorSchemeMapping" href="file:///C:%5CDOCUME%7E1%5Cphoenix%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml">
<!--[if gte mso 9]><xml>
Normal
0
false
7.8 磅
0
2
false
false
false
EN-US
ZH-CN
X-NONE
</xml><![endif]--><!--[if gte mso 9]><![endif]--><style>
<!--
/* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:0 0 0 0 0 0 0 0 0 0;
mso-font-alt:"Times New Roman";}
@font-face
{font-family:""@宋体";
panose-1:2 1 6 0 3 1 1 1 1 1;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{
mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
font-size:10.5pt;
font-family:"Calibri","serif";
mso-bidi-font-family:"Times New Roman";}
.MsoChpDefault
{
mso-bidi-font-family:"Times New Roman";}
/* Page Definitions */
@page
{}
@page Section1
{size:595.3pt 841.9pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
layout-grid:15.6pt;}
div.Section1
{page:Section1;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{
mso-style-parent:"";
font-size:10.5pt;
font-family:"Calibri","serif";}
</style>
<![endif]-->
JTable的单个单元格最复杂的操作也就是Renderer渲染和Editor编辑,然后增加事件处理和悬浮框提示,最多再加点特殊显示效果,在前面的例子里都已经讲过了,这里就剩下最后一个关于单元格的操作了,单元格的合并和拆分.
JTable的单元格可编辑时可以把它看做一个JTextField,不可操作时可以看做一个JLabel,对于单元格的合并和拆分操作来说就是把JLabel或JTextField进行合并和拆分的过程.JTable单元格的合并简单来说就是把你选定的要合并的单元格的边线擦掉,然后调整宽度和高度,再在这几个合并的单元格外围画一个新的边线,然后设置JTable的UI,刷新就可以了.
先看完成后的界面:
<!--[if gte vml 1]>
<![endif]-->
然后是工程的目录结构:
<!--[if gte vml 1]>
<![endif]-->
其中CustomCell就合并后的Cell,它储存了当前那几个Cell被合并,以及合并后的宽和高用于计算.CustomCellRenderer就是合并后的Cell的Renderer了,它用于合并后Cell内容的显示,CustomCellUI则是合并Cell的UI了,这是主要的合并Cell用到的类,剩下的两个接口ICellAttribute和ICellSpan则是合并Cell的接口,里面定义Cell增删和更新的方法,而SpanCellTablePanel类是因为做成的合并单元格JTable很难使用,提供的辅助类,传入数据则把JTable创建出来,并根据数据实现了合并单元格.
先看接口IcellSpan,它提供设置单元格是否可见,单元格的合并和拆分方法,单元格拆分的Index方法需要实现类完成.
/**
*theinterfacethataboutcellspan.
*/
publicinterface ICellSpan {
方法如下:
/**
*getcellSpan.
*/
publicint[] getSpan(int row, int column);
/**
*setcellspan.
*/
publicvoid setSpan(int[] span, int row, int column);
这两个方法是提供JTable真正的行和列和合并后的行和列的对应关系.
/**
*iscellvisible.
*/
publicboolean isVisible(int row, int column);
/**
*wherecombine.
*/
publicvoid combine(int[] rows, int[] columns);
/**
*wheresplit.
*/
publicvoid split(int row, int column);
提供当前Jtable那几个行和列合并;以及合并后的某一行和列的拆分.
然后是IcellAttribute接口,它提供增加行、增加列、以及插入行、取得和设置大小(不是物理大小,是相对于JTable的大小)的方法:
/**
*theinterfacethataboutcellattribute.
*/
publicinterface ICellAttribute {
再看方法:
/**
*addcolumntocell.
*/
publicvoid addColumn();
/**
*addrowtocell.
*/
publicvoid addRow();
/**
*insertrowtocell
*/
publicvoid insertRow(int row);
这三个方法提供行和列的增加操作
/**
*getcellsize.
*/
public Dimension getSize();
/**
*setcellsize.
*/
publicvoid setSize(Dimension
size);
这两个方法提供单元格大小的设置和取得.
再看实现这两个接口的类CustomCell,它是合并后的单元格的信息保存类:
/**
*setcellAttributespanandsoon.
*/
publicclass CustomCell implements ICellAttribute, ICellSpan {
有三个属性:
/**cellwidth.*/
privateintrowSize = 0;
/**cellheight.*/
privateintcolumnSize = 0;
/**cellspans.*/
privateint[][][] span = null;
分别保存合并后单元格的宽度和高度(这个宽和高的意思是在两个方向上有几个JTable的单元格大小),以及合并的单元格是由原本JTable的那几个行和列组成的.
先是构造函数:
/**
*setcellattribute.
*/
public CustomCell() {
this(1, 1);
}
setSize(new Dimension(columnSize, rowSize));
在setSize方法里,初始化属性:
@Override
publicvoid setSize(Dimension size) {
columnSize = size.width;
rowSize = size.height;
span = newint[rowSize][columnSize][2];
initValue();
}
然后是初始化方法,
/**
*setcellinit.
*/
privatevoid initValue() {
for (int i = 0; i < span.length; i++) {
for (int j = 0; j < span[i].length; j++) {
span[i][j][ICellSpan.COLUMN] = 1;
span[i][j][ICellSpan.ROW] = 1;
}
}
}
然后就是实现接口的方法,
@Override
publicint[] getSpan(int row, int column) {
返回span数组对应的行和列:
returnspan[row][column];
@Override
publicvoid setSpan(int[] span, int row, int column) {
设置span数组对应的行和列:
this.span[row][column] = span;
@Override
publicvoid addColumn() {
@Override
publicvoid addRow() {
@Override
publicvoid insertRow(int row) {
这三个方法很类似,都是先取得旧有的span:
int[][][] oldSpan = span;
int numRows = oldSpan.length;
int numColumns = oldSpan[0].length;
然后创建新的:
span = newint[numRows +
1][numColumns][2];
System.arraycopy(oldSpan, 0, span, 0, numRows);
最后赋予新的值:
for (int i = 0; i < numColumns; i++) {
span[numRows][i][ICellSpan.COLUMN] = 1;
span[numRows][i][ICellSpan.ROW] = 1;
}
最后是比较重要的合并和拆分方法,它根据传入的需要合并和拆分的行和列计算,得出数组新的值:
@Override
publicvoid combine(int[] rows, int[] columns) {
先取得开始比较的起点:
int rowSpan = rows.length;
int columnSpan = columns.length;
int startRow = rows[0];
int startColumn = columns[0];
对于需要修改的值比较并赋予新的:
for (int i = 0, ii = 0; i < rowSpan; i++, ii--) {
for (int j = 0, jj = 0; j < columnSpan; j++, jj--)
{
span[startRow + i][startColumn + j][ICellSpan.COLUMN] = jj;
span[startRow + i][startColumn + j][ICellSpan.ROW] = ii;
}
}
最后设置新的数组值:
span[startRow][startColumn][ICellSpan.COLUMN] = columnSpan;
span[startRow][startColumn][ICellSpan.ROW] = rowSpan;
这样新的span就形成了,当画面repaint时,UI会根据新的span的值决定那个单元格的Border需要绘制,那个需要擦去,这样就单元格方面完成了拆分,至于持分后内容的显示则是通过Rebderer控制的.
这里我们的Rebderer类十分简单,我们就不实现任何效果了,只确定合并后的显示问题:
publicclass CustomCellRenderer extends JLabel implements
TableCellRenderer {
它的接口实现方法
@Override
public Component
getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
除了定义颜色背景色的基本属性外,最主要的是设置显示:
setText((value == null) ? "" :
value.toString());
然后就是很重要的CustomCellUI类了,它根据前面CustomCell类的span来绘制合并单元格后的显示问题:
/**
*BasicTableUIimplementation,paintthespantableui.
*/
publicclass CustomCellUI extends BasicTableUI {
它重写BasicTableUI的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);
取得行的边框
Rectangle
rowRect = new Rectangle(0,
0, tableWidth, table
.getRowHeight() + table.getRowMargin());
rowRect.y = firstIndex * rowRect.height;
然后开始绘制行:
先去的需要绘制的合并单元格的属性:
CustomTableModel tableModel = (CustomTableModel) table
.getModel();
ICellSpan cellAtt = (ICellSpan) tableModel.getCellAttribute();
然后算出本行内那几个列需要合并:
cellRow = row
+ cellAtt.getSpan(row,
column)[ICellSpan.ROW];
cellColumn = column
+ cellAtt.getSpan(row, column)[ICellSpan.COLUMN];
最后就是绘制具体的单元格了:
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的显示问题:
Component component = table.getEditorComponent();
component.setBounds(cellRect);
component.validate();
//renderer
rendererPane.paintComponent(g, component, table, cellRect.x,
cellRect.y, cellRect.width, cellRect.height, true);
到这里单元格合并后的显示就完成了,还有就是JTable的显示和TableModel的数据设置,先看TableModel:
我们继承DefaultTableModel类,
publicclass CustomTableModel extends DefaultTableModel {
它的构造函数和DefaultTableModel一样,最终都会转换为Vector,
public CustomTableModel(Vector<Vector<?>> data,
Vector<?> columnNames) {
addDataVector(data, columnNames);
}
在它的addDataVector方法里,不但要给TableModel的数据集赋:
dataVector = new Vector<Vector<?>>(0);
setColumnIdentifiers(columnNames);
dataVector = newData;
还要根据行和列做成我们的CustomCell:
cellAtt = new CustomCell
(dataVector.size(), columnIdentifiers
.size());
同样的TableModel的addColumn、addRow、insertRow方法,我们都需要复写修改,加上我们自己Cell的增加方法:
cellAtt.addRow();
cellAtt.insertRow(row);
cellAtt.addColumn();
最后我们修改的是JTable类,我们继承它,设置它的UI和鼠标行和列的响应:
publicclass CustomTabel extends JTable {
构造函数和JTable相同,只不过我们需要设置自己的UI,
setUI(new CustomCellUI());
然后复写rowAtPoint和columnAtPoint得到鼠标点击时我们真正的行列:
@Override
publicint rowAtPoint(Point point) {
首先是取得当前所在行列和合并单元格的值:
int row = point.y / (rowHeight + rowMargin);
int column = getColumnModel().getColumnIndexAtX(point.x);
ICellSpan cellAtt = (ICellSpan) ((CustomTableModel)
getModel())
.getCellAttribute();
然后取得实际的:
retValue[ICellSpan.COLUMN] = column
+ cellAtt.getSpan(row,
column)[ICellSpan.COLUMN];
retValue[ICellSpan.ROW] = row
+ cellAtt.getSpan(row,
column)[ICellSpan.ROW];
最后需要重写的是方法,它保证了合并单元格后的行和列和Header的对应,不会因为去掉了单元格的Boder线使不能对齐:
@Override
public Rectangle
getCellRect(int row, int column, boolean includeSpacing) {
和UI里的paint方法一样就是计算补足没有Border的间隙,一般每合并一个加上1就可以了.
到这里为止,合并单元格的JTable就算完成了,但是比较麻烦的是因为它并不知道我们合并那个,不会主动给我们合并,需要我们自己去调用combine方法,比较复杂,而实际使用的时候,我们想告诉数据是什么样子的希望JTable自己合并,因此写了一个SpanCellTablePanel类,只需传入数据就可以自己合并了.
publicclass SpanCellTablePanel extends JPanel {
继承Jpanel确保我们可以和一个普通的JPanel一样使用它.
它初始化TableModel并构建了JTable:
CustomTableModel model = new CustomTableModel(datas, convertToVector(columnTitle));
CustomTabel table = new CustomTabel(model)
提供了我们取得JTable的方法:
public JTable getTable() {
returntable;
}
提供一个我们给定数据转换为合并的数据的方法:
privateint[][] combineSpanData(Vector<Vector<?>> datas)
{
然后根据数据合并单元格显示出来:
for (int i = 0; i < columns.length; i++) {
for (int t = 0; t < spanArray.length; t++) {
((ICellSpan) cellAtt).combine(spanArray[t],
newint[] { columns[i] });
}
}
table.clearSelection();
table.revalidate();
table.repaint();
最后就是使用了,只需要要传入我们的数据就可以构建出可合并的JTable了:
spanTablePanel = new SpanCellTablePanel(createTestData());
当我们实际使用时可能希望选中任何一个单元格都选中目前处于的最大列全选择,简单的加个
SelectionListener就可以了
spanTablePanel.getTable().getSelectionModel().addListSelectionListener(
在事件里处理选中:
@Override
publicvoid
valueChanged(ListSelectionEvent e) {
spanTablePanel.getTable().getSelectionModel()
.setSelectionInterval(allSelectRows[0],
llSelectRows[allSelectRows.length - 1]);
到此为之,对单元格的操作就基本结束了,以后看到或者想到别的再补充,JTable剩下的比较复杂的就是JtableHeader了,它也可以设置Rendere和Editor,也可以合并和拆分,可以设置特殊组件,下次就开始JtableHeader.
分享到:
相关推荐
在这个“jquery table rowspan 表格单元格合并Demo.zip”中,我们主要关注的是如何使用 jQuery 来实现 HTML 表格(`<table>`)中的 `rowspan` 属性来合并单元格,以创建更复杂、更有结构感的表格布局。 首先,`...
多于一列时,后一列的单元格合并范围不能超过前一列的合并范围。避免出现交错。 参数说明:_w_table_id 为需要进行合并单元格的表格id。如在HTMl中指定表格 id="data" ,此参数应为 #data 参数说明:_w_table_...
3. **单元格合并**:在网页开发中,如果需要将多个相邻的单元格合并成一个大单元格,可以使用`rowspan`和`colspan`属性。`colspan`与`rowspan`类似,但作用于列的跨度。合并单元格可以提高表格布局的复杂性和美感。 ...
本教程将深入探讨如何在Flex中实现表格单元格的合并。 首先,我们需要了解Flex的DataGrid组件。DataGrid是Adobe Flex提供的一个功能强大的组件,用于显示数据集合,并且支持排序、分页、选择等多种功能。它的列可以...
本篇文章将详细探讨如何正确地合并表格单元格(`<td>`)以及与之相关的`width`和`height`属性的设置。 首先,关于`colspan`属性,它用于合并表格中的列。使用`colspan`时,一个单元格可以跨越多个列。但需要注意,...
colspan等于几就是合并几个列的单元格。du比如:zhicolspan="2",就是合并了2个列的单元格。 rowspan,表示合并行dao。rowspan等于几就是合并几个行的单元格。比如:rowspan="2", 就是合并了2个行的单元格
4. **合并单元格**:合并单元格功能允许用户将相邻的单元格组合成一个大的单元格,常用于创建标题或合并相同的数据。用户可以选择多个单元格,然后执行“合并单元格”操作,以实现这一效果。 5. **其他表格操作**:...
在Vue.js框架中,实现表格单元格的合并是一项常见的需求,尤其在展示复杂数据或创建报表时。Vue的灵活性使得我们可以轻松地处理这样的任务。...希望这个指南能帮助你理解和实现Vue中的表格单元格合并功能。
Winform下DataGridView单元格合并技术详解 在Winform开发中,DataGridView控件是非常常用的控件之一,它可以用来显示和编辑数据。但是,在实际开发中,我们经常会遇到需要合并单元格的问题,例如,在DataGridView中...
然而,在某些情况下,我们可能需要动态地合并Datagrid的表头单元格,以达到更清晰、更具有组织性的数据展示效果。这通常发生在数据有层次结构或需要对某一列进行分类时。本篇将详细讲解如何在WPF中实现这个功能。 ...
总结来说,Vue Easytable通过自定义渲染和数据处理特性,为开发者提供了灵活的表格单元格合并解决方案。通过结合数据结构设计、渲染函数编写以及合并策略制定,我们可以创建出满足各种需求的复杂表格布局。学习并...
在传统的表格布局中,每个单元格(cell)代表一行一列的交叉点,而合并单元格则是将多个相邻的单元格合并为一个大的单元格,这在显示分组数据、创建标题或者简化布局时特别有用。在GridView中,我们可以通过编程的...
背景之前项目中使用 Angular ng-repeat 动态生成的表格有合并单元格的需求,所以在生成 td 标签时统一加了 rowspan 属性,具体的 spa
要启用单元格合并,我们需要利用其自定义的回调函数和DOM操作。 1. **初始化Datatable**: 首先,我们需要在HTML中创建一个表格,并在JavaScript中初始化DataTable。设置基本参数,如数据源、列定义等: ```html...
在这个特定的示例中,“WPF GridControl 单元格合并”指的是如何在GridControl中实现单元格的合并,以创建更复杂和有组织的布局。单元格合并通常用于当一组数据需要跨多行或多列显示时,例如,汇总信息或者创建带有...
"layui table合并单元格.zip" 这个压缩包正是提供了关于如何在layui的表格中实现单元格合并的示例和资源。 首先,"layui table.txt" 文件可能包含了layui表格组件的基础用法和API介绍。layui的表格组件支持动态加载...
本篇文章将详细探讨如何在 JSP(JavaServer Pages)环境中利用 JavaScript 来实现表格单元格的合并功能。 #### 一、背景介绍 在给定的示例代码中,我们看到了一个通过 JSP 和 Struts2(`<s:iterator>` 标签)生成...
1. **动态单元格合并**:在JasperReport中,我们可以通过设置表格列的`isStretchWithOverflow`属性为`true`,使单元格根据内容自动扩展。同时,可以使用`groupFooter`来合并分组后的行。通过编程方式或在JRXML中设置...
在StringGrid控件中实现显示Excel形式的合并单元格效果,也可以用AdvStringGrid,XLGRID等第三方控件,不过要破解比较麻烦。 原理是通过重载 OnDrawCell 事件procedure TForm1.SGDrawCell(Sender: TObject; ACol, ...
它提供了丰富的API,使得开发者能够方便地处理PDF的各种操作,如添加文本、图像、表格,以及合并PDF等。在本示例中,我们将关注如何使用iText进行PDF文件的合并。 首先,确保你的项目已经包含了iText库。通常,你...