实际上,我使用Apache POI生成Word文档,并且需要自动创建引用段落的目录(TOC)以及页面指示。
这是我正在使用的代码(我省略了先决条件和内部方法的主体):
XWPFDocument doc = new XWPFDocument(OPCPackage.openOrCreate(new File(document)));
String strStyleId = "Index Style";
addCustomHeadingStyle(doc, strStyleId, 1);
XWPFParagraph documentControlHeading = doc.createParagraph();
changeText(documentControlHeading, "First try");
documentControlHeading.setAlignment(ParagraphAlignment.LEFT);
documentControlHeading.setPageBreak(true);
documentControlHeading.setStyle(strStyleId);
XWPFParagraph documentControlHeading1 = doc.createParagraph();
changeText(documentControlHeading1, "Second try");
documentControlHeading1.setAlignment(ParagraphAlignment.LEFT);
documentControlHeading1.setPageBreak(true);
documentControlHeading1.setStyle(strStyleId);
doc.createTOC();
当我打开生成的文档时,我得到了这个结果(见蓝色方块):
在左边部分,我可以看到生成的TOC。 到现在为止还挺好。 然而,在文档的正文中,我只能看到一个静态文本“目录”,根本没有任何迹象(既不是段落也不是页面)。 我甚至无法与之互动。
如果我点击菜单条目“目录”(左上角的红色方块),我想要生成的“真实”内容列表正在生成(当然,请按照箭头......)。
我的问题是: 如何从代码中获得第二个结果(红色TOC)?
非常感谢。
_附注:_我甚至尝试把doc.enforceUpdateFields();
在doc.createTOC();
,但是TOC的每个参考都以这种方式消失。
@Sucy,我添加您请求的方法。 不知道你是否能找到它们有用,但:
/*
* Adds a custom style with the given indentation level at the given document.
*/
private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {
CTStyle ctStyle = CTStyle.Factory.newInstance();
ctStyle.setStyleId(strStyleId);
CTString styleName = CTString.Factory.newInstance();
styleName.setVal(strStyleId);
ctStyle.setName(styleName);
CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
indentNumber.setVal(BigInteger.valueOf(headingLevel));
// lower number > style is more prominent in the formats bar
ctStyle.setUiPriority(indentNumber);
CTOnOff onoffnull = CTOnOff.Factory.newInstance();
ctStyle.setUnhideWhenUsed(onoffnull);
// style shows up in the formats bar
ctStyle.setQFormat(onoffnull);
// style defines a heading of the given level
CTPPr ppr = CTPPr.Factory.newInstance();
ppr.setOutlineLvl(indentNumber);
ctStyle.setPPr(ppr);
XWPFStyle style = new XWPFStyle(ctStyle);
// is a null op if already defined
XWPFStyles styles = docxDocument.createStyles();
style.setType(STStyleType.PARAGRAPH);
styles.addStyle(style);
}
/*
* Changes the text of a given paragraph.
*/
public static void changeText(XWPFParagraph p, String newText) {
if (p != null) {
List<XWPFRun> runs = p.getRuns();
for (int i = runs.size() - 1; i >= 0; i--) {
p.removeRun(i);
}
if (runs.size() == 0) {
p.createRun();
}
XWPFRun run = runs.get(0);
run.setText(newText, 0);
}
}
I am actually generating a Word Document with Apache POI, and I need to automatically create a Table of Contents (TOC) that references the paragraphs, with their page's indication.
This is the code I am using (I omit preconditions and internal methods' body):
XWPFDocument doc = new XWPFDocument(OPCPackage.openOrCreate(new File(document)));
String strStyleId = "Index Style";
addCustomHeadingStyle(doc, strStyleId, 1);
XWPFParagraph documentControlHeading = doc.createParagraph();
changeText(documentControlHeading, "First try");
documentControlHeading.setAlignment(ParagraphAlignment.LEFT);
documentControlHeading.setPageBreak(true);
documentControlHeading.setStyle(strStyleId);
XWPFParagraph documentControlHeading1 = doc.createParagraph();
changeText(documentControlHeading1, "Second try");
documentControlHeading1.setAlignment(ParagraphAlignment.LEFT);
documentControlHeading1.setPageBreak(true);
documentControlHeading1.setStyle(strStyleId);
doc.createTOC();
When I open the resulting document, I am getting this result (see blue squares):
In the left part, I can see the generated TOC. So far, so good. In the document's body, however, I can just see a static text "Table of Contents", with no indications at all (neither paragraphs nor pages). I cannot even interact with it.
If I'd click on the menu entry "Table of Contents" (red square on the upper-left corner), the "real" Table of Content that I want is being generated (follow the arrow, of course...).
My question is: how can I achieve the second result (red TOC) from code?
Thank you so much.
Side note: I even tried putting doc.enforceUpdateFields();
after doc.createTOC();
, but every reference of the TOC disappears, this way.
@Sucy, I add the methods that you requested. Don't know if you can find them useful, though:
/*
* Adds a custom style with the given indentation level at the given document.
*/
private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {
CTStyle ctStyle = CTStyle.Factory.newInstance();
ctStyle.setStyleId(strStyleId);
CTString styleName = CTString.Factory.newInstance();
styleName.setVal(strStyleId);
ctStyle.setName(styleName);
CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
indentNumber.setVal(BigInteger.valueOf(headingLevel));
// lower number > style is more prominent in the formats bar
ctStyle.setUiPriority(indentNumber);
CTOnOff onoffnull = CTOnOff.Factory.newInstance();
ctStyle.setUnhideWhenUsed(onoffnull);
// style shows up in the formats bar
ctStyle.setQFormat(onoffnull);
// style defines a heading of the given level
CTPPr ppr = CTPPr.Factory.newInstance();
ppr.setOutlineLvl(indentNumber);
ctStyle.setPPr(ppr);
XWPFStyle style = new XWPFStyle(ctStyle);
// is a null op if already defined
XWPFStyles styles = docxDocument.createStyles();
style.setType(STStyleType.PARAGRAPH);
styles.addStyle(style);
}
/*
* Changes the text of a given paragraph.
*/
public static void changeText(XWPFParagraph p, String newText) {
if (p != null) {
List<XWPFRun> runs = p.getRuns();
for (int i = runs.size() - 1; i >= 0; i--) {
p.removeRun(i);
}
if (runs.size() == 0) {
p.createRun();
}
XWPFRun run = runs.get(0);
run.setText(newText, 0);
}
}
更新时间:2022-09-04 06:09
你所看到的XWPF类是一项正在进行的工作,没有真正的总体架构。 随着时间的推移,这将随着时间的推移而变化,但同时您可以尝试用这种方法为段落添加一个简单的TOC字段。
XWPFParagraph p;
...
// get or create your paragraph
....
CTP ctP = p.getCTP();
CTSimpleField toc = ctP.addNewFldSimple();
toc.setInstr("TOC \\h");
toc.setDirty(STOnOff.TRUE);
这将创建一个带有超链接到页面的目录,当Word打开它时应重新计算它,并且目录将基于预定义的HeaderX样式。
The XWPF classes as you have seen are a work in progress, with no real overarching architecture. That will change over time as we work on it, but in the mean time you can try to add a simple TOC field to a paragraph in this way.
XWPFParagraph p;
...
// get or create your paragraph
....
CTP ctP = p.getCTP();
CTSimpleField toc = ctP.addNewFldSimple();
toc.setInstr("TOC \\h");
toc.setDirty(STOnOff.TRUE);
This will create a Table of contents with hyperlinks to the pages, it should be recalculated when Word opens it, and the table of contents will be based on predefined HeaderX styles.
a
a
你所看到的XWPF类是一项正在进行的工作,没有真正的总体架构。 随着时间的推移,这将随着时间的推移而变化,但同时您可以尝试用这种方法为段落添加一个简单的TOC字段。 XWPFParagraph p; ... // get or create your paragraph .... CTP ctP = p.getCTP(); CTSimpleField toc = ctP.addNewFldSimple(); toc.setInstr("TOC \h"); toc.setDirty(STOnOff.TRUE ...
这可以通过几个简单的步骤完成。 创建PDF文档内容时,请在您希望TOC所在的位置留下一个空页(或多个页面),例如: $this->pdf->AddPage('P','letter'); $this->pdf->AddPage('P','letter'); 在构建pdf内容时将TOC内容添加到数组中。 $toc\[\] = \['label' -> "item", 'page' -> $pdf->PageNo()]; 构建完所有内容后,保存当前页码: $last_page = $pdf->PageNo(); 将页码 ...
好的,我找到了一个足够的解决方案,我已经建立了一个POC - 它的工作原理。 它是一种双通道方法,使用自定义外部组件。 首先渲染子报告以填充目录表,然后运行主报告并在TOC页面上显示TOC结果,然后再进行子报告。 这是让我走的链接 。 问候, 贾森 Ok, I've found an adequate solution that I've built a POC on - and it works. Its a two pass approach, using custom external assembl ...
表是块级项目,这意味着它将根据页面的高度和跨度占用垂直空间,无论是否使用该空间。 所以没有办法以相同的方式并排“流动”两个表,无法并排流动两个段落。 有几种方法可以实现这种效果,但在您的情况下最直接的方法可能是创建一个1行乘三列的表,并将左表放在第一个单元格中,将右表放在第三列中。 中间列可用于实现两者之间的间隔。 您可能不希望在包含表上使用任何边框,因为它用于格式化而不是显示。 A table is a block-level item, meaning it will take up vertical ...
我建议你从原始文档中查看此示例。 没有办法(或至少我不知道/没有找到如何)在开始时生成目录(因为没有办法知道页码)。 因此,您必须在结束时(在摘要带中)生成它,然后将其移动到您想要放置的位置。 要移动它,请使用JasperPrint类,方法getPages,addPage,removePage。 我猜你会有子报告,如果是这样,你需要传递你将在运行时填充到每个子报告的JRBeanCollectionDataSource(并将值返回给主报告)。 希望有所帮助。 I would recommend you che ...
在计算页面时,PageNo()有点时髦。 它按照创建的顺序输出它是什么页面,并且因为ToC页面被创建为最后一页,它将显示为最后一页。 所以改为使用 // Page number $this->Cell(0, 12, ' '.$this->getAliasNumPage().' of '.$this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M'); 您提供的其余代码(如检查它是否是第一页)应与PageNo()一起使用。 Pa ...
我不是“沃尔德”,所以这就是我的目标: Function GetPagesNumber(doc As Document) As Long() Dim i As Long Dim myRng As Range Dim myHeadings As Variant With doc Set myRng = .Content myRng.Collapse Direction:=wdCollapseEnd myHeadings = . ...
推荐对答案的评论...... 序列化XWPFDocument (或实际上任何POI UserModel文档)的方法是通过write(OutputStream)方法 如果需要序列化为字节数组,则可以执行以下操作: XWPFDocument doc = new XWPFDocument(); ... ByteArrayOutputStream baos = new ByteArrayOutputStream(); doc.write(baos); return baos.toByteArray(); 假设您 ...
原网址: 访问
创建于: 2023-05-08 11:04:37
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论