diff --git a/DocxFile使用帮助.docx b/DocxFile使用帮助.docx index 2889768..1b60842 100644 Binary files a/DocxFile使用帮助.docx and b/DocxFile使用帮助.docx differ diff --git a/Windows-X64/office_plugin.dll b/Windows-X64/office_plugin.dll index 9a686e3..d11ef59 100644 Binary files a/Windows-X64/office_plugin.dll and b/Windows-X64/office_plugin.dll differ diff --git a/funcext/TSOffice/TOfficeObj.tsf b/funcext/TSOffice/TOfficeObj.tsf index 408d4ab..242869a 100644 --- a/funcext/TSOffice/TOfficeObj.tsf +++ b/funcext/TSOffice/TOfficeObj.tsf @@ -1,4 +1,4 @@ -// Version 1.4.7 +// Version 1.4.8 Function TOfficeObj(n); Begin @@ -7385,9 +7385,6 @@ type TParagraphImpl=class(NodeInfo) markStart := new TBookMark(self, 'w:bookmarkStart'); Run := new TRun(self, 'w:r'); markEnd := new TBookMark(self, 'w:bookmarkEnd'); - PageNo := new TFldSimple(self, 'w:fldSimple'); - OfRun := new TRun(self, 'w:r'); - TotalPageNo := new TFldSimple(self, 'w:fldSimple'); //TODO... End; @@ -7398,9 +7395,6 @@ type TParagraphImpl=class(NodeInfo) markStart.InitRootNode(node); Run.InitRootNode(node); markEnd.InitRootNode(node); - PageNo.InitRootNode(node); - OfRun.InitRootNode(node); - TotalPageNo.InitRootNode(node); End; Function GetAttrs(); override; @@ -7416,9 +7410,6 @@ type TParagraphImpl=class(NodeInfo) ,('field':'markStart','name':markStart.NodeName,'obj':markStart,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TBookMark') ,('field':'Run','name':Run.NodeName,'obj':Run,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TRun') ,('field':'markEnd','name':markEnd.NodeName,'obj':markEnd,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TBookMark') - ,('field':'PageNo','name':PageNo.NodeName,'obj':PageNo,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TFldSimple') - ,('field':'OfRun','name':OfRun.NodeName,'obj':OfRun,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TRun') - ,('field':'TotalPageNo','name':TotalPageNo.NodeName,'obj':TotalPageNo,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TFldSimple') ) union ExtNodes; End; @@ -7429,9 +7420,6 @@ type TParagraphImpl=class(NodeInfo) markStart; Run; markEnd; - PageNo; - OfRun; - TotalPageNo; End; /////////////////////////////////////////////////////////////// @@ -11130,6 +11118,17 @@ Type TParagraph = Class(DocObject, TParagraphImpl) end return false; End; + + ///获取当前段落的上一个段落 + ///返回:TParagraph对象 + Function PrevParagraph(); + Begin + if ifObj(node_) then + begin + node := node_.PrevElement('w:p'); + return ifObj(node) ? new TParagraph(node) : nil; + end + End; Function CopyRunFormat(del, toRunNode); Begin @@ -12980,6 +12979,14 @@ Type TDocumentBody = Class(DocObject) End; return r; End; + + ///word最后一个段落 + ///返回:TParagraph对象 + Function LastParagraph(); + Begin + node := node_.LastChildElement('w:p'); + return ifObj(node) ? new TParagraph(node) : nil; + End; ///添加新段落 ///paragraph: TParagraph对象 @@ -13040,7 +13047,7 @@ Type TDocumentBody = Class(DocObject) if not ifObj(node) then return false; reset_position := false; - if node.Eq(TOfficeApi().GetCurrentPosition()) then + if ifObj(TOfficeApi().GetCurrentPosition()) and node.Eq(TOfficeApi().GetCurrentPosition()) then reset_position := true; next := node.NextElement('w:p'); node_.DeleteChild(node); @@ -13128,7 +13135,7 @@ Type TDocumentBody = Class(DocObject) ///插入数据表 ///tbl: TTable对象 ///[posOpt: 段落位置],0 在DOCX文件开头;-1 文件尾;N 在第N段之后;DocumentPart对象 在posOpt之后新添加表格 - Function InsertTable(tbl, posOpt); + Function InsertTable(tbl, posOpt, customCell); Begin addPart(posOpt, tbl); TOfficeApi().Set('CurrentTable', tbl.node_); @@ -13166,10 +13173,17 @@ Type TDocumentBody = Class(DocObject) End; tcNode := trNode.InsertEndChild('element', 'w:tc'); - tcPrNode := tcNode.InsertEndChild('element', 'w:tcPr'); - tcWNode := tcPrNode.InsertEndChild('element', 'w:tcW'); - tcWNode.SetAttribute('w:w', tbl.TblGrid.GridCol[j]['obj'].W); - tcWNode.SetAttribute('w:type', 'dxa'); + if istable(customCell) and ifObj(customCell[i, j, 0]) then + begin + tcNode.InsertEndChild(customCell[i, j, 0].Marshal()); + end + else begin + tcPrNode := tcNode.InsertEndChild('element', 'w:tcPr'); + tcWNode := tcPrNode.InsertEndChild('element', 'w:tcW'); + tcWNode.SetAttribute('w:w', tbl.TblGrid.GridCol[j]['obj'].W); + tcWNode.SetAttribute('w:type', 'dxa'); + end + if multiLine then Begin defaultParagraph.node_ := nil; defaultParagraph.Run.ClearText(); @@ -13178,9 +13192,15 @@ Type TDocumentBody = Class(DocObject) End else Begin pNode := tcNode.InsertEndChild('element', 'w:p'); - pNode.InsertEndChild(defaultpPr); + if istable(customCell) and ifObj(customCell[i, j, 1]) then + pNode.InsertEndChild(customCell[i, j, 1].Marshal()); + else + pNode.InsertEndChild(defaultpPr); rNode := pNode.InsertEndChild('element', 'w:r'); - rNode.InsertEndChild(defaultrPr); + if istable(customCell) and ifObj(customCell[i, j, 2]) then + rNode.InsertEndChild(customCell[i, j, 2].Marshal()); + else + rNode.InsertEndChild(defaultrPr); tNode := rNode.InsertEndChild('element','w:t', class(TSXml).CurCodePageToUtf8(tbl.Data_[i, j])); if _preserve(tbl.Data_[i, j]) then tNode.SetAttribute('xml:space', 'preserve'); @@ -13908,54 +13928,44 @@ Type TDocumentBody = Class(DocObject) pNode := posOpt.NextElement(); else pNode := node_.FirstChildElement(); - sectPr := new TSectPr(docx, nil); while ifObj(pNode) do Begin name := pNode.GetName(); - if false and ifarray(numIds) and name = 'w:sectPr' then // 关闭此处的Init计算页码 - sectPr.Init(pNode); - else if name = 'w:p' then Begin - sectNode := pNode.FirstChildElement('w:sectPr'); - if ifObj(sectNode) then Begin //章节 - sectPr.Init(pNode); - End - else Begin - p := new TParagraph(pNode); - //统计数字项目编号 - numArr := array(); - numId := getNumPr('numId', docx, p); - ilvl := getNumPr('Level', docx, p); - if not ilvl then ilvl := 0; - if ifarray(numIds) then Begin - sectPr.Append(p); - if ilvl >= 0 and ilvl < 10 then Begin - if not istable(numIds[numId]) then - numIds[numId] := array(0,0,0,0,0,0,0,0,0,0); - prev := numIds[numId, ilvl]; - if prev then Begin - for i:=ilvl+1 to 9 do - numIds[numId, i] := 0; - End; - numIds[numId, ilvl]++; - numArr := numIds[numId]; + if name = 'w:p' and not ifObj(pNode.FirstChildElement('w:sectPr')) then + begin + p := new TParagraph(pNode); + //统计数字项目编号 + numArr := array(); + numId := getNumPr('numId', docx, p); + ilvl := getNumPr('Level', docx, p); + if not ilvl then ilvl := 0; + if ifarray(numIds) then Begin + if ilvl >= 0 and ilvl < 10 then Begin + if not istable(numIds[numId]) then + numIds[numId] := array(0,0,0,0,0,0,0,0,0,0); + prev := numIds[numId, ilvl]; + if prev then Begin + for i:=ilvl+1 to 9 do + numIds[numId, i] := 0; End; + numIds[numId, ilvl]++; + numArr := numIds[numId]; End; - if bHeadList then Begin //统计大纲显示(目录) - styleId := p.Format.Value('StyleId', 1); - if styleId <> '' then Begin - obj := docx.StyleObject().GetStyleById(styleId); - if ifObj(obj) then Begin - level := getHeadingLevel(docx, obj); - iLevel := Class(TSXml).SafeStrToIntDef(level, -1); - if p.Text() <> "" and iLevel+1 >= UpperHeadingLevel and iLevel+1 <= LowerHeadingLevel then Begin - r[ind]['Level'] := strtoint(level); - r[ind]['Paragraph'] := p; - r[ind]['Text'] := p.Text(); - r[ind]['numId'] := ifnumber(numId) ? integer(numId) : 0; //数字项目编号 - r[ind]['ilvl'] := ilvl; //级别 - r[ind]['numArr'] := numArr; //累加数字编码 - sectPr.Mark(ind);//标记段落 - ind++; - End; + End; + if bHeadList then Begin //统计大纲显示(目录) + styleId := p.Format.Value('StyleId', 1); + if styleId <> '' then Begin + obj := docx.StyleObject().GetStyleById(styleId); + if ifObj(obj) then Begin + level := getHeadingLevel(docx, obj); + iLevel := Class(TSXml).SafeStrToIntDef(level, -1); + if p.Text() <> "" and iLevel+1 >= UpperHeadingLevel and iLevel+1 <= LowerHeadingLevel then Begin + r[ind]['Level'] := strtoint(level); + r[ind]['Paragraph'] := p; + r[ind]['Text'] := p.Text(); + r[ind]['numId'] := ifnumber(numId) ? integer(numId) : 0; //数字项目编号 + r[ind]['ilvl'] := ilvl; //级别 + r[ind]['numArr'] := numArr; //累加数字编码 + ind++; End; End; End; @@ -13964,7 +13974,6 @@ Type TDocumentBody = Class(DocObject) else if ifarray(numIds) and name = 'w:tbl' then Begin tbl := TOfficeObj('TTable'); tbl.Init(pNode); - sectPr.Append(tbl); rows := tbl.Rows(); cols := tbl.Cols(); for i:=1 to rows do Begin @@ -13977,11 +13986,6 @@ Type TDocumentBody = Class(DocObject) pNode := pNode.NextElement(); End; - if ifarray(numIds) then Begin //设置页面 - for i:=0 to length(r)-1 do Begin - r[i]['pageNo'] := sectPr.GetPageNo(i); - End; - End; return r; End; @@ -14505,8 +14509,9 @@ Type TCell = Class(TDocumentBody, TWTc) Function Append(c); Begin - ps := c.Paragraphs(); + ps := c.Parts(); for i:=0 to length(ps)-1 do Begin + if not ps[i].node_.GetName() in array('w:p', 'w:tbl') then continue; data := ps[i].node_.Marshal(); w := node_.InsertEndChild(data[0]); End; @@ -14824,6 +14829,76 @@ Type TTable = Class(DocObject, TTableImpl) return 'Invalid input Coordinates.'; return Merge(top, left, bottom, right, del); End; + + ///删除单元格 + ///row: int, 行 + ///col: int, 列 + ///[cellshift]: int, 默认1。0:删除单元格下方内容上移,1:删除单元格右侧单元格左移 + ///row或col其中一个为nil时,删除某行或某列,如(1, nil),删除第一行 + Function DeleteCell(row, col, cellshift); + Begin + if ifnil(cellshift) then cellshift := 1; + if ifnumber(row) and ifnil(col) then + begin + node := _getRowNode(row - 1); + if ifObj(node) then node_.DeleteChild(node); + for i:=row-1 to length(cells_)-2 do + cells_[i] := cells_[i + 1]; + reindex(cells_, array(length(cells_)-1 : nil)); + end + else if ifnil(row) and ifnumber(col) then + begin + for r:=1 to length(cells_) do + DeleteCell(r, col); + iCol_--; + end + else begin + c := cells_[row-1, col-1]; + if not c then return; + node := _getRowNode(row - 1); + if cellshift then + begin + node.DeleteChild(c[0]); + for i:=col-1 to iCol_ - 1 do + cells_[row-1, i] := cells_[row-1, i+1]; + cells_[row-1, iCol_-1] := nil; + end + else begin + r := row; + len := length(cells_); + while r < len and ifObj(node) do + begin + tcell := cells_[r, col-1]; + if tcell then + begin + new_node := node.InsertAfterChild(c[0], tcell[0].Marshal()[0]); + node.DeleteChild(c[0]); + cells_[row-1, col-1, 0] := new_node; + end + c := tcell; + ++r; + node := node.NextElement(); + end + if c then + begin + p := c[0].FirstChild('w:p'); + c[0].DeleteChildren(); + c[0].InsertEndChild('element', 'w:p'); + end + end + end + End; + + Function _getRowNode(row); + Begin + node := node_.FirstChild('w:tr'); + while row and ifObj(node) do + begin + row--; + node := node.NextElement(); + end + return node; + End; Function _getLeft(row, iCol, left2); Begin @@ -15344,3 +15419,4 @@ Begin return true; return false; End; + diff --git a/funcext/TSOffice/TSDocxFile.tsf b/funcext/TSOffice/TSDocxFile.tsf index bad580b..74fd793 100644 --- a/funcext/TSOffice/TSDocxFile.tsf +++ b/funcext/TSOffice/TSDocxFile.tsf @@ -1,4 +1,4 @@ -// Version 1.4.7 +// Version 1.4.8 Type TSDocxFile = Class ///Version: V1.0 2022-09-20 @@ -123,6 +123,13 @@ Type TSDocxFile = Class Begin return document_.Body().Paragraphs(); End; + + ///word文档最后一个段落 + ///返回:TParagraph对象 + Function LastParagraph(); + Begin + return document_.Body().LastParagraph(); + End; ///添加新段落 ///paragraph: TParagraph对象 @@ -230,10 +237,12 @@ Type TSDocxFile = Class ///插入数据表 ///tbl: TTable对象 ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加表格 + ///customCell: 二维数组,自定义指定单元格的样式 + /// 如:一行一列arr[0][0] := array(twtcPr, twpPr, twrPr);其中twtcPr是twtcPr对象,twpPr是twpPr对象,twrPr是twrPr对象 ///返回: TTable对象 - Function InsertTable(tbl, posOpt); + Function InsertTable(tbl, posOpt, customCell); Begin - return document_.Body().InsertTable(tbl, getPosNode(posOpt)); + return document_.Body().InsertTable(tbl, getPosNode(posOpt), customCell); End; ///返回CoreProperties对象 diff --git a/funcext/TSOffice/TSExcelFile.tsf b/funcext/TSOffice/TSExcelFile.tsf index ceb3e3c..e948c47 100644 --- a/funcext/TSOffice/TSExcelFile.tsf +++ b/funcext/TSOffice/TSExcelFile.tsf @@ -1,4 +1,4 @@ -// Version 1.4.7 +// Version 1.4.8 Type TSExcelFile = Class ///Version: V1.0 2022-08-08 diff --git a/funcext/TSOffice/TSUtils/NodeInfo.tsf b/funcext/TSOffice/TSUtils/NodeInfo.tsf index ad6f00e..cb29145 100644 --- a/funcext/TSOffice/TSUtils/NodeInfo.tsf +++ b/funcext/TSOffice/TSUtils/NodeInfo.tsf @@ -71,27 +71,16 @@ public children_ := nil; GetChildrenEx(); //优化为变量,减少数据COPY,2022-12-10 child_arr := array(); + name_map := array(); len := 0; for i:=0 to length(children_)-1 do begin node_type := children_[i]['nodeType']; obj := children_[i]['obj']; if ifnil(obj) then continue; - //find := select thisrowindex as "rowindex_", * from child_arr where ['name'] = children_[i]['name'] end; //优化为循环,性能提高15-20%,2022-12-20 - find := array(); - for j:=length(child_arr)-1 downto 0 do Begin //支持列表模式(如多节点:),查找最近的节点 - if child_arr[j]['name'] = children_[i]['name'] then Begin - find[0] := child_arr[j]; - find[0]['rowindex_'] := j; - break; - End; - End; - if not ifnil(obj) and not ifObj(obj) and istable(find) and ifstring(children_[i]['attrEx']) and children_[i]['attrEx'] <> '' then + if not ifObj(obj) and not ifnil(name_map[children_[i]['name']]) and children_[i]['attrEx'] <> '' then begin - if not ifarray(find[0]['attributes']) then find[0]['attributes'] := array(); - key := children_[i]['attrEx']; - find[0]['attributes'] union= array(key : obj); - child_arr[find[0]['rowindex_']]['attributes'] := find[0]['attributes']; + child_arr[name_map[children_[i]['name']]]['attributes'] union=array(children_[i]['attrEx'] : obj); continue; end @@ -118,7 +107,7 @@ public key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; arr['attributes'] := array(key : obj); end - + name_map[children_[i]['name']] := len; child_arr[len++] := arr; end diff --git a/funcext/TSOffice/document/TTableContent.tsf b/funcext/TSOffice/document/TTableContent.tsf index 8cafb3c..6c02810 100644 --- a/funcext/TSOffice/document/TTableContent.tsf +++ b/funcext/TSOffice/document/TTableContent.tsf @@ -142,7 +142,7 @@ Type TTableContent = class Begin ///获取标题列表 array((("Level":level,"Paragraph":"object","Text":title,"numId":,"ilvl":,"numArr":)); numMap := array(); - r := docx_.Document().Body().GetHeadingListImpl(docx_, -1, UpperHeadingLevel, LowerHeadingLevel, numMap, true); + r := docx_.Document().Body().GetHeadingListImpl(docx_, nil, UpperHeadingLevel, LowerHeadingLevel, numMap, true); for i:=0 to length(r)-1 do Begin p := _AddItem(UpperHeadingLevel, LowerHeadingLevel, r[i]['Level'], i = 0 ? true: false); //fldCharType diff --git a/更新日志.md b/更新日志.md index 1a29882..426e883 100644 --- a/更新日志.md +++ b/更新日志.md @@ -1,5 +1,16 @@ # 更新日志 +## 2023-9-27 + +### V1.4.8 + +#### word + +1. 支持`Inserttable`时候加入对单元格样式的设置 +2. 新增`TSDocxFile.LastParagraph`方法 +3. 新增`TParagraph.PrevParagraph`方法 +4. 性能优化 + ## 2023-9-22 ### V1.4.7