Îmbinați Celulele Tabelului
Uneori, anumite rânduri dintr-un tabel necesită un titlu sau blocuri mari de text care ocupă întreaga lățime a tabelului. Pentru proiectarea corectă a tabelului, utilizatorul poate îmbina mai multe celule de tabel într-una. Aspose.Words acceptă celule îmbinate atunci când lucrați cu toate formatele de intrare, inclusiv importul de conținut HTML.
Cum să îmbinați celulele tabelului
În Aspose.Words, celulele fuzionate sunt reprezentate de următoarele proprietăți ale clasei CellFormat:
- HorizontalMerge care descrie dacă celula este o parte a unei fuziuni orizontale de celule
- VerticalMerge care descrie dacă celula este o parte a unei fuziuni verticale de celule
Valorile acestor proprietăți determină comportamentul de îmbinare al celulelor:
- Prima celulă dintr-o secvență de celule fuzionate va avea CellMerge.First
- Orice celule fuzionate ulterior vor avea CellMerge.Previous
- O celulă care nu este îmbinată va avea CellMerge.None
Verificarea dacă o celulă este îmbinată
Pentru a verifica dacă o celulă face parte dintr-o secvență de celule îmbinate, verificăm pur și simplu proprietățile HorizontalMerge și VerticalMerge.
Următorul exemplu de cod arată cum să imprimați tipul de îmbinare a celulelor orizontale și verticale:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
Document doc = new Document(getMyDir() + "Table with merged cells.docx"); | |
Table table = (Table) doc.getChild(NodeType.TABLE, 0, true); | |
for (Row row : (Iterable<Row>) table.getRows()) | |
{ | |
for (Cell cell : (Iterable<Cell>) row.getCells()) | |
{ | |
System.out.println(printCellMergeType(cell)); | |
} | |
} |
Îmbinați Celulele Tabelului Atunci Când Utilizați DocumentBuilder
Pentru a îmbina celulele într – un tabel creat cu DocumentBuilder, trebuie să setați tipul de îmbinare corespunzător pentru fiecare celulă în care se așteaptă îmbinarea-mai întâi CellMerge.First și apoi CellMerge.Previous.
De asemenea, trebuie să vă amintiți să ștergeți setarea de îmbinare pentru acele celule în care nu este necesară îmbinarea – acest lucru se poate face prin setarea primei celule care nu merge la CellMerge.None. Dacă acest lucru nu se face, toate celulele din tabel vor fi îmbinate.
Următorul exemplu de cod arată cum se creează un tabel cu două rânduri în care celulele din primul rând sunt îmbinate orizontal:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
Document doc = new Document(); | |
DocumentBuilder builder = new DocumentBuilder(doc); | |
builder.insertCell(); | |
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST); | |
builder.write("Text in merged cells."); | |
builder.insertCell(); | |
// This cell is merged to the previous and should be empty. | |
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS); | |
builder.endRow(); | |
builder.insertCell(); | |
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE); | |
builder.write("Text in one cell."); | |
builder.insertCell(); | |
builder.write("Text in another cell."); | |
builder.endRow(); | |
builder.endTable(); | |
doc.save(getArtifactsDir() + "WorkingWithTables.HorizontalMerge.docx"); |
Următorul exemplu de cod arată cum se creează un tabel cu două coloane în care celulele din prima coloană sunt îmbinate vertical:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
Document doc = new Document(); | |
DocumentBuilder builder = new DocumentBuilder(doc); | |
builder.insertCell(); | |
builder.getCellFormat().setVerticalMerge(CellMerge.FIRST); | |
builder.write("Text in merged cells."); | |
builder.insertCell(); | |
builder.getCellFormat().setVerticalMerge(CellMerge.NONE); | |
builder.write("Text in one cell"); | |
builder.endRow(); | |
builder.insertCell(); | |
// This cell is vertically merged to the cell above and should be empty. | |
builder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS); | |
builder.insertCell(); | |
builder.getCellFormat().setVerticalMerge(CellMerge.NONE); | |
builder.write("Text in another cell"); | |
builder.endRow(); | |
builder.endTable(); | |
doc.save(getArtifactsDir() + "WorkingWithTables.VerticalMerge.docx"); |
Îmbinați celulele tabelului în alte cazuri
În alte situații în care DocumentBuilder nu este utilizat, cum ar fi într-un tabel existent, fuziunea celulelor în modul anterior poate să nu fie la fel de ușoară. În schimb, putem înfășura operațiile de bază implicate în aplicarea proprietăților de îmbinare celulelor într-o metodă care face sarcina mult mai ușoară. Această metodă este similară cu metoda de automatizare a fuziunii, care este chemată să fuzioneze o gamă de celule dintr-un tabel.
Codul de mai jos va îmbina celulele tabelului în intervalul specificat, începând de la celula dată și terminând la celula finală. În acest caz, intervalul poate cuprinde mai multe rânduri sau coloane:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
void mergeCells(Cell startCell, Cell endCell) | |
{ | |
Table parentTable = startCell.getParentRow().getParentTable(); | |
// Find the row and cell indices for the start and end cell. | |
Point startCellPos = new Point(startCell.getParentRow().indexOf(startCell), | |
parentTable.indexOf(startCell.getParentRow())); | |
Point endCellPos = new Point(endCell.getParentRow().indexOf(endCell), parentTable.indexOf(endCell.getParentRow())); | |
// Create a range of cells to be merged based on these indices. | |
// Inverse each index if the end cell is before the start cell. | |
Rectangle mergeRange = new Rectangle(Math.min(startCellPos.x, endCellPos.y), | |
Math.min(startCellPos.y, endCellPos.y), | |
Math.abs(endCellPos.x - startCellPos.x) + 1, Math.abs(endCellPos.y - startCellPos.y) + 1); | |
for (Row row : parentTable.getRows()) | |
{ | |
for (Cell cell : row.getCells()) | |
{ | |
Point currentPos = new Point(row.indexOf(cell), parentTable.indexOf(row)); | |
// Check if the current cell is inside our merge range, then merge it. | |
if (mergeRange.contains(currentPos)) | |
{ | |
cell.getCellFormat().setHorizontalMerge(currentPos.x == mergeRange.getX() ? CellMerge.FIRST : CellMerge.PREVIOUS); | |
cell.getCellFormat().setVerticalMerge(currentPos.y == mergeRange.getY() ? CellMerge.FIRST : CellMerge.PREVIOUS); | |
} | |
} | |
} | |
} |
Următorul exemplu de cod arată cum să îmbinați o gamă de celule între două celule specificate:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
Document doc = new Document(getMyDir() + "Table with merged cells.docx"); | |
Table table = doc.getFirstSection().getBody().getTables().get(0); | |
// We want to merge the range of cells found inbetween these two cells. | |
Cell cellStartRange = table.getRows().get(0).getCells().get(0); | |
Cell cellEndRange = table.getRows().get(1).getCells().get(1); | |
// Merge all the cells between the two specified cells into one. | |
mergeCells(cellStartRange, cellEndRange); | |
doc.save(getArtifactsDir() + "WorkingWithTables.MergeCellRange.docx"); |
Celule combinate verticale și orizontale în tabelul HTML
După cum am spus în articolele anterioare, un tabel în Microsoft Word este un set de rânduri independente. Fiecare rând are un set de celule care sunt independente de celulele altor rânduri. Astfel, în tabelul Microsoft Word nu există un astfel de obiect ca o “coloană”, iar “coloana 1” este ceva de genul “setul celulelor 1 ale fiecărui rând din tabel”. Acest lucru permite utilizatorilor să aibă un tabel în care, de exemplu, rândul 1 este format din două celule – 2cm și 1cm, iar rândul 2 este format din două celule diferite – 1cm și 2cm lățime. Și Aspose.Words susține acest concept de tabele.
Un tabel din HTML are o structură esențial diferită: fiecare rând are același număr de celule și (este important pentru sarcină) fiecare celulă are lățimea coloanei corespunzătoare, aceeași pentru toate celulele dintr-o singură coloană. Deci, dacă HorizontalMerge și VerticalMerge returnează o valoare incorectă, utilizați următorul exemplu de cod:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
Document doc = new Document(getMyDir() + "Table with merged cells.docx"); | |
SpanVisitor visitor = new SpanVisitor(doc); | |
doc.accept(visitor); |
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
/// <summary> | |
/// Helper class that contains collection of rowinfo for each row. | |
/// </summary> | |
public static class TableInfo | |
{ | |
public ArrayList<RowInfo> getRows() { return mRows; } | |
private ArrayList<RowInfo> mRows = new ArrayList<>(); | |
} | |
/// <summary> | |
/// Helper class that contains collection of cellinfo for each cell. | |
/// </summary> | |
public static class RowInfo | |
{ | |
public ArrayList<CellInfo> getCells() { return mCells; }; | |
private ArrayList<CellInfo> mCells = new ArrayList<>(); | |
} | |
/// <summary> | |
/// Helper class that contains info about cell. currently here is only colspan and rowspan. | |
/// </summary> | |
public static class CellInfo | |
{ | |
public CellInfo(int colSpan, int rowSpan) | |
{ | |
mColSpan = colSpan; | |
mRowSpan = rowSpan; | |
} | |
public int getColSpan() { return mColSpan; }; | |
private int mColSpan; | |
public int getRowSpan() { return mRowSpan; }; | |
private int mRowSpan; | |
} | |
public static class SpanVisitor extends DocumentVisitor | |
{ | |
/// <summary> | |
/// Creates new SpanVisitor instance. | |
/// </summary> | |
/// <param name="doc"> | |
/// Is document which we should parse. | |
/// </param> | |
public SpanVisitor(Document doc) throws Exception { | |
mWordTables = doc.getChildNodes(NodeType.TABLE, true); | |
// We will parse HTML to determine the rowspan and colspan of each cell. | |
ByteArrayOutputStream htmlStream = new ByteArrayOutputStream(); | |
HtmlSaveOptions options = new HtmlSaveOptions(); | |
{ | |
options.setImagesFolder(System.getProperty("java.io.tmpdir")); | |
} | |
doc.save(htmlStream, options); | |
// Load HTML into the XML document. | |
org.jsoup.nodes.Document document = Jsoup.parse(htmlStream.toString()); | |
// Get collection of tables in the HTML document. | |
Elements tables = document.getElementsByTag("table"); | |
for (Element table : tables) { | |
TableInfo tableInf = new TableInfo(); | |
// Get collection of rows in the table. | |
Elements rows = table.getElementsByTag("tr"); | |
for (Element row : rows) { | |
RowInfo rowInf = new RowInfo(); | |
// Get collection of cells. | |
Elements cells = row.getElementsByTag("td"); | |
for (Element cell : cells) { | |
// Determine row span and colspan of the current cell. | |
String colSpanAttr = cell.attributes().get("colspan"); | |
String rowSpanAttr = cell.attributes().get("rowspan"); | |
int colSpan = StringUtils.isNotBlank(colSpanAttr) ? Integer.parseInt(colSpanAttr) : 0; | |
int rowSpan = StringUtils.isNotBlank(rowSpanAttr) ? Integer.parseInt(rowSpanAttr) : 0; | |
CellInfo cellInf = new CellInfo(colSpan, rowSpan); | |
rowInf.getCells().add(cellInf); | |
} | |
tableInf.getRows().add(rowInf); | |
} | |
mTables.add(tableInf); | |
} | |
} | |
public int visitCellStart(Cell cell) | |
{ | |
int tabIdx = mWordTables.indexOf(cell.getParentRow().getParentTable()); | |
int rowIdx = cell.getParentRow().getParentTable().indexOf(cell.getParentRow()); | |
int cellIdx = cell.getParentRow().indexOf(cell); | |
int colSpan = 0; | |
int rowSpan = 0; | |
if (tabIdx < mTables.size() && | |
rowIdx < mTables.get(tabIdx).getRows().size() && | |
cellIdx < mTables.get(tabIdx).getRows().get(rowIdx).getCells().size()) | |
{ | |
colSpan = mTables.get(tabIdx).getRows().get(rowIdx).getCells().get(cellIdx).getColSpan(); | |
rowSpan = mTables.get(tabIdx).getRows().get(rowIdx).getCells().get(cellIdx).getRowSpan(); | |
} | |
System.out.println(MessageFormat.format("{0}.{1}.{2} colspan={3}\t rowspan={4}", tabIdx, rowIdx, cellIdx, colSpan, rowSpan)); | |
return VisitorAction.CONTINUE; | |
} | |
private ArrayList<TableInfo> mTables = new ArrayList<>(); | |
private NodeCollection mWordTables; | |
} |
Convertiți în celule fuzionate orizontal
Uneori nu este posibil să se detecteze care celule sunt fuzionate deoarece unele versiuni mai noi ale Microsoft Word nu mai folosesc steagurile de îmbinare atunci când celulele sunt fuzionate orizontal. Dar pentru situațiile în care celulele sunt fuzionate într-o celulă orizontal prin lățimea lor folosind steaguri de îmbinare, Aspose.Words oferă metoda ConvertToHorizontallyMergedCells
pentru a converti celulele. Această metodă transformă pur și simplu tabelul și adaugă celule noi după cum este necesar.
Următorul exemplu de cod arată metoda de mai sus în funcțiune:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git. | |
Document doc = new Document(getMyDir() + "Table with merged cells.docx"); | |
Table table = doc.getFirstSection().getBody().getTables().get(0); | |
// Now merged cells have appropriate merge flags. | |
table.convertToHorizontallyMergedCells(); |