Hợp Nhất Các Ô Bảng
Đôi khi một số hàng nhất định trong bảng yêu cầu một tiêu đề hoặc các khối văn bản lớn chiếm toàn bộ chiều rộng của bảng. Để thiết kế bảng phù hợp, người dùng có thể hợp nhất một số ô bảng thành một. Aspose.Words hỗ trợ các ô được hợp nhất khi làm việc với tất cả các định dạng đầu vào, bao gồm nhập nội dung HTML.
Cách Hợp Nhất Các Ô Bảng
Trong Aspose.Words, các ô được hợp nhất được biểu thị bằng các thuộc tính sau của lớp CellFormat:
- HorizontalMerge mô tả nếu ô là một phần của sự hợp nhất ngang của các ô
- VerticalMerge mô tả nếu ô là một phần của sự hợp nhất theo chiều dọc của các ô
Các giá trị của các thuộc tính này xác định hành vi hợp nhất của các ô:
- Ô đầu tiên trong một chuỗi các ô được hợp nhất sẽ có CellMerge.First
- Bất kỳ ô nào được hợp nhất sau đó sẽ có CellMerge.Previous
- Một ô không được hợp nhất sẽ có CellMerge.None
Kiểm tra Xem Ô có được Hợp nhất hay không
Để kiểm tra xem một ô có phải là một phần của chuỗi các ô được hợp nhất hay không, chúng tôi chỉ cần kiểm tra các thuộc tính HorizontalMerge và VerticalMerge.
Ví dụ mã sau đây cho thấy cách in kiểu hợp nhất ô ngang và dọc:
// 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 with merged cells.docx"); | |
auto table = System::ExplicitCast<Table>(doc->GetChild(NodeType::Table, 0, true)); | |
for (const auto& row : System::IterateOver<Row>(table->get_Rows())) | |
{ | |
for (const auto& cell : System::IterateOver<Cell>(row->get_Cells())) | |
{ | |
std::cout << PrintCellMergeType(cell) << std::endl; | |
} | |
} |
Các Ô được hợp nhất trong Một Bảng
Để hợp nhất các ô trong bảng được tạo bằng DocumentBuilder, bạn cần đặt kiểu hợp nhất thích hợp cho mỗi ô nơi dự kiến hợp nhất – đầu tiên CellMerge.First và sau đó CellMerge.Previous.
Ngoài ra, bạn phải nhớ xóa cài đặt hợp nhất cho các ô không cần hợp nhất – điều này có thể được thực hiện bằng cách đặt ô không hợp nhất đầu tiên thành CellMerge.None. Nếu điều này không được thực hiện, tất cả các ô trong bảng sẽ được hợp nhất.
Ví dụ mã sau đây cho thấy cách tạo một bảng có hai hàng trong đó các ô trong hàng đầu tiên được hợp nhất theo chiều ngang:
// 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->InsertCell(); | |
builder->get_CellFormat()->set_HorizontalMerge(CellMerge::First); | |
builder->Write(u"Text in merged cells."); | |
builder->InsertCell(); | |
// This cell is merged to the previous and should be empty. | |
builder->get_CellFormat()->set_HorizontalMerge(CellMerge::Previous); | |
builder->EndRow(); | |
builder->InsertCell(); | |
builder->get_CellFormat()->set_HorizontalMerge(CellMerge::None); | |
builder->Write(u"Text in one cell."); | |
builder->InsertCell(); | |
builder->Write(u"Text in another cell."); | |
builder->EndRow(); | |
builder->EndTable(); | |
doc->Save(ArtifactsDir + u"WorkingWithTables.HorizontalMerge.docx"); |
Ví dụ mã sau đây cho thấy cách tạo bảng hai cột trong đó các ô trong cột đầu tiên được hợp nhất theo chiều dọc:
// 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->InsertCell(); | |
builder->get_CellFormat()->set_VerticalMerge(CellMerge::First); | |
builder->Write(u"Text in merged cells."); | |
builder->InsertCell(); | |
builder->get_CellFormat()->set_VerticalMerge(CellMerge::None); | |
builder->Write(u"Text in one cell"); | |
builder->EndRow(); | |
builder->InsertCell(); | |
// This cell is vertically merged to the cell above and should be empty. | |
builder->get_CellFormat()->set_VerticalMerge(CellMerge::Previous); | |
builder->InsertCell(); | |
builder->get_CellFormat()->set_VerticalMerge(CellMerge::None); | |
builder->Write(u"Text in another cell"); | |
builder->EndRow(); | |
builder->EndTable(); | |
doc->Save(ArtifactsDir + u"WorkingWithTables.VerticalMerge.docx"); |
Hợp Nhất Các Ô Bảng Trong Các Trường hợp khác
Trong các tình huống khác mà DocumentBuilder không được sử dụng, chẳng hạn như trong bảng hiện có, việc hợp nhất các ô theo cách trước đó có thể không dễ dàng như vậy. Thay vào đó, chúng ta có thể bọc các hoạt động cơ bản liên quan đến việc áp dụng các thuộc tính hợp nhất cho các ô trong một phương thức giúp nhiệm vụ dễ dàng hơn nhiều. Phương thức này tương tự như Phương thức Tự động Hóa Hợp nhất, được gọi để hợp nhất một loạt các ô trong bảng.
Mã dưới đây sẽ hợp nhất các ô bảng trong phạm vi được chỉ định, bắt đầu từ ô đã cho và kết thúc ở ô cuối. Trong trường hợp này, phạm vi có thể kéo dài nhiều hàng hoặc cột:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git. | |
void MergeCells(SharedPtr<Cell> startCell, SharedPtr<Cell> endCell) | |
{ | |
SharedPtr<Table> parentTable = startCell->get_ParentRow()->get_ParentTable(); | |
// Find the row and cell indices for the start and end cell. | |
System::Drawing::Point startCellPos(startCell->get_ParentRow()->IndexOf(startCell), parentTable->IndexOf(startCell->get_ParentRow())); | |
System::Drawing::Point endCellPos(endCell->get_ParentRow()->IndexOf(endCell), parentTable->IndexOf(endCell->get_ParentRow())); | |
// Create a range of cells to be merged based on these indices. | |
// Inverse each index if the end cell is before the start cell. | |
System::Drawing::Rectangle mergeRange( | |
System::Math::Min(startCellPos.get_X(), endCellPos.get_X()), System::Math::Min(startCellPos.get_Y(), endCellPos.get_Y()), | |
System::Math::Abs(endCellPos.get_X() - startCellPos.get_X()) + 1, System::Math::Abs(endCellPos.get_Y() - startCellPos.get_Y()) + 1); | |
for (const auto& row : System::IterateOver<Row>(parentTable->get_Rows())) | |
{ | |
for (const auto& cell : System::IterateOver<Cell>(row->get_Cells())) | |
{ | |
System::Drawing::Point currentPos(row->IndexOf(cell), parentTable->IndexOf(row)); | |
// Check if the current cell is inside our merge range, then merge it. | |
if (mergeRange.Contains(currentPos)) | |
{ | |
cell->get_CellFormat()->set_HorizontalMerge(currentPos.get_X() == mergeRange.get_X() ? CellMerge::First : CellMerge::Previous); | |
cell->get_CellFormat()->set_VerticalMerge(currentPos.get_Y() == mergeRange.get_Y() ? CellMerge::First : CellMerge::Previous); | |
} | |
} | |
} | |
} |
Ví dụ mã sau đây cho thấy cách hợp nhất một phạm vi ô giữa hai ô được chỉ định:
// 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 with merged cells.docx"); | |
SharedPtr<Table> table = doc->get_FirstSection()->get_Body()->get_Tables()->idx_get(0); | |
// We want to merge the range of cells found inbetween these two cells. | |
SharedPtr<Cell> cellStartRange = table->get_Rows()->idx_get(0)->get_Cells()->idx_get(0); | |
SharedPtr<Cell> cellEndRange = table->get_Rows()->idx_get(1)->get_Cells()->idx_get(1); | |
// Merge all the cells between the two specified cells into one. | |
MergeCells(cellStartRange, cellEndRange); | |
doc->Save(ArtifactsDir + u"WorkingWithTables.MergeCellRange.docx"); |
Tùy thuộc vào phiên bản Của Khung Bạn đang sử dụng, bạn có thể muốn tinh chỉnh phương thức này bằng cách biến nó thành một phương thức mở rộng. Trong trường hợp này, bạn có thể gọi phương thức này trực tiếp trên một ô để hợp nhất một phạm vi ô, chẳng hạn như cell1.Merge(cell2)
.
Các Ô được Hợp nhất dọc Và Ngang trong Bảng
Như chúng tôi đã nói trong các bài viết trước, một bảng trong Microsoft Word là một tập hợp các hàng độc lập. Mỗi hàng có một tập hợp các ô độc lập với các ô của các hàng khác. Do đó, trong bảng Microsoft Word không có đối tượng nào như “cột” và “cột1st” là một cái gì đó giống như “tập hợp các ô 1st của mỗi hàng trong bảng”. Điều này cho phép người dùng có một bảng trong đó, ví dụ, hàng 1st bao gồm hai ô – 2cm và 1cm và hàng 2nd bao gồm hai ô khác nhau – 1cm và 2cm rộng. Và Aspose.Words hỗ trợ khái niệm bảng này.
Một bảng trong HTML có cấu trúc cơ bản khác nhau: mỗi hàng có cùng số ô và (điều quan trọng đối với tác vụ) mỗi ô có chiều rộng của cột tương ứng, giống nhau cho tất cả các ô trong một cột. Vì vậy, nếu HorizontalMerge và VerticalMerge trả về một giá trị không chính xác, hãy sử dụng ví dụ mã sau:
// 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 with merged cells.docx"); | |
auto visitor = MakeObject<WorkingWithTables::SpanVisitor>(doc); | |
doc->Accept(visitor); |
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git. | |
/// <summary> | |
/// Helper class that contains collection of rowinfo for each row. | |
/// </summary> | |
class TableInfo : public System::Object | |
{ | |
public: | |
SharedPtr<System::Collections::Generic::List<SharedPtr<WorkingWithTables::RowInfo>>> get_Rows() | |
{ | |
return mRows; | |
} | |
TableInfo() : mRows(MakeObject<System::Collections::Generic::List<SharedPtr<WorkingWithTables::RowInfo>>>()) | |
{ | |
} | |
private: | |
SharedPtr<System::Collections::Generic::List<SharedPtr<WorkingWithTables::RowInfo>>> mRows; | |
}; | |
/// <summary> | |
/// Helper class that contains collection of cellinfo for each cell. | |
/// </summary> | |
class RowInfo : public System::Object | |
{ | |
public: | |
SharedPtr<System::Collections::Generic::List<SharedPtr<WorkingWithTables::CellInfo>>> get_Cells() | |
{ | |
return mCells; | |
} | |
RowInfo() : mCells(MakeObject<System::Collections::Generic::List<SharedPtr<WorkingWithTables::CellInfo>>>()) | |
{ | |
} | |
private: | |
SharedPtr<System::Collections::Generic::List<SharedPtr<WorkingWithTables::CellInfo>>> mCells; | |
}; | |
/// <summary> | |
/// Helper class that contains info about cell. currently here is only colspan and rowspan. | |
/// </summary> | |
class CellInfo : public System::Object | |
{ | |
public: | |
int get_ColSpan() | |
{ | |
return pr_ColSpan; | |
} | |
int get_RowSpan() | |
{ | |
return pr_RowSpan; | |
} | |
CellInfo(int colSpan, int rowSpan) : pr_ColSpan(0), pr_RowSpan(0) | |
{ | |
pr_ColSpan = colSpan; | |
pr_RowSpan = rowSpan; | |
} | |
private: | |
int pr_ColSpan; | |
int pr_RowSpan; | |
}; | |
class SpanVisitor : public DocumentVisitor | |
{ | |
public: | |
/// <summary> | |
/// Creates new SpanVisitor instance. | |
/// </summary> | |
/// <param name="doc"> | |
/// Is document which we should parse. | |
/// </param> | |
SpanVisitor(SharedPtr<Document> doc) : mTables(MakeObject<System::Collections::Generic::List<SharedPtr<WorkingWithTables::TableInfo>>>()) | |
{ | |
mWordTables = doc->GetChildNodes(NodeType::Table, true); | |
// We will parse HTML to determine the rowspan and colspan of each cell. | |
auto htmlStream = MakeObject<System::IO::MemoryStream>(); | |
auto options = MakeObject<Aspose::Words::Saving::HtmlSaveOptions>(); | |
options->set_ImagesFolder(System::IO::Path::GetTempPath()); | |
doc->Save(htmlStream, options); | |
// Load HTML into the XML document. | |
auto xmlDoc = MakeObject<System::Xml::XmlDocument>(); | |
htmlStream->set_Position(0); | |
xmlDoc->Load(htmlStream); | |
// Get collection of tables in the HTML document. | |
SharedPtr<System::Xml::XmlNodeList> tables = xmlDoc->get_DocumentElement()->GetElementsByTagName(u"table"); | |
for (const auto& table : System::IterateOver(tables)) | |
{ | |
auto tableInf = MakeObject<WorkingWithTables::TableInfo>(); | |
// Get collection of rows in the table. | |
SharedPtr<System::Xml::XmlNodeList> rows = table->SelectNodes(u"tr"); | |
for (const auto& row : System::IterateOver(rows)) | |
{ | |
auto rowInf = MakeObject<WorkingWithTables::RowInfo>(); | |
// Get collection of cells. | |
SharedPtr<System::Xml::XmlNodeList> cells = row->SelectNodes(u"td"); | |
for (const auto& cell : System::IterateOver(cells)) | |
{ | |
// Determine row span and colspan of the current cell. | |
SharedPtr<System::Xml::XmlAttribute> colSpanAttr = cell->get_Attributes()->idx_get(u"colspan"); | |
SharedPtr<System::Xml::XmlAttribute> rowSpanAttr = cell->get_Attributes()->idx_get(u"rowspan"); | |
int colSpan = colSpanAttr == nullptr ? 0 : System::Int32::Parse(colSpanAttr->get_Value()); | |
int rowSpan = rowSpanAttr == nullptr ? 0 : System::Int32::Parse(rowSpanAttr->get_Value()); | |
auto cellInf = MakeObject<WorkingWithTables::CellInfo>(colSpan, rowSpan); | |
rowInf->get_Cells()->Add(cellInf); | |
} | |
tableInf->get_Rows()->Add(rowInf); | |
} | |
mTables->Add(tableInf); | |
} | |
} | |
VisitorAction VisitCellStart(SharedPtr<Cell> cell) override | |
{ | |
int tabIdx = mWordTables->IndexOf(cell->get_ParentRow()->get_ParentTable()); | |
int rowIdx = cell->get_ParentRow()->get_ParentTable()->IndexOf(cell->get_ParentRow()); | |
int cellIdx = cell->get_ParentRow()->IndexOf(cell); | |
int colSpan = 0; | |
int rowSpan = 0; | |
if (tabIdx < mTables->get_Count() && rowIdx < mTables->idx_get(tabIdx)->get_Rows()->get_Count() && | |
cellIdx < mTables->idx_get(tabIdx)->get_Rows()->idx_get(rowIdx)->get_Cells()->get_Count()) | |
{ | |
colSpan = mTables->idx_get(tabIdx)->get_Rows()->idx_get(rowIdx)->get_Cells()->idx_get(cellIdx)->get_ColSpan(); | |
rowSpan = mTables->idx_get(tabIdx)->get_Rows()->idx_get(rowIdx)->get_Cells()->idx_get(cellIdx)->get_RowSpan(); | |
} | |
std::cout << tabIdx << "." << rowIdx << "." << cellIdx << " colspan=" << colSpan << "\t rowspan=" << rowSpan << std::endl; | |
return VisitorAction::Continue; | |
} | |
private: | |
SharedPtr<System::Collections::Generic::List<SharedPtr<WorkingWithTables::TableInfo>>> mTables; | |
SharedPtr<NodeCollection> mWordTables; | |
}; |
Chuyển đổi Sang Các Ô Được Hợp nhất Theo Chiều Ngang
Đôi khi không thể phát hiện ô nào được hợp nhất vì một số phiên bản mới hơn của Microsoft Word không còn sử dụng cờ hợp nhất khi các ô được hợp nhất theo chiều ngang. Nhưng đối với các tình huống mà các ô được hợp nhất thành một ô theo chiều ngang theo chiều rộng của chúng bằng cách sử dụng các cờ hợp nhất, Aspose.Words cung cấp phương thức ConvertToHorizontallyMergedCells
để chuyển đổi các ô. Phương pháp này chỉ đơn giản là biến đổi bảng và thêm các ô mới khi cần thiết.
Ví dụ mã sau đây cho thấy phương thức trên đang hoạt động:
// 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 with merged cells.docx"); | |
SharedPtr<Table> table = doc->get_FirstSection()->get_Body()->get_Tables()->idx_get(0); | |
// Now merged cells have appropriate merge flags. | |
table->ConvertToHorizontallyMergedCells(); |