Tablo Hücrelerini Birleştir

Bazen bir tablodaki belirli satırlar, tablonun tüm genişliğini kaplayan bir başlık veya büyük metin blokları gerektirir. Tablonun doğru tasarımı için, kullanıcı birkaç tablo hücresini bir araya getirebilir. Aspose.Words HTML içeriğin içe aktarılması da dahil olmak üzere tüm giriş biçimleriyle çalışırken birleştirilmiş hücreleri destekler.

Tablo Hücreleri Nasıl Birleştirilir

Aspose.Words’de, birleştirilmiş hücreler CellFormat sınıfının aşağıdaki özellikleriyle temsil edilir:

  • HorizontalMerge hücrenin yatay hücre birleşmesinin bir parçası olup olmadığını açıklar
  • VerticalMerge hücrenin dikey hücre birleşmesinin bir parçası olup olmadığını açıklar

Bu özelliklerin değerleri, hücrelerin birleştirme davranışını belirler:

  • Birleştirilmiş hücreler dizisindeki ilk hücre CellMerge.First değerine sahip olacaktır
  • Sonradan birleştirilen tüm hücreler CellMerge.Previous değerine sahip olacaktır
  • Birleştirilmemiş bir hücrede CellMerge.None olacaktır

Hücrenin Birleştirilip Birleştirilmediğini kontrol edin

Bir hücrenin birleştirilmiş hücreler dizisinin bir parçası olup olmadığını kontrol etmek için HorizontalMerge ve VerticalMerge özelliklerini kontrol etmemiz yeterlidir.

Aşağıdaki kod örneği, yatay ve dikey hücre birleştirme türünün nasıl yazdırılacağını gösterir:

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

Tablodaki Birleştirilmiş Hücreler

DocumentBuilder ile oluşturulan bir tablodaki hücreleri birleştirmek için, birleştirmenin beklendiği her hücre için uygun birleştirme türünü ayarlamanız gerekir – önce CellMerge.First ve sonra CellMerge.Previous.

Ayrıca, birleştirmenin gerekli olmadığı hücreler için birleştirme ayarını temizlemeyi de unutmamalısınız – bu, birleştirilmeyen ilk hücreyi CellMerge.None olarak ayarlayarak yapılabilir. Bu yapılmazsa, tablodaki tüm hücreler birleştirilir.

Aşağıdaki kod örneği, ilk satırdaki hücrelerin yatay olarak birleştirildiği iki satırlık bir tablonun nasıl oluşturulacağını gösterir:

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

Aşağıdaki kod örneği, ilk sütundaki hücrelerin dikey olarak birleştirildiği iki sütunlu bir tablonun nasıl oluşturulacağını gösterir:

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

Diğer Durumlarda Tablo Hücrelerini Birleştir

Varolan bir tabloda olduğu gibi DocumentBuilder ‘ın kullanılmadığı diğer durumlarda, hücreleri önceki şekilde birleştirmek o kadar kolay olmayabilir. Bunun yerine, birleştirme özelliklerini hücrelere uygulamakla ilgili temel işlemleri, görevi çok daha kolaylaştıran bir yöntemle sarabiliriz. Bu yöntem, bir tablodaki hücre aralığını birleştirmek için çağrılan Birleştirme otomasyonu yöntemine benzer.

Aşağıdaki kod, belirtilen hücreden başlayıp son hücrede biten tablo hücrelerini belirtilen aralıkta birleştirecektir. Bu durumda, aralık birden çok satır veya sütunu kapsayabilir:

// 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);
}
}
}
}
view raw merge-cells.h hosted with ❤ by GitHub

Aşağıdaki kod örneği, belirtilen iki hücre arasında bir hücre aralığının nasıl birleştirileceğini gösterir:

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

Kullandığınız Çerçevenin sürümüne bağlı olarak, bu yöntemi bir uzantı yöntemine dönüştürerek daraltmak isteyebilirsiniz. Bu durumda, cell1.Merge(cell2) gibi bir hücre aralığını birleştirmek için bu yöntemi doğrudan bir hücrede çağırabilirsiniz.

Tablodaki Dikey ve Yatay Birleştirilmiş Hücreler

Önceki makalelerde söylediğimiz gibi, Microsoft Word içindeki bir tablo bağımsız satırlar kümesidir. Her satır, diğer satırların hücrelerinden bağımsız bir dizi hücreye sahiptir. Bu nedenle, Microsoft Word tablosunda “sütun” diye bir nesne yoktur ve “1 st sütunu”, “tablodaki her satırın 1 st hücrelerinin kümesi” gibi bir şeydir. Bu, kullanıcıların örneğin 1 st satırının iki hücreden (2 cm ve 1 cm) ve 2 nd satırının iki farklı hücreden (1 cm ve 2 cm genişliğinde) oluştuğu bir tabloya sahip olmalarını sağlar. Ve Aspose.Words bu tablo kavramını destekler.

HTML ‘deki bir tablo esasen farklı bir yapıya sahiptir: her satır aynı sayıda hücreye sahiptir ve (görev için önemlidir) her hücre karşılık gelen sütunun genişliğine sahiptir, bir sütundaki tüm hücreler için aynıdır. Bu nedenle, HorizontalMerge ve VerticalMerge yanlış bir değer döndürürse, aşağıdaki kod örneğini kullanın:

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

Yatay Olarak Birleştirilmiş Hücrelere Dönüştür

Hücreler yatay olarak birleştirildiğinde Microsoft Word’in bazı yeni sürümleri artık birleştirme bayraklarını kullanmadığı için bazen hangi hücrelerin birleştirildiğini tespit etmek mümkün değildir. Ancak, hücrelerin birleştirme bayrakları kullanılarak genişliklerine göre yatay olarak bir hücreye birleştirildiği durumlar için Aspose.Words, hücreleri dönüştürmek için ConvertToHorizontallyMergedCells yöntemini sağlar. Bu yöntem yalnızca tabloyu dönüştürür ve gerektiğinde yeni hücreler ekler.

Aşağıdaki kod örneği, işlemdeki yukarıdaki yöntemi gösterir:

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