Pracuj z kolumnami i wierszami

Aby uzyskać większą kontrolę nad działaniem tabel, dowiedz się, jak manipulować kolumnami i wierszami.

Znajdź indeks elementu tabeli

Kolumnami, wierszami i komórkami zarządza się, uzyskując dostęp do wybranego węzła dokumentu za pomocą jego indeksu. Znalezienie indeksu dowolnego węzła polega na zebraniu wszystkich węzłów potomnych typu elementu z węzła nadrzędnego, a następnie użyciu metody IndexOf w celu znalezienia indeksu żądanego węzła w kolekcji.

Znajdź indeks tabeli w dokumencie

Czasami może być konieczne wprowadzenie zmian w określonej tabeli w dokumencie. Aby to zrobić, możesz odwołać się do tabeli według jej indeksu.

Poniższy przykład kodu pokazuje, jak pobrać indeks tabeli w dokumencie:

// 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);

Znajdź indeks wiersza w tabeli

Podobnie może być konieczne wprowadzenie zmian w określonym wierszu w wybranej tabeli. Aby to zrobić, możesz również odwołać się do wiersza według jego indeksu.

Poniższy przykład kodu pokazuje, jak pobrać indeks wiersza w tabeli:

// 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());

Znajdź indeks komórki w wierszu

Na koniec może być konieczne wprowadzenie zmian w określonej komórce i możesz to zrobić również według indeksu komórki.

Poniższy przykład kodu pokazuje, jak pobrać indeks komórki z rzędu:

// 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));

Pracuj z kolumnami

W modelu obiektowym dokumentu Aspose.Words (DOM) węzeł Table składa się z węzłów Row, a następnie węzłów Cell. Tak więc w modelu obiektowym Document Aspose.Words, jak w dokumentach Word, nie ma pojęcia kolumny.

Z założenia wiersze tabeli w Microsoft Word i Aspose.Words są całkowicie niezależne, a podstawowe właściwości i operacje są zawarte tylko w wierszach i komórkach tabeli. Daje to tabelom możliwość posiadania interesujących atrybutów:

  • Każdy wiersz tabeli może mieć zupełnie inną liczbę komórek
  • W pionie komórki każdego rzędu mogą mieć różne szerokości
  • Możliwe jest łączenie tabel o różnych formatach wierszy i liczbie komórek

Wszelkie operacje wykonywane na kolumnach są w rzeczywistości “skrótami”, które wykonują operację poprzez zbiorową zmianę komórek wierszy w taki sposób, że wygląda na to, że są stosowane do kolumn. Oznacza to, że możesz wykonywać operacje na kolumnach, po prostu iterując po tym samym indeksie komórek wiersza tabeli.

Poniższy przykład kodu upraszcza takie operacje, udowadniając klasę fasady, która zbiera komórki tworzące “kolumnę” tabeli:

// 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

Poniższy przykład kodu pokazuje, jak wstawić pustą kolumnę do tabeli:

// 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)));
}

Poniższy przykład kodu pokazuje, jak usunąć kolumnę z tabeli w dokumencie:

// 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

Określ wiersze jako wiersze nagłówka

Możesz powtórzyć pierwszy wiersz w tabeli jako wiersz nagłówka tylko na pierwszej stronie lub na każdej stronie, jeśli tabela jest podzielona na kilka. W Aspose.Words możesz powtórzyć wiersz nagłówka na każdej stronie za pomocą właściwości HeadingFormat.

Możesz także zaznaczyć wiele wierszy nagłówka, jeśli takie wiersze znajdują się jeden po drugim na początku tabeli. Aby to zrobić, musisz zastosować właściwości HeadingFormat do tych wierszy.

Poniższy przykład kodu pokazuje, jak zbudować tabelę zawierającą wiersze nagłówka powtarzające się na kolejnych stronach:

// 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");

Zapobiegaj łamaniu tabel i wierszy na stronach

Są chwile, w których zawartość tabeli nie powinna być dzielona na strony. Na przykład, jeśli tytuł znajduje się nad tabelą, tytuł i tabela powinny być zawsze przechowywane razem na tej samej stronie, aby zachować odpowiedni wygląd.

Istnieją dwie oddzielne techniki, które są przydatne do osiągnięcia tej funkcjonalności:

  • Allow row break across pages, który jest stosowany do wierszy tabeli
  • Keep with next, który jest stosowany do akapitów w komórkach tabeli

Domyślnie powyższe właściwości są wyłączone.

Nie przerywaj wiersza na stronach

Polega to na ograniczeniu zawartości wewnątrz komórek wiersza przed podziałem na stronę. W Microsoft Word można to znaleźć w sekcji Właściwości tabeli jako opcję “Zezwalaj wierszowi na dzielenie stron”. W Aspose.Words to znajduje się pod RowFormat obiekt a Row jako właściwość RowFormat.AllowBreakAcrossPages.

Poniższy przykład kodu pokazuje, jak wyłączyć dzielenie wierszy na stronach dla każdego wiersza w tabeli:

// 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");

Nie przerywaj tabeli na stronach

Aby zatrzymać podział tabeli na strony, musimy określić, że chcemy, aby zawartość zawarta w tabeli pozostała razem.

Aby to zrobić, Aspose.Words używa metody, która pozwala użytkownikom wybrać tabelę i włączyć parametr KeepWithNext do wartości true dla każdego akapitu w komórkach tabeli. Wyjątkiem jest ostatni akapit w tabeli, który powinien być ustawiony na false.

Poniższy przykład kodu pokazuje, jak ustawić tabelę, aby pozostać razem na tej samej stronie:

// 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");