Работа со столбцами и строками

Чтобы лучше контролировать работу таблиц, узнайте, как манипулировать столбцами и строками.

Найдите индекс элемента таблицы

Управление столбцами, строками и ячейками осуществляется путем обращения к выбранному узлу документа по его индексу. Поиск индекса любого узла включает в себя сбор всех дочерних узлов типа element из родительского узла, а затем использование метода IndexOf для поиска индекса нужного узла в коллекции.

Найдите индекс таблицы в документе

Иногда вам может потребоваться внести изменения в определенную таблицу в документе. Для этого вы можете обратиться к таблице по ее индексу.

В следующем примере кода показано, как получить индекс таблицы в документе:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
auto table = System::ExplicitCast<Table>(doc->GetChild(NodeType::Table, 0, true));
SharedPtr<NodeCollection> allTables = doc->GetChildNodes(NodeType::Table, true);
int tableIndex = allTables->IndexOf(table);

Найдите индекс строки в таблице

Аналогичным образом, вам может потребоваться внести изменения в определенную строку в выбранной таблице. Для этого вы также можете обратиться к строке по ее индексу.

В следующем примере кода показано, как получить индекс строки в таблице:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
int rowIndex = table->IndexOf(table->get_LastRow());

Найдите индекс ячейки в строке

Наконец, вам может потребоваться внести изменения в определенную ячейку, и вы также можете сделать это с помощью индекса ячейки.

В следующем примере кода показано, как получить индекс ячейки в строке:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
int cellIndex = row->IndexOf(row->get_Cells()->idx_get(4));

Работа с колонками

В объектной модели документа Aspose.Words (DOM) узел Table состоит из Row узлов, а затем из Cell узлов. Таким образом, в объектной модели документа Aspose.Words, как и в документах Word, отсутствует понятие столбца.

По замыслу, строки таблицы в Microsoft Word и Aspose.Words полностью независимы друг от друга, а основные свойства и операции содержатся только в строках и ячейках таблицы. Это позволяет таблицам иметь некоторые интересные атрибуты:

  • Каждая строка таблицы может содержать совершенно разное количество ячеек
  • По вертикали ячейки каждой строки могут иметь разную ширину
  • Можно объединять таблицы с разными форматами строк и количеством ячеек

Любые операции, выполняемые со столбцами, на самом деле являются “сокращениями”, которые выполняют операцию путем коллективного изменения ячеек строк таким образом, что это выглядит так, как будто они применяются к столбцам. То есть вы можете выполнять операции со столбцами, просто повторяя индекс одной и той же ячейки строки таблицы.

Следующий пример кода упрощает такие операции, демонстрируя класс facade, который собирает ячейки, составляющие “столбец” таблицы:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
/// <summary>
/// Represents a facade object for a column of a table in a Microsoft Word document.
/// </summary>
class Column : public System::Object
{
public:
/// <summary>
/// Returns the cells which make up the column.
/// </summary>
ArrayPtr<SharedPtr<Cell>> get_Cells()
{
return GetColumnCells()->ToArray();
}
/// <summary>
/// Returns a new column facade from the table and supplied zero-based index.
/// </summary>
static SharedPtr<WorkingWithTables::Column> FromIndex(SharedPtr<Table> table, int columnIndex)
{
return WorkingWithTables::Column::MakeObject(table, columnIndex);
}
/// <summary>
/// Returns the index of the given cell in the column.
/// </summary>
int IndexOf(SharedPtr<Cell> cell)
{
return GetColumnCells()->IndexOf(cell);
}
/// <summary>
/// Inserts a brand new column before this column into the table.
/// </summary>
SharedPtr<WorkingWithTables::Column> InsertColumnBefore()
{
ArrayPtr<SharedPtr<Cell>> columnCells = get_Cells();
if (columnCells->get_Length() == 0)
{
throw System::ArgumentException(u"Column must not be empty");
}
// Create a clone of this column.
for (SharedPtr<Cell> cell : columnCells)
{
cell->get_ParentRow()->InsertBefore(cell->Clone(false), cell);
}
// This is the new column.
auto column = WorkingWithTables::Column::MakeObject(columnCells[0]->get_ParentRow()->get_ParentTable(), mColumnIndex);
// We want to make sure that the cells are all valid to work with (have at least one paragraph).
for (SharedPtr<Cell> cell : column->get_Cells())
{
cell->EnsureMinimum();
}
// Increase the index which this column represents since there is now one extra column in front.
mColumnIndex++;
return column;
}
/// <summary>
/// Removes the column from the table.
/// </summary>
void Remove()
{
for (SharedPtr<Cell> cell : get_Cells())
{
cell->Remove();
}
}
/// <summary>
/// Returns the text of the column.
/// </summary>
String ToTxt()
{
auto builder = System::MakeObject<System::Text::StringBuilder>();
for (SharedPtr<Cell> cell : get_Cells())
{
builder->Append(cell->ToString(SaveFormat::Text));
}
return builder->ToString();
}
private:
int mColumnIndex;
SharedPtr<Table> mTable;
Column(SharedPtr<Table> table, int columnIndex) : mColumnIndex(0)
{
if (table == nullptr)
{
throw System::ArgumentException(u"table");
}
mTable = table;
mColumnIndex = columnIndex;
}
MEMBER_FUNCTION_MAKE_OBJECT(Column, CODEPORTING_ARGS(SharedPtr<Table> table, int columnIndex), CODEPORTING_ARGS(table, columnIndex));
/// <summary>
/// Provides an up-to-date collection of cells which make up the column represented by this facade.
/// </summary>
SharedPtr<System::Collections::Generic::List<SharedPtr<Cell>>> GetColumnCells()
{
SharedPtr<System::Collections::Generic::List<SharedPtr<Cell>>> columnCells =
System::MakeObject<System::Collections::Generic::List<SharedPtr<Cell>>>();
for (const auto& row : System::IterateOver<Row>(mTable->get_Rows()))
{
SharedPtr<Cell> cell = row->get_Cells()->idx_get(mColumnIndex);
if (cell != nullptr)
{
columnCells->Add(cell);
}
}
return columnCells;
}
};
view raw column-class.h hosted with ❤ by GitHub

В следующем примере кода показано, как вставить пустой столбец в таблицу:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
auto doc = MakeObject<Document>(MyDir + u"Tables.docx");
auto table = System::ExplicitCast<Table>(doc->GetChild(NodeType::Table, 0, true));
SharedPtr<WorkingWithTables::Column> column = WorkingWithTables::Column::FromIndex(table, 0);
// Print the plain text of the column to the screen.
std::cout << column->ToTxt() << std::endl;
// Create a new column to the left of this column.
// This is the same as using the "Insert Column Before" command in Microsoft Word.
SharedPtr<WorkingWithTables::Column> newColumn = column->InsertColumnBefore();
for (SharedPtr<Cell> cell : newColumn->get_Cells())
{
cell->get_FirstParagraph()->AppendChild(MakeObject<Run>(doc, String(u"Column Text ") + newColumn->IndexOf(cell)));
}

В следующем примере кода показано, как удалить столбец из таблицы в документе:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
auto doc = MakeObject<Document>(MyDir + u"Tables.docx");
auto table = System::ExplicitCast<Table>(doc->GetChild(NodeType::Table, 1, true));
SharedPtr<WorkingWithTables::Column> column = WorkingWithTables::Column::FromIndex(table, 2);
column->Remove();
view raw remove-column.h hosted with ❤ by GitHub

Укажите строки в качестве строк заголовка

Вы можете выбрать повторение первой строки таблицы в качестве строки заголовка только на первой странице или на каждой странице, если таблица разделена на несколько частей. В Aspose.Words вы можете повторять строку заголовка на каждой странице, используя свойство HeadingFormat.

Вы также можете пометить несколько строк заголовка, если такие строки расположены одна за другой в начале таблицы. Для этого вам необходимо применить к этим строкам свойства HeadingFormat.

В следующем примере кода показано, как создать таблицу, включающую строки заголовка, которые повторяются на последующих страницах:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
auto doc = MakeObject<Document>();
auto builder = MakeObject<DocumentBuilder>(doc);
builder->StartTable();
builder->get_RowFormat()->set_HeadingFormat(true);
builder->get_ParagraphFormat()->set_Alignment(ParagraphAlignment::Center);
builder->get_CellFormat()->set_Width(100);
builder->InsertCell();
builder->Writeln(u"Heading row 1");
builder->EndRow();
builder->InsertCell();
builder->Writeln(u"Heading row 2");
builder->EndRow();
builder->get_CellFormat()->set_Width(50);
builder->get_ParagraphFormat()->ClearFormatting();
for (int i = 0; i < 50; i++)
{
builder->InsertCell();
builder->get_RowFormat()->set_HeadingFormat(false);
builder->Write(u"Column 1 Text");
builder->InsertCell();
builder->Write(u"Column 2 Text");
builder->EndRow();
}
doc->Save(ArtifactsDir + u"WorkingWithTables.RepeatRowsOnSubsequentPages.docx");

Следите за тем, чтобы таблицы и строки не разбивались по страницам

В некоторых случаях содержимое таблицы не должно быть разделено по страницам. Например, если заголовок находится над таблицей, заголовок и таблица всегда должны располагаться вместе на одной странице, чтобы сохранить надлежащий внешний вид.

Есть два отдельных метода, которые полезны для достижения этой функциональности:

  • Allow row break across pages, который применяется к строкам таблицы
  • Keep with next, который применяется к абзацам в ячейках таблицы

По умолчанию вышеуказанные свойства отключены.

Следите за тем, чтобы строка не разбивалась на страницы

Это включает в себя ограничение разбиения содержимого внутри ячеек строки на страницы. В Microsoft Word это можно найти в разделе “Свойства таблицы” в качестве опции “Разрешить разбиение строки на страницы”. В Aspose.Words это находится в RowFormat объекте Row как свойство RowFormat.AllowBreakAcrossPages.

В следующем примере кода показано, как отключить разбиение строк по страницам для каждой строки таблицы:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
auto doc = MakeObject<Document>(MyDir + u"Table spanning two pages.docx");
auto table = System::ExplicitCast<Table>(doc->GetChild(NodeType::Table, 0, true));
// Disable breaking across pages for all rows in the table.
for (const auto& row : System::IterateOver<Row>(table->get_Rows()))
{
row->get_RowFormat()->set_AllowBreakAcrossPages(false);
}
doc->Save(ArtifactsDir + u"WorkingWithTables.RowFormatDisableBreakAcrossPages.docx");

Следите за тем, чтобы таблица не разбивалась на страницы

Чтобы таблица не разбивалась на страницы, нам нужно указать, что мы хотим, чтобы содержимое, содержащееся в таблице, оставалось единым.

Для этого в Aspose.Words используется метод, который позволяет пользователям выбирать таблицу и устанавливать для параметра KeepWithNext значение true для каждого абзаца в ячейках таблицы. Исключением является последний абзац в таблице, для которого должно быть установлено значение false.

В следующем примере кода показано, как настроить таблицу так, чтобы она оставалась вместе на одной странице:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git.
auto doc = MakeObject<Document>(MyDir + u"Table spanning two pages.docx");
auto table = System::ExplicitCast<Table>(doc->GetChild(NodeType::Table, 0, true));
// We need to enable KeepWithNext for every paragraph in the table to keep it from breaking across a page,
// except for the last paragraphs in the last row of the table.
for (const auto& cell : System::IterateOver<Cell>(table->GetChildNodes(NodeType::Cell, true)))
{
cell->EnsureMinimum();
for (const auto& para : System::IterateOver<Paragraph>(cell->get_Paragraphs()))
{
if (!(cell->get_ParentRow()->get_IsLastRow() && para->get_IsEndOfCell()))
{
para->get_ParagraphFormat()->set_KeepWithNext(true);
}
}
}
doc->Save(ArtifactsDir + u"WorkingWithTables.KeepTableTogether.docx");