ادغام سلول های جدول
گاهی اوقات ردیف های خاصی در یک جدول نیاز به یک عنوان یا بلوک های بزرگ متن دارند که عرض کامل جدول را اشغال می کنند. برای طراحی مناسب جدول، کاربر می تواند چندین سلول جدول را در یک ادغام کند. Aspose.Words از سلول های ادغام شده در هنگام کار با تمام فرمت های ورودی، از جمله وارد کردن محتوای HTML پشتیبانی می کند.
نحوه ادغام سلول های جدول
در Aspose.Words، سلول های ادغام شده با خواص زیر کلاس CellFormat نشان داده می شوند:
- HorizontalMerge که توضیح می دهد که آیا سلول بخشی از ادغام افقی سلول ها است
- VerticalMerge که توصیف می کند که آیا سلول بخشی از ادغام عمودی سلول ها است
مقادیر این خواص رفتار ادغام سلول ها را تعیین می کند:
- اولین سلول در یک دنباله از سلول های ادغام شده خواهد داشت CellMerge.First
- هر سلول ادغام شده بعدی CellMerge.Previousخواهد داشت
- سلولی که ادغام نشده باشد CellMerge.Noneخواهد داشت
بررسی کنید که آیا سلول ادغام شده است
برای بررسی اینکه آیا یک سلول بخشی از یک دنباله از سلول های ادغام شده است، ما به سادگی ویژگی های HorizontalMerge و VerticalMerge را بررسی می کنیم.
مثال کد زیر نشان می دهد که چگونه نوع ادغام سلول افقی و عمودی را چاپ کنیم:
// 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; | |
} | |
} |
سلول های ادغام شده در یک جدول
برای ادغام سلول ها در یک جدول ایجاد شده با DocumentBuilder، شما باید نوع ادغام مناسب را برای هر سلول که در آن ادغام انتظار می رود تنظیم کنید – ابتدا CellMerge.First و سپس CellMerge.Previous.
همچنین، باید به یاد داشته باشید که تنظیمات ادغام را برای سلول هایی که نیازی به ادغام ندارند پاک کنید – این کار را می توان با تنظیم اولین سلول غیر ادغام به CellMerge.None انجام داد. اگر این کار انجام نشود، تمام سلول های جدول با هم ادغام می شوند.
مثال کد زیر نشان می دهد که چگونه یک جدول با دو ردیف ایجاد کنیم که در آن سلول های ردیف اول به صورت افقی ادغام می شوند:
// 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"); |
مثال کد زیر نشان می دهد که چگونه یک جدول دو ستون ایجاد کنیم که در آن سلول های ستون اول به طور عمودی ادغام می شوند:
// 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"); |
سلول های جدول را در موارد دیگر ادغام کنید
در موقعیت های دیگر که DocumentBuilder استفاده نمی شود، مانند یک جدول موجود، ادغام سلول ها به روش قبلی ممکن است به همان اندازه آسان نباشد. در عوض، ما می توانیم عملیات اساسی مربوط به استفاده از خواص ادغام به سلول ها را به روشی که کار را بسیار آسان تر می کند، بسته بندی کنیم. این روش شبیه به روش اتوماسیون ادغام است که برای ادغام طیف وسیعی از سلول ها در یک جدول فراخوانده می شود.
کد زیر سلول های جدول را در محدوده مشخص شده ادغام می کند، از سلول داده شده شروع می شود و در سلول نهایی به پایان می رسد. در این حالت، محدوده می تواند چندین ردیف یا ستون را در بر بگیرد:
// 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); | |
} | |
} | |
} | |
} |
مثال کد زیر نشان می دهد که چگونه طیف وسیعی از سلول ها را بین دو سلول مشخص شده ادغام کنیم:
// 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"); |
بسته به نسخه چارچوبی که استفاده می کنید، ممکن است بخواهید این روش را با تبدیل آن به یک روش تمدید اصلاح کنید. در این حالت، می توانید این روش را مستقیما روی یک سلول فراخوانی کنید تا طیف وسیعی از سلول ها مانند cell1.Merge(cell2)
را ادغام کنید.
سلول های ادغام شده عمودی و افقی در یک جدول
همانطور که در مقالات قبلی گفتیم، جدول در Microsoft Word مجموعه ای از ردیف های مستقل است. هر ردیف دارای مجموعه ای از سلول هایی است که مستقل از سلول های ردیف های دیگر هستند. بنابراین، در جدول Microsoft Word چیزی به نام “ستون” وجود ندارد و “ستون1st” چیزی شبیه “مجموعه سلول های 1st هر ردیف در جدول"است. این به کاربران اجازه می دهد تا یک جدول داشته باشند که در آن، به عنوان مثال، ردیف 1st از دو سلول تشکیل شده است – 2سانتی متر و 1سانتی متر، و ردیف 2nd از دو سلول مختلف تشکیل شده است – 1سانتی متر و 2سانتی متر عرض. و Aspose.Words از این مفهوم جداول پشتیبانی می کند.
یک جدول در HTML دارای ساختار اساسا متفاوت است: هر ردیف دارای تعداد سلول های یکسان است و (برای کار مهم است) هر سلول دارای عرض ستون مربوطه است، برای همه سلول ها در یک ستون یکسان است. بنابراین اگر HorizontalMerge و VerticalMerge یک مقدار نادرست را برگردانند، از مثال کد زیر استفاده کنید:
// 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; | |
}; |
تبدیل به سلول های ادغام شده افقی
گاهی اوقات تشخیص اینکه کدام سلول ها ادغام می شوند امکان پذیر نیست زیرا برخی از نسخه های جدیدتر Microsoft Word دیگر از پرچم های ادغام استفاده نمی کنند وقتی سلول ها به صورت افقی ادغام می شوند. اما برای شرایطی که سلول ها با استفاده از پرچم های ادغام به صورت افقی با عرض خود به یک سلول ادغام می شوند، Aspose.Words روش ConvertToHorizontallyMergedCells
را برای تبدیل سلول ها فراهم می کند. این روش به سادگی جدول را تغییر می دهد و سلول های جدید را در صورت نیاز اضافه می کند.
مثال کد زیر روش بالا را در عمل نشان می دهد:
// 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(); |