Добавление изображений на листы, которые подчиняются правилам сортировки и фильтрации - PullRequest
0 голосов
/ 08 июля 2019

Редактировать : Вероятно, это общая проблема 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 - генерирует две таблицы. Каждый демонстрирует одну из моих проблем. Существует также папка examples с предварительно сгенерированными рабочими листами, если вы предпочитаете просто просмотреть полученные книги.

Рабочий лист выглядит так до применения любой сортировки / фильтрации:

enter image description here

Сортировка / фильтрация включены на листе с помощью:

sheet.setAutoFilter(new CellRangeAddress(sheet.getFirstRowNum(), sheet.getLastRowNum(), 0, 2));

Код (также в приведенной выше ссылке на github), который добавляет изображение:

        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 является решающим фактором, при значении MOVE_AND_RESIZE изображения не сортируются при использовании функции сортировки в фильтрах: enter image description here

Обратите внимание, что изображения больше не соответствуют столбцу «Текст». (Изображение с изображением «1» теперь рядом с текстом «Два»)

Если для imageAnchorType установлено значение MOVE_DONT_RESIZE, изображения сортируются соответствующим образом, но при применении фильтров, удаляющих строки изображений, изображения остаются: enter image description here

Мы применили фильтр для отображения столбцов «Только текст», поэтому данные строк «Один» и «Три» пропали, но их изображения остались.

Есть ли какие-либо другие свойства, которые я должен установить, чтобы это работало так, как я хочу?

1 Ответ

1 голос
/ 09 июля 2019

Проблема не только в типе якоря. Чтобы обеспечить как сортировку, так и фильтрацию, 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();

 }
}

Результат:

enter image description here

Возможна сортировка и фильтрация.

...