使用 Apache POI 更改 XLSX 表单控件位置
Changing XLSX form control location with Apache POI
我有一些包含表单控件的 xlsm 文件。我想以编程方式将每个 sheet 上的特定按钮向下移动几行。我的第一个希望是做这样的事情:
FileInputStream inputStream = new FileInputStream(new File("t.xlsm"));
XSSFWorkbook wb = new XSSFWorkbook(inputStream);
XSSFSheet xs = (XSSFSheet)wb.getSheetAt(1);
RelationPart rp = xs.getRelationParts().get(0);
XSSFDrawing drawing = (XSSFDrawing)rp.getDocumentPart();
for(XSSFShape sh : drawing.getShapes()){
XSSFClientAnchor a = (XSSFClientAnchor)sh.getAnchor();
if (sh.getShapeName().equals("Button 2")) {
a.setRow1(a.getRow1()+10);
a.setRow2(a.getRow2()+10);
}
}
但是,XSSFDrawing.getShapes()
给出的形状对象是副本,在 wb.write()
之后对它们的任何更改都不会反映在文档中。
我尝试了其他几种方法,例如获取 CTShape
并在其中解析 XML,但事情很快就变得棘手了。
是否有推荐的方法来通过 POI 管理这样的表单控件?
我最终直接摆弄了 XML:
wb = new XSSFWorkbook(new File(xlsmFile));
XSSFSheet s = wb.getSheet("TWO");
XmlObject[] subobj = s.getCTWorksheet().selectPath(declares+
" .//mc:AlternateContent/mc:Choice/main:controls/mc:AlternateContent/mc:Choice/main:control");
String targetButton = "Button 2";
int rowsDown = 10;
for (XmlObject obj : subobj) {
XmlCursor cursor = obj.newCursor();
cursor.push();
String attrName = cursor.getAttributeText(new QName("name"));
if (attrName.equals(targetButton)) {
cursor.selectPath(declares+" .//main:from/xdr:row");
if (!cursor.toNextSelection()) {
throw new Exception();
}
int newRow = Integer.parseInt(cursor.getTextValue()) + rowsDown;
cursor.setTextValue(Integer.toString(newRow));
cursor.pop();
cursor.selectPath(declares+" .//main:to/xdr:row");
if (!cursor.toNextSelection()) {
throw new Exception();
}
newRow = Integer.parseInt(cursor.getTextValue()) + rowsDown;
cursor.setTextValue(Integer.toString(newRow));
}
cursor.dispose();
}
这会将命名按钮向下移动 10 行。我必须找到按钮名称(这可能不容易通过 Excel 找到,我直接检查了文件)。我猜这对正在使用的 Excel 版本非常敏感。
我有一些包含表单控件的 xlsm 文件。我想以编程方式将每个 sheet 上的特定按钮向下移动几行。我的第一个希望是做这样的事情:
FileInputStream inputStream = new FileInputStream(new File("t.xlsm"));
XSSFWorkbook wb = new XSSFWorkbook(inputStream);
XSSFSheet xs = (XSSFSheet)wb.getSheetAt(1);
RelationPart rp = xs.getRelationParts().get(0);
XSSFDrawing drawing = (XSSFDrawing)rp.getDocumentPart();
for(XSSFShape sh : drawing.getShapes()){
XSSFClientAnchor a = (XSSFClientAnchor)sh.getAnchor();
if (sh.getShapeName().equals("Button 2")) {
a.setRow1(a.getRow1()+10);
a.setRow2(a.getRow2()+10);
}
}
但是,XSSFDrawing.getShapes()
给出的形状对象是副本,在 wb.write()
之后对它们的任何更改都不会反映在文档中。
我尝试了其他几种方法,例如获取 CTShape
并在其中解析 XML,但事情很快就变得棘手了。
是否有推荐的方法来通过 POI 管理这样的表单控件?
我最终直接摆弄了 XML:
wb = new XSSFWorkbook(new File(xlsmFile));
XSSFSheet s = wb.getSheet("TWO");
XmlObject[] subobj = s.getCTWorksheet().selectPath(declares+
" .//mc:AlternateContent/mc:Choice/main:controls/mc:AlternateContent/mc:Choice/main:control");
String targetButton = "Button 2";
int rowsDown = 10;
for (XmlObject obj : subobj) {
XmlCursor cursor = obj.newCursor();
cursor.push();
String attrName = cursor.getAttributeText(new QName("name"));
if (attrName.equals(targetButton)) {
cursor.selectPath(declares+" .//main:from/xdr:row");
if (!cursor.toNextSelection()) {
throw new Exception();
}
int newRow = Integer.parseInt(cursor.getTextValue()) + rowsDown;
cursor.setTextValue(Integer.toString(newRow));
cursor.pop();
cursor.selectPath(declares+" .//main:to/xdr:row");
if (!cursor.toNextSelection()) {
throw new Exception();
}
newRow = Integer.parseInt(cursor.getTextValue()) + rowsDown;
cursor.setTextValue(Integer.toString(newRow));
}
cursor.dispose();
}
这会将命名按钮向下移动 10 行。我必须找到按钮名称(这可能不容易通过 Excel 找到,我直接检查了文件)。我猜这对正在使用的 Excel 版本非常敏感。