diff --git a/Demo/ExcelHelp.tsl b/Demo/ExcelHelp.tsl index 7f8280a..044894b 100644 --- a/Demo/ExcelHelp.tsl +++ b/Demo/ExcelHelp.tsl @@ -759,5 +759,20 @@ style.Protection.Lock := 1; ), 'Demo': '', ), + ('ObjName': 'TCalcPr', + 'Desc': ('TCalcPr有以下属性: '), + 'AttrInfo': ( + ('attrName': 'CalcMode', 'type': 'string', 'desc': '工作簿计算模式', 'value': array('nil(默认): 自动重算', '"autoNoTable": 除模拟运算表外自动重算', '"manual": 手动重算')), + ('attrName': 'RefMode', 'type': 'string', 'desc': 'R1C1引用样式', 'value': array('nil(默认): 不启用', '"R1C1": 启用R1C1引用样式')), + ('attrName': 'Iterate', 'type': 'bool', 'desc': '是否启用迭代计算', 'value': array()), + ('attrName': 'IterateCount', 'type': 'int', 'desc': '最多迭代次数', 'value': array()), + ('attrName': 'IterateDelta', 'type': 'double', 'desc': '最大误差,需要使用科学计数法,如0.002时为2E-3', 'value': array()), + ('attrName': 'CalcOnSave', 'type': 'bool', 'desc': '保存工作簿之前重新计算,{CalcMode}为"manual"时有效', 'value': array()), + ('attrName': 'ConCurrentCalc', 'type': 'bool', 'desc': '是否启用多线程计算', 'value': array()), + ('attrName': 'ConCurrentManualCount', 'type': 'int', 'desc': '自定义计算线程数', 'value': array()), + ('attrName': 'FullPrecision', 'type': 'bool', 'desc': '是否采用完整精度', 'value': array()), + ), + 'Demo': '', + ), ); End diff --git a/DocxFile使用帮助.docx b/DocxFile使用帮助.docx index 1dfbe09..33fecc0 100644 Binary files a/DocxFile使用帮助.docx and b/DocxFile使用帮助.docx differ diff --git a/ExcelFile使用帮助.xlsx b/ExcelFile使用帮助.xlsx index 0232a3b..2de69c9 100644 Binary files a/ExcelFile使用帮助.xlsx and b/ExcelFile使用帮助.xlsx differ diff --git a/funcext/TSOffice/TOfficeObj.tsf b/funcext/TSOffice/TOfficeObj.tsf index 7f8a8c0..b6bc329 100644 --- a/funcext/TSOffice/TOfficeObj.tsf +++ b/funcext/TSOffice/TOfficeObj.tsf @@ -1,4 +1,4 @@ -// Version 1.1.6 +// Version 1.1.7 Function TOfficeObj(n); Begin @@ -309,6 +309,8 @@ Begin return new TBreak(); "tprotect": return new TProtect(); + "tcalcpr": + return new TCalcPr(); End; End; @@ -9461,6 +9463,58 @@ type TProtect=class(NodeInfo) //Nodes End; +/////////////////////////////////////////////////////////////// +/// TCalcPr +/////////////////////////////////////////////////////////////// +type TCalcPr=class(NodeInfo) + Function Create(); overload; + Begin + Create(nil, 'calcPr'); + End; + + Function Create(p, name); overload; + Begin + Class(NodeInfo).Create(p, name); + Init(); + End; + + Function Init(); + Begin + //TODO... + End; + + Function InitRootNode(node); + Begin + RootObj := node; + End; + + Function GetAttrs(); override; + Begin + HandleAttrs(); + return array(("CalCId", "calcId", CalCId, ""),("CalcMode", "calcMode", CalcMode, ""),("RefMode", "refMode", RefMode, ""),("Iterate", "iterate", Iterate, ""),("IterateCount", "iterateCount", IterateCount, ""),("IterateDelta", "iterateDelta", IterateDelta, ""),("CalcOnSave", "calcOnSave", CalcOnSave, ""),("FullPrecision", "fullPrecision", FullPrecision, ""),("ConCurrentCalc", "conCurrentCalc", ConCurrentCalc, ""),("ConCurrentManualCount", "conCurrentManualCount", ConCurrentManualCount, "")) union ExtAttr; + End; + + Function GetChildren(); override; + Begin + HandleChildren(); + return ExtNodes; + End; + + //Attributes + CalCId; + CalcMode; + RefMode; + Iterate; + IterateCount; + IterateDelta; + CalcOnSave; + FullPrecision; + ConCurrentCalc; + ConCurrentManualCount; + + //Nodes +End; + /////////////////////////////////////////////////////////////////////////////////////////// ///DOCX文档实现 @@ -14302,3 +14356,4 @@ private End + diff --git a/funcext/TSOffice/TSDocxFile.tsf b/funcext/TSOffice/TSDocxFile.tsf index c2a9ab3..2301691 100644 --- a/funcext/TSOffice/TSDocxFile.tsf +++ b/funcext/TSOffice/TSDocxFile.tsf @@ -1,4 +1,4 @@ -// Version 1.1.6 +// Version 1.1.7 Type TSDocxFile = Class ///Version: V1.0 2022-09-20 @@ -73,6 +73,25 @@ Type TSDocxFile = Class return zipfile_.Save(alias, fname); End; + ///另存为二进制流数据 + ///返回: [err, fileContent] fileContent 文件内容,为Binary数据类型 + Function SaveToMem(); + Begin + return zipfile_.Save2Mem(); + End; + + ///打开二进制内容 + ///data: 二进制数据 + ///返回: [err, errmsg] + Function LoadFromMem(data); + Begin + [err, errmsg] := zipfile_.LoadFromMem(data); + if err=0 then Begin + document_ := new docxDocument(zipfile_); + End; + return array(err, errmsg); + End; + ///真实文件名 ///返回:string Function FileName(); diff --git a/funcext/TSOffice/TSExcelFile.tsf b/funcext/TSOffice/TSExcelFile.tsf index 81dae5f..155d124 100644 --- a/funcext/TSOffice/TSExcelFile.tsf +++ b/funcext/TSOffice/TSExcelFile.tsf @@ -1,4 +1,4 @@ -// Version 1.1.6 +// Version 1.1.7 Type TSExcelFile = Class ///Version: V1.0 2022-08-08 @@ -69,6 +69,27 @@ Type TSExcelFile = Class return zipfile_.Save(); End; + ///打开二进制内容 + ///data: 二进制数据 + ///返回: [err, errmsg] + Function LoadFromMem(data); + Begin + [err, errmsg] := zipfile_.LoadFromMem(data); + if err = 0 then + begin + workbook_ := new xlsxWorkBook(zipfile_); + workbook_.Load(); + end + return array(err, errmsg); + End; + + ///保存为二进制内容 + ///返回: [err, fileContent] fileContent二进制文件内容 + Function SaveToMem(); + Begin + return zipfile_.Save2Mem(); + End; + ///另存为 ///alias: string,文件目录别名 ///fname: string,文件名 @@ -115,11 +136,19 @@ Type TSExcelFile = Class ///创建新sheet ///sheet: string,工作表名称 - Function NewSheet(sheet); + Function NewSheet(sheet);overload; Begin return workbook_.NewSheet(class(TSXml).CurCodePageToUtf8(sheet)); End; + ///在指定sheet之前插入新sheet + ///sourceSheet: string,指定工作表名称 + ///destSheet: string,目的工作表名称 + Function NewSheet(sourceSheet, destSheet);overload; + Begin + return workbook_.NewSheet(class(TSXml).CurCodePageToUtf8(sourceSheet), class(TSXml).CurCodePageToUtf8(destSheet)); + End; + ///删除sheet ///sheet: string,工作表名称 Function DeleteSheet(sheet); @@ -848,6 +877,13 @@ Type TSExcelFile = Class return workbook_.GetDefaultFont(); End; + ///设置工作簿计算选项 + ///calcPr: TCalcPr对象 + Function SetCalcOptions(calcPr); + Begin + return workbook_.SetCalcOptions(calcPr); + End; + Function WorkBook(); Begin return workbook_; diff --git a/funcext/TSOffice/worksheet/xlsxWorkBook.tsf b/funcext/TSOffice/worksheet/xlsxWorkBook.tsf index b1b89ba..ab7bfbb 100644 --- a/funcext/TSOffice/worksheet/xlsxWorkBook.tsf +++ b/funcext/TSOffice/worksheet/xlsxWorkBook.tsf @@ -139,7 +139,7 @@ Type xlsxWorkBook = Class ///创建新sheet ///sheet: string,工作表名称 - Function NewSheet(sheet); + Function NewSheet(sheet);overload; Begin lname := LowerCase(sheet); if ifint(sheetIndexMap_[ lname ]) then return 'The sheet already exists.'; @@ -201,6 +201,86 @@ Type xlsxWorkBook = Class SetDefaultSheet(sheet); End; + Function NewSheet(sourceSheet, destSheet);overload; + Begin + lname := LowerCase(destSheet); + if ifint(sheetIndexMap_[ lname ]) then return 'destSheet already exists.'; + sname := LowerCase(sourceSheet); + if not ifint(sheetIndexMap_[ sname ]) then return 'sourceSheet does not exists'; + + //添加文件xl/worksheets/sheetN.xml + sheetId := vselect maxof(['sheetId']) from sheetNames_ end; + sheetId := integer(sheetId) + 1; + fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml'; + zipfile_.Add(fname, class(TSXml).XmlHeader() + class(TSXml).GetTemplate('sheet1')); + + //设置 workbook.xml.rels + rid := getWorkbookRelsRid(); + workbook_rels := GetXmlFileObj('xl/_rels/workbook.xml.rels'); + rels := workbook_rels.FirstChildElement('Relationships').InsertEndChild('element', 'Relationship'); + rels.SetAttribute('Target', getTarget( sheetsCount_ + 1)); + rels.SetAttribute('Type', class(TSXml).GetTemplate('RelationshipWorkSheet')); + rels.SetAttribute('Id', rid); + //workbook_rels.Print; + + //设置 xl/workbook.xml + workbook := GetXmlFileObj('xl/workbook.xml'); + node := workbook.FirstChildElement('workbook').FirstChildElement('sheets'); + sheet_node := node.FirstChildElement('sheet'); + while ifObj(sheet_node) do + begin + if sheet_node.GetAttribute('name') = sourceSheet then + begin + sheet_node := node.InsertAfterChild(sheet_node, 'element', 'sheet'); + sheet_node.SetAttribute('name', destSheet); + sheet_node.SetAttribute('sheetId', sheetId); + sheet_node.SetAttribute('r:id', rid); + break; + end + sheet_node := sheet_node.NextElement(); + end + //workbook.Print(); + + //设置docProps/app.xml + app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app')); + //app.Print(); + node := app.FirstChildElement('Properties').FirstChildElement('TitlesOfParts'); + vector := node.FirstChildElement('vt:vector'); + vector.SetAttribute('size', length(sheetNames_) + 1); + lpstr := vector.FirstChildElement('vt:lpstr'); + while ifObj(lpstr) do + begin + if LowerCase(lpstr.GetText()) = LowerCase(sourceSheet) then + begin + lpstr := vector.InsertAfterChild(lpstr, 'element', 'vt:lpstr'); + lpstr.SetValue(destSheet); + break; + end + lpstr := lpstr.NextElement(); + end + + //设置[Content_Types].xml + content_xml := GetXmlFileObj(class(TSXml).GetFileName('Content_Types')); + class(TSXml).AddOverrideContentType(content_xml, '/' + fname, class(TSXml).GetTemplate('sheetContentType')); + + ind := sheetIndexMap_[sname]; + for i:=sheetsCount_ downto ind+2 do + begin + sheetNames_[i]['name'] := sheetNames_[i-1]['name']; + sheetNames_[i]['sheetId'] := sheetNames_[i-1]['sheetId']; + sheetNames_[i]['rid'] := sheetNames_[i-1]['rid']; + sheetNames_[i]['file'] := sheetNames_[i-1]['file']; + sheetIndexMap_[ LowerCase(sheetNames_[i]['name']) ] := i; + end + sheetIndexMap_[lname] := ind + 1; + sheetNames_[ind+1]['name'] := destSheet; + sheetNames_[ind+1]['sheetId'] := sheetId; + sheetNames_[ind+1]['rid'] := rid; + sheetNames_[ind+1]['file'] := fname; + sheetsCount_ ++; + SetDefaultSheet(destSheet); + End; + Function DeleteSheet(sheet); Begin if sheetsCount_ <= 1 then return 'Cant not delete the last sheet.'; @@ -299,6 +379,9 @@ Type xlsxWorkBook = Class del_partname := '/' + sheetPrefix_ + inttostr(sheetsCount_ + 1) + '.xml'; DeleteContentType(del_partname); + //删除calcChain.xml + zipfile_.Remove('xl/calcChain.xml'); + xmlFileObjMap_ := array(); //设置默认工作表 @@ -1143,6 +1226,17 @@ Type xlsxWorkBook = Class return tfont; End; + Function SetCalcOptions(calcPr); + Begin + workbook_xml := GetXmlFileObj('xl/workbook.xml'); + workbook_node := workbook_xml.FirstChildElement('workbook'); + calc_node := workbook_node.FirstChildElement('calcPr'); + sheet_node := workbook_node.FirstChildElement('sheets'); + if ifObj(calc_node) then workbook_node.DeleteChild(calc_node); + calcPr.calcId := "191029"; + workbook_node.InsertAfterChild(sheet_node, calcPr.Marshal()); + End + private Function generateRow(c1, c2, r); Begin diff --git a/更新日志.md b/更新日志.md index 116800d..fd46e4c 100644 --- a/更新日志.md +++ b/更新日志.md @@ -1,5 +1,20 @@ # 更新日志 +## 2023-2-21 + +### V1.1.7 + +#### word + +1. 新增`LoadFromMem`, `SavaToMem` + +#### excel + +1. 新增`LoadFromMem`, `SavaToMem` +2. 新增重载方法`NewSheet` +3. 新增`SetCalcOptions` +4. 修复删除sheet报错问题 + ## 2023-2-13 ### V1.1.6