Java 如何将XDDF图表添加到特定段落(即表格中的单元格)?POI 4.0.1
我想将图表添加到XWPFDocument中的特定表格单元格中。我希望图表位于表格单元格中,以便确保与稍后添加的其他元素对齐。那么Java 如何将XDDF图表添加到特定段落(即表格中的单元格)?POI 4.0.1,java,apache-poi,apache-poi-4,Java,Apache Poi,Apache Poi 4,我想将图表添加到XWPFDocument中的特定表格单元格中。我希望图表位于表格单元格中,以便确保与稍后添加的其他元素对齐。那么 如何创建XWPF/XDDF图表而不将其添加到文档中(例如,不使用document.createChart()) 如何获取该图表并将其添加到特定段落/运行(例如,在表格单元格中创建的段落/运行) 已尝试: 创建映射XWPFDocument.createChart()中代码的图表 将XWPFRun.addChart()与我在中使用的RelationPart.getRe
- 如何创建XWPF/XDDF图表而不将其添加到文档中(例如,不使用document.createChart())
- 如何获取该图表并将其添加到特定段落/运行(例如,在表格单元格中创建的段落/运行)
// Create a document with some initial text
XWPFDocument document = new XWPFDocument();
XWPFParagraph tmpParagraph = document.createParagraph();
XWPFRun tmpRun = tmpParagraph.createRun();
tmpRun.setText("text");
tmpRun.setFontSize(18);
// Try making the chart
// the same code as here, https://stackoverflow.com/questions/55192804/how-do-i-add-a-second-line-with-a-second-axis-to-an-xddfchart-in-poi-4-0-1
try{
String[] categories = new String[]{"1","2","3","4","5","6","7","8","9"};
Double[] values1 = new Double[]{1d,2d,3d,4d,5d,6d,7d,8d,9d};
Double[] values2 = new Double[]{200d,300d,400d,500d,600d,700d,800d,900d,1000d};
// create the chart
// XWPFChart chart = document.createChart(7* Units.EMU_PER_CENTIMETER, 7*Units.EMU_PER_CENTIMETER);
// Try to make a chart stand alone
// using the same code as here,
// https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java?view=markup
int chartNumber = document.getCharts().size();
POIXMLDocumentPart.RelationPart rp = document.createRelationship(XWPFRelation.CHART, XWPFFactory.getInstance(), chartNumber, false);
XWPFChart chart = rp.getDocumentPart();
chart.setChartIndex(chartNumber);
chart.setChartBoundingBox(7* Units.EMU_PER_CENTIMETER, 7*Units.EMU_PER_CENTIMETER);
document.getCharts().add(chart);
// This stuff to make the chart is not part of the question
// create data sources
int numOfPoints = categories.length;
String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
String valuesDataRange1 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
XDDFNumericalDataSource<Double> valuesData1 = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange1, 1);
XDDFNumericalDataSource<Double> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
// first line chart
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
XDDFChartData data = chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFChartData.Series series = data.addSeries(categoriesData, valuesData1);
chart.plot(data);
solidLineSeries(data, 0, PresetColor.BLUE);
// second line chart
// bottom axis must be there but must not be visible
bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setVisible(false);
XDDFValueAxis rightAxis = chart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosses(AxisCrosses.MAX);
// set correct cross axis
bottomAxis.crossAxis(rightAxis);
rightAxis.crossAxis(bottomAxis);
data = chart.createData(ChartTypes.LINE, bottomAxis, rightAxis);
series = data.addSeries(categoriesData, valuesData2);
chart.plot(data);
// correct the id and order, must not be 0 again because there is one line series already
chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getIdx().setVal(1);
chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getOrder().setVal(1);
solidLineSeries(data, 0, PresetColor.RED);
// End of extra stuff
// Back to question
// Add the chart by relation id
XWPFParagraph p2 = document.createParagraph();
XWPFRun r2 = p2.createRun();
r2.addChart(rp.getRelationship().getId());
// Add a new run to try to add a new drawing?
XWPFRun r3 = p2.createRun();
CTDrawing drawing = r3.getCTR().addNewDrawing();
????
}catch(Exception e){}
//创建带有一些初始文本的文档
XWPFDocument document=新的XWPFDocument();
XWPFParagraph tmpParagraph=document.createParagraph();
XWPFRun tmpRun=tmpParagraph.createRun();
tmpRun.setText(“文本”);
tmpRun.setFontSize(18);
//试着制作图表
//和这里的代码一样,https://stackoverflow.com/questions/55192804/how-do-i-add-a-second-line-with-a-second-axis-to-an-xddfchart-in-poi-4-0-1
试一试{
字符串[]类别=新字符串[]{“1”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9”};
Double[]值1=新的Double[]{1d、2d、3d、4d、5d、6d、7d、8d、9d};
双[]值2=新的双[]值{200d、300d、400d、500d、600d、700d、800d、900d、1000d};
//创建图表
//XWPFChart chart=document.createChart(每厘米7*Units.EMU,每厘米7*Units.EMU);
//试着单独制作一张图表
//使用与此处相同的代码,
// https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java?view=markup
int chartNumber=document.getCharts().size();
POIXMLDocumentPart.RelationPart rp=document.createRelationship(XWPFRelation.CHART,XWPFFactory.getInstance(),chartNumber,false);
XWPFChart chart=rp.getDocumentPart();
图表。设置图表索引(图表编号);
chart.setChartBoundingBox(每厘米7*Units.EMU,每厘米7*Units.EMU);
document.getCharts().add(图表);
//制作图表的这些东西不是问题的一部分
//创建数据源
int numOfPoints=categories.length;
String categoryDataRange=chart.formatRange(新的CellRangeAddress(1,numOfPoints,0,0));
String valuesDataRange1=chart.formatRange(新的CellRangeAddress(1,numOfPoints,1,1));
String valuesDataRange2=chart.formatRange(新的CellRangeAddress(1,numOfPoints,2,2));
XDDFDataSource categoriesData=XDDFDataSourcesFactory.fromArray(categories,CategorityDataRange,0);
XDDFNumericalDataSource valuesData1=XDDFDataSourcesFactory.fromArray(值1,值sDataRange1,1);
XDDFNumericalDataSource valuesData2=XDDFDataSourcesFactory.fromArray(values2,valuesDataRange2,2);
//第一折线图
XDDFCategoryAxis bottomAxis=chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis=chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setcrosss(axiscrosss.AUTO_ZERO);
XDDFChartData data=chart.createData(ChartTypes.LINE、bottomAxis、leftAxis);
XDDFChartData.Series系列=data.addSeries(categoriesData,valuesData1);
图表、绘图(数据);
solidLineSeries(数据,0,预设颜色。蓝色);
//第二折线图
//底部轴必须在那里,但不能可见
bottomAxis=chart.createCategoryAxis(AxisPosition.BOTTOM);
底部轴设置可见(假);
XDDFValueAxis rightAxis=chart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosss(axisCrosss.MAX);
//设置正确的横轴
下轴。横轴(右轴);
右轴。横轴(下轴);
数据=chart.createData(ChartTypes.LINE、bottomAxis、rightAxis);
series=data.addSeries(categoriesData,valuesData2);
图表、绘图(数据);
//请更正id和顺序,不能再次为0,因为已经有一个行序列
chart.getCTChart().getPlotArea().getLineChartArray(1.GetSerray(0.getIdx().setVal(1);
chart.getCTChart().getPlotArea().getLineChartArray(1.GetSerray(0.getOrder().setVal(1);
solidLineSeries(数据,0,预设颜色,红色);
//多余的东西结束了
//回到问题上来
//按关系id添加图表
XWPFParagraph p2=document.createParagraph();
XWPFRun r2=p2.createRun();
r2.addChart(rp.getRelationship().getId());
//是否添加新管路以尝试添加新图形?
XWPFRun r3=p2.createRun();
CTDrawing drawing=r3.getCTR().addNewDrawing();
????
}捕获(例外e){}
当我通过r2.addChart()添加图表时,什么都没有显示?也许我没有正确地创建图表?或者我没有正确地将其添加到跑步中
图表是否可以转换为图形
由于对哪些方法是受保护的或私有的做出了奇怪的决定,apache poi常常使得扩展他们的代码变得非常困难。在这种情况下,它在
XWPFDocument
中缺少方法public XWPFChart createChart(int-width,int-height,XWPFRun-run)
,因为现有方法总是将图表放入文档正文中新创建段落的新创建运行中。但是简单地扩展XWPFDocument
几乎是不可能的,因为所需的方法是受保护的或私有的
我发现的最简单的方法是首先使用document.createChart()
将图表放在文档的第一段。然后删除第一段。图表部分保留(至少使用<
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
public class CreateWordXDDFChartTwoLinesInTable {
public static void main(String[] args) throws Exception {
try (XWPFDocument document = new XWPFDocument()) {
// create the data
String[] categories = new String[]{"1","2","3","4","5","6","7","8","9"};
Double[] values1 = new Double[]{1d,2d,3d,4d,5d,6d,7d,8d,9d};
Double[] values2 = new Double[]{200d,300d,400d,500d,600d,700d,800d,900d,1000d};
// create the chart
// this also puts the chart into a run in a new created paragraph
XWPFChart chart = createChart(document, categories, values1, values2);
// remove the first paragraph since we need the chart being elsewhere
document.removeBodyElement(0);
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("First paragraph having first text run.");
// create the table
XWPFTable table = document.createTable(1,2);
table.setWidth("100%");
// create first run in first table cell
paragraph = table.getRow(0).getCell(0).getParagraphArray(0);
run = paragraph.createRun();
// attach the chart here
java.lang.reflect.Method attach = XWPFChart.class.getDeclaredMethod("attach", String.class, XWPFRun.class);
attach.setAccessible(true);
attach.invoke(chart, document.getRelationId(chart), run);
chart.setChartBoundingBox(7*Units.EMU_PER_CENTIMETER, 7*Units.EMU_PER_CENTIMETER);
// set text in second table cell
paragraph = table.getRow(0).getCell(1).getParagraphArray(0);
run = paragraph.createRun();
run.setText("Other text goes in the 2");
run = paragraph.createRun();
run.setSubscript(VerticalAlign.SUPERSCRIPT);
run.setText("nd");
run = paragraph.createRun();
run.setText(" cell.");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Lorem ipsum...");
// Write the output to a file
try (FileOutputStream fileOut = new FileOutputStream("CreateWordXDDFChartTwoLinesInTable.docx")) {
document.write(fileOut);
}
}
}
private static XWPFChart createChart(XWPFDocument document,
String[] categories, Double[] values1, Double[] values2) throws Exception {
// create the chart
XWPFChart chart = document.createChart();
// create data sources
int numOfPoints = categories.length;
String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
String valuesDataRange1 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 1, 1));
String valuesDataRange2 = chart.formatRange(new CellRangeAddress(1, numOfPoints, 2, 2));
XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
XDDFNumericalDataSource<Double> valuesData1 = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange1, 1);
XDDFNumericalDataSource<Double> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, 2);
// first line chart
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
XDDFChartData data = chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
XDDFChartData.Series series = data.addSeries(categoriesData, valuesData1);
chart.plot(data);
solidLineSeries(data, 0, PresetColor.BLUE);
// second line chart
// bottom axis must be there but must not be visible
bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setVisible(false);
XDDFValueAxis rightAxis = chart.createValueAxis(AxisPosition.RIGHT);
rightAxis.setCrosses(AxisCrosses.MAX);
// set correct cross axis
bottomAxis.crossAxis(rightAxis);
rightAxis.crossAxis(bottomAxis);
data = chart.createData(ChartTypes.LINE, bottomAxis, rightAxis);
series = data.addSeries(categoriesData, valuesData2);
chart.plot(data);
// correct the id and order, must not be 0 again because there is one line series already
chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getIdx().setVal(1);
chart.getCTChart().getPlotArea().getLineChartArray(1).getSerArray(0).getOrder().setVal(1);
solidLineSeries(data, 0, PresetColor.RED);
return chart;
}
private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
XDDFLineProperties line = new XDDFLineProperties();
line.setFillProperties(fill);
XDDFChartData.Series series = data.getSeries().get(index);
XDDFShapeProperties properties = series.getShapeProperties();
if (properties == null) {
properties = new XDDFShapeProperties();
}
properties.setLineProperties(line);
series.setShapeProperties(properties);
}
}