首页 > 解决方案 > 在 java 中添加到 org.apache.poi.xssf.usermodel.XSSFTextBox 的超链接

问题描述

我想使用文本框添加一个超链接(指的是具有不同工作表的同一文档,例如 E1)。超链接在此创建,但这不是指表 E1。

下面是我的代码。

    XSSFSheet sheet = templateWorkbook.getSheetAt(0);
    XSSFDrawing drawing = sheet.createDrawingPatriarch();
    anchor.setAnchorType(AnchorType.MOVE_DONT_RESIZE);
    XSSFTextBox textBox = drawing.createTextbox(anchor);
    textBox.setFillColor(112, 80, 151);
    textBox.setVerticalAlignment(VerticalAlignment.CENTER);
    XSSFRichTextString text = new XSSFRichTextString("text");
     
     textBox.setTopInset(0.25D);
   
     textBox.setText("text");
     CTTextCharacterProperties rpr = textBox.getCTShape().getTxBody().getPArray(0).getRArray(0).getRPr();
     Color color = Color.white;
     rpr.addNewSolidFill().addNewSrgbClr().setVal(new byte[]{(byte)color.getRed(),(byte)color.getGreen(),(byte)color.getBlue()});
    CTHyperlink hyperlink = CTHyperlink.Factory.newInstance();
    

    
    textBox.getCTShape().getNvSpPr().getCNvPr().setHlinkClick(hyperlink);

标签: javaexcelapache-poi

解决方案


有关图片的相同问题,请参阅Apache poi 在图像中放置超链接。

CTHyperlink直接设置超链接目标。而是CTHyperlink指绘图的封装关系中的引用。然后包关系引用超链接目标。因此需要创建该包关系并将其 id 设置为CTHyperlink.

使用 current 测试和工作的完整示例apache poi 5.0.0

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;

import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;

import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;


public class CreateExcelTextBoxHyperlink {
    
 private static void setHyperlinkToShape(XSSFSimpleShape shape, String hyperlinkurl) throws Exception {

  XSSFDrawing drawing = shape.getDrawing();
  PackageRelationship packagerelationship = 
    drawing.getPackagePart().addExternalRelationship(hyperlinkurl, PackageRelationshipTypes.HYPERLINK_PART);
  String rid = packagerelationship.getId();

  CTShape ctshape = shape.getCTShape();
  CTShapeNonVisual crshapenonvisual = ctshape.getNvSpPr();
  if (crshapenonvisual == null) crshapenonvisual = ctshape.addNewNvSpPr();
  CTNonVisualDrawingProps ctnonvisualdrawingprops = crshapenonvisual.getCNvPr();
  if (ctnonvisualdrawingprops == null) ctnonvisualdrawingprops = crshapenonvisual.addNewCNvPr();
  CTHyperlink cthyperlink = ctnonvisualdrawingprops.getHlinkClick();
  if (cthyperlink == null) cthyperlink = ctnonvisualdrawingprops.addNewHlinkClick();
  cthyperlink.setId(rid);

 }

 public static void main(String[] args) throws Exception {
  XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("./Excel.xlsx"));

  XSSFSheet sheet = workbook.getSheetAt(0);
  
  XSSFDrawing drawing = sheet.createDrawingPatriarch();
  XSSFClientAnchor anchor =  drawing.createAnchor(0, 0, 0, 0, 2, 2, 3, 3);
  anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE);
  XSSFTextBox textBox = drawing.createTextbox(anchor);
  textBox.setFillColor(112, 80, 151);
  textBox.setVerticalAlignment(VerticalAlignment.CENTER);
  textBox.setTopInset(0.25D);
  
  XSSFRichTextString text = workbook.getCreationHelper().createRichTextString("text");
  XSSFFont font = workbook.createFont();
  font.setColor(IndexedColors.WHITE.getIndex()); 
  text.applyFont(font);
  textBox.setText(text);
  
  setHyperlinkToShape(textBox, "#Sheet2!E1");

  FileOutputStream out = new FileOutputStream("./ExcelNew.xlsx");
  workbook.write(out);
  out.close();
  workbook.close();
 }
}

超链接目标URI #Sheet2!E1是指E1工作表中名为的单元格Sheet2

由于apache poi将所有超链接目标作为URI需要URI编码的 s,因此目标工作表名称不能包含空格。如果目标工作表名称是Sheet 2,那么目标URI必须是#'Sheet%202'!E1。但Excel预计#'Sheet 2'!E1。所以对于Excel那些目标根本不是URIs。但对于apache poi他们来说。


推荐阅读