From c59043f90bea13a7e2d5b2a9a7e1c77f2e520f6a Mon Sep 17 00:00:00 2001 From: csh Date: Tue, 2 Jan 2024 15:38:31 +0800 Subject: [PATCH] update --- README.md | 50 ++++- demo/TSVbaDocxHelp.tsl | 476 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 demo/TSVbaDocxHelp.tsl diff --git a/README.md b/README.md index d48072e..1713d2d 100644 --- a/README.md +++ b/README.md @@ -1 +1,49 @@ -# TSOfficeVba 项目: 基于 TSOffice 项目,以类 VBA 方式,用 TSL 实现对 excel、word 的操作 +# TSOfficeVba + +## 介绍 + +该项目主要是以类`VBA`的方式完成对 office 文件的读写,使用方式与`VBA`大致相同,可参考[微软 VBA 文档][1] + +如:打开一个 word 文件 + +vba打开: + +```vbs +Dim path As String +Dim doc As Document +set path = "./default.docx" +set doc = Documents.Open FileName:=path ' 打开一个文件 +doc.Activate ' 可设置doc为ActiveDocument +Msgbox ActiveDocument.Paragraphs.Count ' 可用doc/ActiveDocument进行操作 +``` + +tsl 打开: + +```cpp +path = "./default.docx" +application := new TSDocxApplication(); // new一个Application对象 +doc = application.Documents.Open(FileName:=path) // 通过application打开文件 +doc.Activate; // 激活 +ActiveDocument = application.ActiveDocument; // 需要通过application属性赋值才能使用ActiveDocument +echo ActiveDocument.Paragraphs.Count; // 也可用doc进行操作 +``` + +## 帮助文档 + +帮助文档涵盖了**TSOfficeVBA**对`VBA`的支持情况,以及相关的**FAQ** + +生成你的帮助文档 + +```txt +tsl .\demo\TSVbaDocxHelp.tsl --path=C:\\xxx\\funcext +``` + +`TSVbaDocxHelp.tsl`:帮助脚本文件,克隆后在demo目录下 +`--path=`: 部署的路径 + +## 部署 + +该项目基于[**TSOffice**][2],所以部署到`funcext`时需要检查**TSOffice**是否部署成功 + +[1]: https://learn.microsoft.com/en-us/office/vba/api/overview/library-reference +[2]: https://git.mytsl.cn/tinysoft/OfficePlugin diff --git a/demo/TSVbaDocxHelp.tsl b/demo/TSVbaDocxHelp.tsl new file mode 100644 index 0000000..1c23008 --- /dev/null +++ b/demo/TSVbaDocxHelp.tsl @@ -0,0 +1,476 @@ +Uses TSDocxEnumerations; +Application := new TSDocxApplication(); + +path := SysparamStr(1); +if path and LeftStr(path, 7) = "--path=" then +begin + path := path[8:] $ "\\OfficeVBA\\docx\\"; +end +savepath := "TSVbaDocxHelp.docx"; + +// document := Application.Documents.Open(FileName: openpath); +document := Application.Documents.Add; +document.Activate; +ActiveDocument := Application.ActiveDocument; + +FirstPage(ActiveDocument); +Preface(ActiveDocument); +SupportedList(path, ActiveDocument); +FAQ(ActiveDocument); +AddTablesOfContents(ActiveDocument); + +ActiveDocument.SaveAs2(FileName : savepath); +echo "ActiveDocument.SaveAs2 = " $ savepath $ "\n"; +return; + +Function FirstPage(ActiveDocument); +Begin + para := ActiveDocument.Paragraphs.Last; + para.Range.Text := "TSVBA"; + para.Range.InsertBefore("天软"); + para.Range.InsertAfter("帮助文档"); + para.Range.Font.Bold := true; + para.Range.Font.Size := 25; + para.Range.Font.Apply(); + para.Format.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + para.Format.Style := "Title"; + para.Format.Apply(); // 写属性后要apply + + image := TOfficeTemplate('tinysoft.gif',true); + shape := ActiveDocument.InlineShapes.AddPicture(image); + shape.Width := 410; + shape.Height := 75; + shape.Apply(); + + ActiveDocument.Paragraphs.Add; + ActiveDocument.Paragraphs(3).Range.InsertParagraphAfter(); + ActiveDocument.Paragraphs(4).Range.InsertParagraphBefore(); + range := ActiveDocument.Paragraphs(4).Range; + range.Collapse(TSDocxEnumerations.wdCollapseEnd()); + table := ActiveDocument.Tables.Add(Range:=range, NumRows:=3, NumColumns:=2, DefaultTableBehavior:=TSDocxEnumerations.wdWord9TableBehavior); + println("ActiveDocument.Paragraphs.Count = {}", ActiveDocument.Paragraphs.Count); + table.Columns(1).Width := 120; + table.Columns(2).Width := 320; + data := array(("文档名称", "TSVBA"), ("文档版本", "Version 1.0"), ("修订日期", Datetimetostr(now()))); + for i:=1 to 3 do + begin + cell := table.Cell(i, 1); + cell.Shading.Texture := TSDocxEnumerations.wdTexture27Pt5Percent; + cell.Shading.ForegroundPatternColor := TSDocxEnumerations.wdColorAutomatic; + cell.Shading.BackgroundPatternColor := TSDocxEnumerations.wdColorGray15; + cell.Shading.Apply(); + cell.Range.Text := data[i-1][0]; + cell.Range.Font.Bold := true; + cell.Range.Font.Apply(); + + cell := table.Cell(i, 2); + cell.VerticalAlignment := TSDocxEnumerations.wdCellAlignVerticalCenter; + cell.Range.Text := data[i-1][1]; + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + end + ActiveDocument.Paragraphs.Add; + para := ActiveDocument.Paragraphs.Last; + para.Range.InsertBreak(TSDocxEnumerations.wdPageBreak()); +End; + +Function AddTitle(ActiveDocument, text, level); +Begin + ActiveDocument.Paragraphs.Add; + para := ActiveDocument.Paragraphs.Last; + info := array( + (22, TSDocxEnumerations.wdViolet(), TSDocxEnumerations.wdOutlineLevel1(), 0), + (16, TSDocxEnumerations.wdDarkRed(), TSDocxEnumerations.wdOutlineLevel2(), 2), + (16, TSDocxEnumerations.wdTeal(), TSDocxEnumerations.wdOutlineLevel3(), 15), + ); + index := level - 1; + para.Range.Text := text; + para.Range.Font.Size := info[index][0]; + para.Range.Font.Bold := true; + para.Range.Font.ColorIndex := info[index][1]; + para.Range.Font.Apply(); + para.Format.OutlineLevel := info[index][2]; + para.Format.LeftIndent := info[index][3]; + // para.Format.CharacterUnitLeftIndent := 0; + para.Format.Apply(); + para.Range.ListFormat.ApplyOutlineNumberDefault(); +End; + +Function Preface(ActiveDocument); +Begin + AddTitle(ActiveDocument, "前言", 1); + para := ActiveDocument.Paragraphs.Last; + para.Format.PageBreakBefore := true; + para.Format.Apply(); + + ActiveDocument.Paragraphs.Add; + para := ActiveDocument.Paragraphs.Last; + para.Range.Text := "该文档由docx_vba_help.tsl脚本自动生成。"; + para.Range.Font.Size := 14; + para.Range.Font.Italic := true; + para.Range.Font.ColorIndex := TSDocxEnumerations.wdPink(); + para.Range.Font.Apply(); + para.Format.CharacterUnitFirstLineIndent := 2; + para.Format.FirstLineIndent := 20; + para.Format.Apply(); + font := para.Range.Font.Duplicate; + format := para.Format.Duplicate; + + ActiveDocument.Paragraphs.Add; + para := ActiveDocument.Paragraphs.Last; + para.Range.Text := "本项目基于TSOffice,使用前请先部署TSOffice。该项目以类VBA的方式,用TSL实现对excel、word的操作。"; + para.Range.Font := font; + para.Format := format; + para.Range.Font.Italic := false; + para.Range.Font.ColorIndex := TSDocxEnumerations.wdBlack(); + para.Range.Font.Apply(); + font := para.Range.Font.Duplicate; + format := para.Format.Duplicate; + + ActiveDocument.Paragraphs.Add; + para := ActiveDocument.Paragraphs.Last; + para.Range.Text := "项目目前仅支持常用的操作,比如对段落、表格的操作。需注意该项目在使用时可能存在与VBA有差异的情况。具体支持列表如下:"; + para.Range.Font := font; + para.Format := format; +End; + +Function SupportedList(path, ActiveDocument); +Begin + ActiveDocument.Paragraphs.Add; + AddTitle(ActiveDocument, "TSVBA支持对象", 1); + + println("\n\nAuto generate classInfo.."); + files := array( + path + "TSDocxApplication.tsf", + path + "border\\TSDocxBorder.tsf", + path + "border\\TSDocxBorders.tsf", + path + "TSDocxCell.tsf", + path + "TSDocxCells.tsf", + path + "TSDocxColumn.tsf", + path + "TSDocxColumns.tsf", + path + "TSDocxDocument.tsf", + path + "TSDocxDocuments.tsf", + path + "font\\TSDocxFont.tsf", + path + "listformat\\TSDocxListFormat.tsf", + path + "TSDocxInlineShape.tsf", + path + "TSDocxInlineShapes.tsf", + path + "TSDocxTable.tsf", + path + "TSDocxTables.tsf", + path + "TSDocxTablesOfContents.tsf", + path + "paragraphformat\\TSDocxParagraphFormat.tsf", + path + "TSDocxParagraphs.tsf", + path + "TSDocxParagraph.tsf", + path + "TSDocxRange.tsf", + path + "TSDocxRows.tsf", + path + "TSDocxRow.tsf", + path + "shading\\TSDocxShading.tsf", + ); + // files := array( + // path + "TSDocxTables.tsf", + // ); + for i:=0 to length(files)-1 do + begin + file := files[i]; + name := ExtractFileName(file); + name := name[7:length(name)-4]; + AddTitle(ActiveDocument, name, 2); + + methods := array(); + properties := array(); + LoadClassInfo(file, methods, properties); + AddMethods(ActiveDocument, methods); + AddProperties(ActiveDocument, properties); + println("file = {}, is OK!", file); + end +End; + +Function AddMethods(ActiveDocument, arr); +Begin + if not istable(arr) then return; + methods := array(); + for k, v in arr do + if v = 2 then methods[k] := v; + for k, v in arr do + methods[k] := v; + + AddTitle(ActiveDocument, "方法支持情况", 3); + para := ActiveDocument.Paragraphs.Last; + row := length(methods) + 1; + para.Range.Collapse(TSDocxEnumerations.wdCollapseEnd()); + table := ActiveDocument.Tables.Add(Range := para.Range, NumRows := row, NumColumns := 2, DefaultTableBehavior := TSDocxEnumerations.wdWord9TableBehavior); + table.Columns(1).Width := 220; + table.Columns(2).Width := 220; + + init_title := function(cell, title); + begin + cell.Shading.Texture := TSDocxEnumerations.wdTexture12Pt5Percent; + cell.Shading.ForegroundPatternColor := TSDocxEnumerations.wdColorAutomatic; + cell.Shading.BackgroundPatternColorIndex := TSDocxEnumerations.wdTurquoise; + cell.Shading.Apply(); + cell.Range.Text := title; + cell.Range.Font.Bold := true; + cell.Range.Font.Size := 14; + cell.Range.Font.ColorIndex := TSDocxEnumerations.wdRed(); + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + border := cell.Borders(TSDocxEnumerations.wdBorderBottom); + border.LineStyle := TSDocxEnumerations.wdLineStyleTriple(); + border.ColorIndex := TSDocxEnumerations.wdBlue(); + border.Apply(); + end + ##init_title(table.Cell(1, 1), "VBA函数"); + ##init_title(table.Cell(1, 2), "TSVBA是否支持"); + i := 2; + for k, v in methods do + begin + cell := table.Cell(i, 1); + cell.Range.Text := k; + cell.Range.Font.NameAscii := "Consolas"; + cell.Range.Font.NameFarEast := "微软雅黑"; + cell.Range.Font.Size := 11; + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + cell := table.Cell(i, 2); + cell.Range.Text := v = 2 ? "✅" : "❌"; + cell.Range.Font.NameAscii := "Segoe UI Emoji"; + cell.Range.Font.NameOther := "Segoe UI Emoji"; + cell.Range.Font.NameBi := "Segoe UI Emoji"; + cell.Range.Font.Size := 11; + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + i++; + end +End; + +Function AddProperties(ActiveDocument, arr); +Begin + if not istable(arr) then return; + properties := array(); + for k, v in arr do + if v["r"] = 2 or v["w"] = 2 then properties[k] := v; + for k, v in arr do + properties[k] := v; + + AddTitle(ActiveDocument, "属性支持情况", 3); + + row := length(properties) + 2; + para := ActiveDocument.Paragraphs.Last; + para.Range.Collapse(TSDocxEnumerations.wdCollapseEnd()); + table := ActiveDocument.Tables.Add(Range := para.Range, NumRows := row, NumColumns := 4, DefaultTableBehavior := TSDocxEnumerations.wdWord9TableBehavior); + table.Columns(1).Width := 110; + table.Columns(2).Width := 110; + table.Columns(3).Width := 110; + table.Columns(4).Width := 110; + table.Cell(1, 1).Merge(table.Cell(1, 2)); + table.Cell(1, 3).Merge(table.Cell(1, 4)); + + init_title := function(cell, title); + begin + cell.Shading.Texture := TSDocxEnumerations.wdTexture22Pt5Percent; + cell.Shading.ForegroundPatternColor := TSDocxEnumerations.wdColorAutomatic; + cell.Shading.BackgroundPatternColor := TSDocxEnumerations.wdColorLime; + cell.Shading.Apply(); + cell.Range.Text := title; + cell.Range.Font.Bold := true; + cell.Range.Font.Size := 14; + cell.Range.Font.ColorIndex := TSDocxEnumerations.wdRed(); + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + border := cell.Borders(TSDocxEnumerations.wdBorderBottom); + border.LineStyle := TSDocxEnumerations.wdLineStyleTriple(); + border.ColorIndex := TSDocxEnumerations.wdBlue(); + border.Apply(); + end + ##init_title(table.Cell(1, 1), "VBA属性"); + ##init_title(table.Cell(1, 3), "TSVBA是否支持"); + init_info := function(cell, content); + begin + cell.Range.Text := content; + cell.Range.Font.NameAscii := "Consolas"; + cell.Range.Font.NameFarEast := "微软雅黑"; + cell.Range.Font.Size := 12; + cell.Range.Font.ColorIndex := TSDocxEnumerations.wdViolet(); + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + cell.Shading.Texture := TSDocxEnumerations.wdTexture7Pt5Percent; + cell.Shading.ForegroundPatternColor := TSDocxEnumerations.wdColorAutomatic; + cell.Shading.BackgroundPatternColor := TSDocxEnumerations.wdColorGray30; + cell.Shading.Apply(); + end + ##init_info(table.Cell(2, 1), "属性名称"); + ##init_info(table.Cell(2, 2), "读写"); + ##init_info(table.Cell(2, 3), "读"); + ##init_info(table.Cell(2, 4), "写"); + + i := 3; + for k, v in properties do + begin + cell := table.Cell(i, 1); + // println("k = {}", k); + cell.Range.Text := k; + cell.Range.Font.NameAscii := "Consolas"; + cell.Range.Font.NameFarEast := "微软雅黑"; + cell.Range.Font.Size := 11; + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + + content := ""; + if v["r"] then content += "读"; + if v["w"] then content += "/写"; + cell := table.Cell(i, 2); + cell.Range.Text := content; + cell.Range.Font.NameAscii := "Consolas"; + cell.Range.Font.NameFarEast := "微软雅黑"; + cell.Range.Font.Size := 11; + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + + r := v["r"] = 2 ? "✅" : "❌"; + cell := table.Cell(i, 3); + cell.Range.Text := r; + cell.Range.Font.NameAscii := "Segoe UI Emoji"; + cell.Range.Font.NameOther := "Segoe UI Emoji"; + cell.Range.Font.NameBi := "Segoe UI Emoji"; + cell.Range.Font.Size := 11; + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + + font := cell.Range.Font; + w := v["w"] = 2 ? "✅" : "❌"; + cell := table.Cell(i, 4); + cell.Range.Text := w; + cell.Range.Font.NameAscii := "Segoe UI Emoji"; + cell.Range.Font.NameOther := "Segoe UI Emoji"; + cell.Range.Font.NameBi := "Segoe UI Emoji"; + cell.Range.Font.Size := 11; + cell.Range.Font.Apply(); + cell.Range.ParagraphFormat.Alignment := TSDocxEnumerations.wdAlignParagraphCenter(); + cell.Range.ParagraphFormat.Apply(); + i++; + end +End; + +Function FAQ(ActiveDocument); +Begin + ActiveDocument.Paragraphs.Add; + AddTitle(ActiveDocument, "FAQ", 1); + + AddTitle(ActiveDocument, "TSVBA在使用上有哪些特别的地方", 2); + FAQContent(ActiveDocument, "TSVBA重载了[]运算符,对于诸如Documents, Paragraphs, Tables, Borders等,均可用[]获取对应的对象"); + FAQContent(ActiveDocument, "Documents := ActiveDocument.Documents; // 获取Documents对象"); + FAQContent(ActiveDocument, "Document := Documents[2]; // 等价于 Documents.Item(2);"); + + AddTitle(ActiveDocument, "为什么设置了Font, Shading等时未生效", 2); + FAQContent(ActiveDocument, "考虑到性能问题,类似xxx.Range.Font.Size := 10;并不会立即生效,需要手动调用Apply方法,如:"); + FAQContent(ActiveDocument, "paragraph.Range.Font.Name := 'Consolas';"); + FAQContent(ActiveDocument, "paragraph.Range.Font.Size := 12;"); + FAQContent(ActiveDocument, "paragraph.Range.Font.Apply();"); + FAQContent(ActiveDocument, "注意一:在应用Font, Shading, ParagraphFormat, border, ListFormat以及InlineShape时均需要执行Apply方法使得设置生效"); + FAQContent(ActiveDocument, "注意二:使用这些类时,最多支持到两级赋值,比如说paragraph.Range.Font中,Range是第一级,paragraph是第二级。若使用paragraphs.Item(1).Range.Font,则不会生效。这里出现了第三级Paragraphs"); + + AddTitle(ActiveDocument, "如何使用VBA中的Enumerations", 2); + FAQContent(ActiveDocument, "用了TSL的Unit特性,将用到的枚举项均封装到了TSDocxEnumerations中"); + FAQContent(ActiveDocument, "Uses TSDocxEnumerations;"); + FAQContent(ActiveDocument, "xxx := TSDocxEnumerations.WdBlack;"); + + AddTitle(ActiveDocument, "为什么目录无法计算页码", 2); + FAQContent(ActiveDocument, "由于目录页码计算比较复杂,目前仅提供生成目录项功能,不支持页码的计算。"); + FAQContent(ActiveDocument, "另外使用TablesOfContents.Add生成目录时,仅支持Range, UpperHeadingLevel, LowerHeadingLevel三个参数的设置,其余参数设置均无效。"); + + AddTitle(ActiveDocument, "为什么添加图片的FileName参数不生效", 2); + FAQContent(ActiveDocument, "因为TSVBA中,FileName是一个二进制格式,需要传入的是图片的二进制内容,而不是路径"); +End; + +Function FAQContent(ActiveDocument, text); +Begin + ActiveDocument.Paragraphs.Add; + para := ActiveDocument.Paragraphs.Last; + para.Range.Text := text; + para.Range.Font.Name := "Consolas"; + para.Range.Font.NameAscii := "Consolas"; + para.Range.Font.NameFarEast := "微软雅黑"; + para.Range.Font.Size := 12; + para.Range.Font.Apply(); + para.Format.CharacterUnitFirstLineIndent := 2; + para.Format.FirstLineIndent := 20; + para.Format.Apply(); +End; + +Function AddTablesOfContents(ActiveDocument); +Begin + range := ActiveDocument.Paragraphs(16).Range; + // println("range.text = {}", range.Text); + range.Collapse(TSDocxEnumerations.wdCollapseStart()); + ActiveDocument.TablesOfContents.Add(Range := range, UseHeadingStyles := true, UpperHeadingLevel := 1, LowerHeadingLevel := 9); +End; + +Function LoadClassInfo(f, methods, properties); +Begin + [err,fh] := io_open(f); + if err then return t; + [err, data] := io_read(fh); + io_close(fh); + if err then return t; + + lines := str2array(string(data), "\n"); + flag := true; + for i:=0 to length(lines)-1 do + begin + line := lines[i]; + if AnsiContainsText(line, "// Methods") then flag := false; + if AnsiContainsText(line, "// Properties") then flag := true; + + if not flag and ParseRegExpr("\\s\+Function\\s\+(\\w+)\\(", line, "i", result, MPos, Mlen) and length(result) then + methods[result[0][1]] := 1; + if AnsiContainsText(line, "property") then + begin + ParseRegExpr("\\s\+property\\s\+(\\w+)\\s\+read\\s\+(\\w+)(\\s\+write\\s\+(\\w+))\?", line, "", result, MPos, Mlen); + if not istable(result) then continue; + rw := array(); + if result[0][2] then rw["r"] := 1; + if result[0][4] then rw["w"] := 1; + properties[result[0][1]] := rw; + end + if AnsiContainsText(line, "End;") then break; + end + for j:=i to length(lines)-1 do + begin + line := lines[j]; + if not AnsiContainsText(line, "Function") then continue; + if ParseRegExpr("Function\\s\+.*\\.(\\w+)\\(", line, "i", result, MPos, Mlen) and istable(result) then + begin + name := result[0][1]; + if not name then continue; + if methods[name] then + begin + methods[name] := 2; + continue; + end + if AnsiContainsText(name, "Read") then + begin + rname := name[5:]; + if properties[rname] then properties[rname]["r"] := 2; + end + else if AnsiContainsText(name, "Write") then + begin + wname := name[6:]; + if properties[wname] then properties[wname]["w"] := 2; + end + end + end +End; + +Function Test(); +Begin + line := "Function TSDocxTables.Add(Range, NumRows, NumColumns, DefaultTableBehavior, AutoFitBehavior);"; + ParseRegExpr("Function\\s\+.*\\.(\\w+)\\(", line, "i", result, MPos, Mlen); + println("result = {}", result); +End;