这几天上网时无意中看到这篇文章(利用java的开源组件JExcel创建无差异的Excel文件,并且导入到.net项目中去),看到评论里有人说有老外利用J#把JExcelAPI编译为.NET可用的组件了。当即下载下来测试,Excel文件读写竟然都正常ORZ。当然,不知这种方式编译出来的组件是否存在bug,但几天测试下来一般功能还是正常的。
下面说下这几天的测试情况:
1、在.net上使用需要依赖一个j#的库文件vjslib.dll,只要安装了j#的发行包,在以下目录就能找到这个组件C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
在VS下直接添加引用就可以了。(假如不想安装j#发行包,可下载我打包的几个必须的j#库文件,下载后放到网站的bin目录下就可以了)
2、修改单元格的值
Code
// 直接修改原单元格的值
WritableCell cell = sheet.getWritableCell(0, 1);
if (cell.getType() == CellType.LABEL) // 判断单元格类型
((Label)cell).setString("excel test");
// 覆盖原有单元格(原有单元格格式会丢失!)
WritableCell cell = new new jxl.write.Label(0, 1, "excel test");
sheet.addCell(cell);
// 覆盖原有单元格(保留格式)
WritableCell cell = sheet.getWritableCell(0, 1);
jxl.format.CellFormat format = cell.getCellFormat();
if (format != null)
cell = new jxl.write.Label(0, 1, "excel test", format);
else
cell = new jxl.write.Label(0, 1, "excel test");
sheet.addCell(cell);
// 直接修改原单元格的值
WritableCell cell = sheet.getWritableCell(0, 1);
if (cell.getType() == CellType.LABEL) // 判断单元格类型
((Label)cell).setString("excel test");
// 覆盖原有单元格(原有单元格格式会丢失!)
WritableCell cell = new new jxl.write.Label(0, 1, "excel test");
sheet.addCell(cell);
// 覆盖原有单元格(保留格式)
WritableCell cell = sheet.getWritableCell(0, 1);
jxl.format.CellFormat format = cell.getCellFormat();
if (format != null)
cell = new jxl.write.Label(0, 1, "excel test", format);
else
cell = new jxl.write.Label(0, 1, "excel test");
sheet.addCell(cell);
3、工作表区块复制
发现没有区块复制的功能,只能利用WritableCell的copyTo()函数自己实现了。不过这个函数只能复制单元格的内容和格式,像合并单元格范围和行的格式等都需要另外复制。下面是我写的复制区块的函数:
Code
/// <summary>
/// 工作表内区块复制(不支持图片,图表等复杂对象复制)
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="srcCol">区块列索引</param>
/// <param name="srcRow">区块行索引</param>
/// <param name="srcWidth">区块的宽度</param>
/// <param name="srcHeight">区块的高度</param>
/// <param name="decCol">区块的目标列索引</param>
/// <param name="decRow">区块的目标行索引</param>
private void CopyRange(WritableSheet sheet, int srcCol, int srcRow, int srcWidth, int srcHeight, int decCol, int decRow)
{
CopyCells(sheet, srcCol, srcRow, srcWidth, srcHeight, decCol, decRow);
CopyMergeCells(sheet, srcCol, srcRow, srcWidth, srcHeight, decCol, decRow);
CopyRowFormat(sheet, srcRow, srcHeight, decRow);
}
private void CopyCells(WritableSheet sheet, int srcCol, int srcRow, int srcWidth, int srcHeight, int decCol, int decRow)
{
WritableCell newCell;
WritableCell writeCell;
Cell readCell;
jxl.format.CellFormat readFormat;
for (int i = 0; i < srcHeight; i++)
{
for (int j = 0; j < srcWidth; j++)
{
readCell = sheet.getCell(srcCol + j, srcRow + i);
readFormat = readCell.getCellFormat();
if (readCell.getType() == CellType.EMPTY && readFormat == null) //没有格式的空单元格不处理
continue;
writeCell = sheet.getWritableCell(srcCol + j, srcRow + i);
newCell = writeCell.copyTo(srcCol + j + decCol, srcRow + i + decRow);
sheet.addCell(newCell);
}
}
}
private void CopyRowFormat(WritableSheet sheet, int srcRow, int srcHeight, int decRow)
{
CellView cellView;
for (int i = 0; i < srcHeight; i++)
{
cellView = sheet.getRowView(srcRow + i);
sheet.setRowView(decRow + i, cellView);
}
}
private void CopyMergeCells(WritableSheet sheet, int srcCol, int srcRow, int srcWidth, int srcHeight, int decCol, int decRow)
{
Range[] ranges= sheet.getMergedCells(); // 获取工作表现有单元格
Cell brCell; // 合并格的下对角单元格
Cell ltCell; // 合并格的上对角单元格
int w1; // 原区域的上对角到合并格上对角的水平距离
int h1; // 原区域的上对角到合并格上对角的垂直距离
int w2; // 合并格的宽度
int h2; // 合并格的高度
for(int i=0; i<ranges.Length; i++)
{
if (!IsInRange(ranges[i], srcCol, srcRow, srcWidth, srcHeight))
continue;
brCell = ranges[i].getBottomRight();
ltCell = ranges[i].getTopLeft();
w1 = ltCell.getColumn() - srcCol;
h1 = ltCell.getRow() - srcRow;
w2 = brCell.getColumn() - ltCell.getColumn();
h2 = brCell.getRow() - ltCell.getRow();
sheet.mergeCells(decCol + w1, decRow + h1, decCol + w1 + w2, decRow + h1 + h2);
}
}
private bool IsInRange(Range merge, int srcCol, int srcRow, int srcWidth, int srcHeight)
{
bool flag = true;
// 判断合并单元格上对角是否落在区块内
Cell cell = merge.getTopLeft();
if (cell.getRow() < srcRow)
flag = false;
if (cell.getColumn() < srcCol)
flag = false;
// 判断合并单元格下对角是否落在区块内
cell = merge.getBottomRight();
if (cell.getRow() > (srcRow + srcHeight))
flag = false;
if (cell.getColumn() > (srcCol + srcWidth))
flag = false;
return flag;
}
/// <summary>
/// 工作表内区块复制(不支持图片,图表等复杂对象复制)
/// </summary>
/// <param name="sheet">工作表</param>
/// <param name="srcCol">区块列索引</param>
/// <param name="srcRow">区块行索引</param>
/// <param name="srcWidth">区块的宽度</param>
/// <param name="srcHeight">区块的高度</param>
/// <param name="decCol">区块的目标列索引</param>
/// <param name="decRow">区块的目标行索引</param>
private void CopyRange(WritableSheet sheet, int srcCol, int srcRow, int srcWidth, int srcHeight, int decCol, int decRow)
{
CopyCells(sheet, srcCol, srcRow, srcWidth, srcHeight, decCol, decRow);
CopyMergeCells(sheet, srcCol, srcRow, srcWidth, srcHeight, decCol, decRow);
CopyRowFormat(sheet, srcRow, srcHeight, decRow);
}
private void CopyCells(WritableSheet sheet, int srcCol, int srcRow, int srcWidth, int srcHeight, int decCol, int decRow)
{
WritableCell newCell;
WritableCell writeCell;
Cell readCell;
jxl.format.CellFormat readFormat;
for (int i = 0; i < srcHeight; i++)
{
for (int j = 0; j < srcWidth; j++)
{
readCell = sheet.getCell(srcCol + j, srcRow + i);
readFormat = readCell.getCellFormat();
if (readCell.getType() == CellType.EMPTY && readFormat == null) //没有格式的空单元格不处理
continue;
writeCell = sheet.getWritableCell(srcCol + j, srcRow + i);
newCell = writeCell.copyTo(srcCol + j + decCol, srcRow + i + decRow);
sheet.addCell(newCell);
}
}
}
private void CopyRowFormat(WritableSheet sheet, int srcRow, int srcHeight, int decRow)
{
CellView cellView;
for (int i = 0; i < srcHeight; i++)
{
cellView = sheet.getRowView(srcRow + i);
sheet.setRowView(decRow + i, cellView);
}
}
private void CopyMergeCells(WritableSheet sheet, int srcCol, int srcRow, int srcWidth, int srcHeight, int decCol, int decRow)
{
Range[] ranges= sheet.getMergedCells(); // 获取工作表现有单元格
Cell brCell; // 合并格的下对角单元格
Cell ltCell; // 合并格的上对角单元格
int w1; // 原区域的上对角到合并格上对角的水平距离
int h1; // 原区域的上对角到合并格上对角的垂直距离
int w2; // 合并格的宽度
int h2; // 合并格的高度
for(int i=0; i<ranges.Length; i++)
{
if (!IsInRange(ranges[i], srcCol, srcRow, srcWidth, srcHeight))
continue;
brCell = ranges[i].getBottomRight();
ltCell = ranges[i].getTopLeft();
w1 = ltCell.getColumn() - srcCol;
h1 = ltCell.getRow() - srcRow;
w2 = brCell.getColumn() - ltCell.getColumn();
h2 = brCell.getRow() - ltCell.getRow();
sheet.mergeCells(decCol + w1, decRow + h1, decCol + w1 + w2, decRow + h1 + h2);
}
}
private bool IsInRange(Range merge, int srcCol, int srcRow, int srcWidth, int srcHeight)
{
bool flag = true;
// 判断合并单元格上对角是否落在区块内
Cell cell = merge.getTopLeft();
if (cell.getRow() < srcRow)
flag = false;
if (cell.getColumn() < srcCol)
flag = false;
// 判断合并单元格下对角是否落在区块内
cell = merge.getBottomRight();
if (cell.getRow() > (srcRow + srcHeight))
flag = false;
if (cell.getColumn() > (srcCol + srcWidth))
flag = false;
return flag;
}
4、下面是我写的一个demo,根据excel模板输出内容。只要在excel模板的单元格中写上格式内容:$数据库列名$,程序就会在指定单元格内写上数据库对应的数据。现在支持输出三种格式的报表:
1、数据表数据导出
2、分页导出数据
3、导出数据到一个sheet中