编辑:这可能是Excel的一般问题,我在这里进行跟踪:https://superuser.com/questions/1457518/adding-images-to-excel-that-obey-both-filtering-and-sorting-rules
我正在生成工作表,其中某些行将嵌入图像。根据我嵌入图像的方式,当隐藏其余行数据时图像不会隐藏,或者在对工作表进行排序时图像不会排序。
示例应用程序演示了此问题:https://github.com/dan-kirberger/poi-excel-image-issue-它生成两个工作表。每个都展示了我的问题之一。如果您只想查看生成的工作簿,那么还有一个slave-jenkins-node
文件夹包含预先生成的工作表。
在应用任何排序/过滤之前,工作表如下所示:
通过以下方式在工作表上启用排序/筛选:
examples
添加图像的代码(也在上面的github链接中):
sheet.setAutoFilter(new CellRangeAddress(sheet.getFirstRowNum(), sheet.getLastRowNum(), 0, 2));
在该代码段中, Drawing drawing = cell.getSheet().createDrawingPatriarch();
XSSFClientAnchor anchor = new XSSFClientAnchor();
anchor.setAnchorType(imageAnchorType);
anchor.setCol1(cell.getColumnIndex());
anchor.setRow1(cell.getRowIndex());
Picture picture = drawing.createPicture(anchor, pictureId);
picture.resize(1, 1);
是决定因素,如果设置为imageAnchorType
,则在过滤器中使用排序功能时,图像将不会排序:
请注意,图像不再与“文本”列匹配。 (带有图片“ 1”的图像现在位于“两位”的文本旁边)
如果将MOVE_AND_RESIZE
设置为imageAnchorType
,则图像会适当排序,但是当应用删除图像行的过滤器时,图像将保留:
我们应用了一个过滤器来显示“仅文本”列,因此“一个”和“三”行数据消失了,但它们的图像仍然保留。
我是否应该设置其他属性以使其按我想要的方式工作?
答案 0 :(得分:1)
问题不仅仅在于锚类型。同时提供排序和过滤,ClientAnchor.AnchorType.MOVE_AND_RESIZE
是正确的。为了进行排序,必须进行移动,并且对于过滤,必须进行大小调整(不可见行的行高为0)。
但是要支持排序,图片还必须适合已排序的单元格。它们不能确定单元格的大小,否则它们将不会与单元格一起排序。因此picture.resize
是不可能的,因为调整大小会将图片调整为原始尺寸,该尺寸可能会大于图片所锚定的单元格的尺寸。
ClientAnchor提供以下设置:
setCol1
,是锚点锚定的第一列。图片的左上边缘从该列的左边缘开始。
setDx1
是添加到锚点锚定的第一列左边缘的值。它将图片从第一列的左边缘水平移开。
setRow1
,即锚点锚定的第一行。图片的左上边缘从该行的上边缘开始。
setDy1
是添加到锚点锚定的第一行顶部边缘的值。它将图片垂直移离第一行的顶部边缘。
setCol2
,是锚点锚定的第二列。图片的右下边缘在该列的左边缘结束。
setDx2
是添加到锚点锚定的第二列左边缘的值。它将图片的右下边缘水平移离第二列的左边缘。这将水平放大图片。
setRow2
,即锚点锚定的第二行。图片的右下边缘在该行的上边缘结束。
setDy1
是添加到锚点锚定的第二行顶部的值。它将图片的右下边缘垂直移离第二行的上边缘。这将垂直拉伸图片。
要支持排序,Row1
和Row2
必须在同一行。这样,在对该行进行排序时,图片就属于该行。这意味着图片高度只能由Dy2
确定。图片高度必须适合行高。
以下代码显示了一个示例。我从您的github下载的图片。
代码:
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.util.IOUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.*;
class CreateExcelPictures {
static String excelPath = "ExcelWithPictures.xlsx";
static String[][] data = new String[][]{
new String[]{"Image", "Text", "Type"},
new String[]{"", "One", "One and Three"},
new String[]{"", "Two", "Two only"},
new String[]{"", "Three", "One and Three"}
};
static String[] pictureFileNames = new String[]{"one.png", "two.png", "three.png"};
static int pictureWidthPx = 30;
static int pictureHeightPx = 25;
static XSSFWorkbook workbook;
static XSSFSheet sheet;
static void addImage(int col1, int row1, int col2, int row2,
int dx1, int dy1, int dx2, int dy2,
String imageFileName, ClientAnchor.AnchorType anchorType) throws Exception {
InputStream imageInputStream = new FileInputStream(imageFileName);
byte[] bytes = IOUtils.toByteArray(imageInputStream);
int pictureId = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
imageInputStream .close();
XSSFClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
anchor.setAnchorType(anchorType);
// set Col1, Dx1, Row1, Dy1, Col2, Dx2, Row2, Dy2
// only this determines the picture's size then
anchor.setCol1(col1);
anchor.setDx1(dx1);
anchor.setRow1(row1);
anchor.setDy1(dy1);
anchor.setCol2(col2);
anchor.setDx2(dx2);
anchor.setRow2(row2);
anchor.setDy2(dy2);
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFPicture picture = drawing.createPicture(anchor, pictureId);
}
public static void main(String args[]) throws Exception {
workbook = new XSSFWorkbook();
sheet = workbook.createSheet();
int r = 0;
for (String[] rowData : data) {
XSSFRow row = sheet.createRow(r);
int c = 0;
for (String cellData : rowData) {
XSSFCell cell = row.createCell(c++);
cell.setCellValue(cellData);
}
if (r > 0) {
float rowHeight = (float)Units.pixelToPoints(pictureHeightPx); // picture's height must fit into row height
row.setHeightInPoints(rowHeight);
addImage(0, r, 0, r, /*all fits in one cell*/
/*Dx1 = 0 and Dy1 = 0, picture's top left edge starts on top left of the cell*/
Units.pixelToEMU(0), Units.pixelToEMU(0),
/*Dx2 is picture's width and Dy2 is picture's height, picture's bottom right edge ends on that point into the cell*/
Units.pixelToEMU(pictureWidthPx), Units.pixelToEMU(pictureHeightPx),
pictureFileNames[r-1], ClientAnchor.AnchorType.MOVE_AND_RESIZE);
}
r++;
}
sheet.setColumnWidth(2, 15*256);
sheet.setAutoFilter(new CellRangeAddress(0, 3, 0, 2));
FileOutputStream fos = new FileOutputStream(excelPath);
workbook.write(fos);
fos.close();
workbook.close();
}
}
结果:
可以进行排序和过滤。