В комментарии к вашему вопросу о том, как избежать ограничения 255 ( Как обойти ограничение 255 символов в MSWord Search & Replace с помощью OLE ), я упомянул переменные документа как, возможно, более простой способ добавить время выполнения содержание в текстовый документ.
Я думаю, что они также являются ответом на то, что вы хотите сделать здесь. Тем не менее, они не совсем интуитивно понятны для конечных пользователей, поэтому было бы неплохо оставить и заполнители. К сожалению, это не совсем возможно, потому что вы получите документ, содержащий заполнитель и поле переменной документа. И это в конечном итоге приведет к повторению значений.
Тем не менее, мы можем сохранить заполнители для конечных пользователей. Конечно, для их первоначального редактирования «шаблона». И даже для добавления новых заполнителей в существующий текстовый документ, который уже «преобразован в использование переменных».
Код ниже показывает, как это сделать. Я не включил «стандартные» части автоматизации Word - открытие и закрытие Word и / или документа. Я начну с того момента, когда вы использовали шаблон для открытия нового документа и теперь готовы начать замену значений. Решение заключается в трех методах:
HideExistingFieldCodes(Doc);
AddFieldDocVarsToPlaceHolders(Doc);
SetValuesForDocVars(Doc);
HideExistingFieldCodes необходим, потому что мы используем заполнители в качестве имен для переменных документа, и если поля показывают их коды вместо их значений, мы в конечном итоге заменим имя переменной документа новой переменной документа, и это будет возможно, громко заставит Ворда говорить.
procedure HideExistingFieldCodes(const Doc: WordDocument);
var
i: Integer;
begin
for i := 1 to Doc.Fields.Count do begin
// Only interested in document variables.
if Doc.Fields.Item( i ).Type_ = wdFieldDocVariable then begin
Doc.Fields.Item( i ).ShowCodes := False;
end;
end;
// Do not call Doc.Fields.Update, because that will show all fields' code again.
// Doc.Fields.Update;
end;
После того как коды любых существующих полей были скрыты, мы можем отсканировать документ на наличие заполнителей и заменить каждое из них на поле переменной документа.
procedure AddFieldDocVarsToPlaceHolders(const Doc: WordDocument);
var
i: Integer;
OleTrue: OleVariant;
OleFalse: OleVariant;
OleEmpty: OleVariant;
FindText: OleVariant;
Replace: OleVariant;
FieldType: OleVariant;
NewField: Field;
begin
OleTrue := True;
OleFalse := False;
OleEmpty := '';
Replace := wdReplaceOne;
FieldType := wdFieldDocVariable;
// Skip the titles.
for i := 1 to PlaceHoldersEdit.Strings.Count do begin
FindText := Format('%s', [PlaceHoldersEdit.Keys[i]]);
FWord.Selection.SetRange(0, 0); // Back to the beginning of the document.
while FWord.Selection.Find.ExecuteOld({FindText}FindText, {MatchCase}EmptyParam, {MatchWholeWord}EmptyParam,
{MatchWildcards}EmptyParam, {MatchSoundsLike}EmptyParam, {MatchAllWordForms}EmptyParam, {Forward}OleTrue,
{Wrap}OleFalse, {Format}EmptyParam, {ReplaceWith}OleEmpty, {Replace}Replace )
do begin
NewField := FWord.Selection.Fields.Add({Range}FWord.Selection.Range, {Type_}FieldType, {Text}FindText, {PreserveFormatting}OleTrue);
NewField.ShowCodes := False; // Make sure document variable name is hidden
// Select this field and set selection to the end of its definition, making
// doubly sure we won't find its name and replace it again.
NewField.Select;
FWord.Selection.SetRange(FWord.Selection.End_, FWord.Selection.End_);
end;
end;
end;
Я использовал TValueListEditor (с именем PlaceHoldersEdit) для хранения имен и значений заполнителей. Его первая строка содержит заголовки столбцов в этом элементе управления и пропускается. После этого необходимо выполнить цикл по всем заполнителям и каждому циклу вхождения в документе Word.
Затем, наконец, мы можем начать добавлять фактические переменные документа, которые будут содержать значения для полей переменных документа. (О, как я люблю все эти похожие звучащие имена.)
procedure SetValuesForDocVars(const Doc: WordDocument);
function ExtractVarNameFromField(VarCode: WideString): OleVariant;
var
s: string;
i: Integer;
begin
// Code Text: DOCVARIABLE Naam \* MERGEFORMAT
// Code Text: DOCVARIABLE Naam
s := Trim(VarCode);
Delete(s, 1, Length('DOCVARIABLE '));
i := Pos('\* MERGEFORMAT', s);
if i > 0 then begin
Delete(s, i, Length('\* MERGEFORMAT'));
end;
Result := Trim(s); // Somebody might have added extra spaces by hand...
end;
function PlaceHolderValue(const aKey: string): string;
begin
Result := PlaceHoldersEdit.Values[aKey];
end;
function ReplaceCrLfWithCr(const aSource: string): string;
begin
Result := StringReplace(aSource, #13#10, #13, [rfReplaceAll]);
end;
var
i: Integer;
OleVarName: OleVariant;
OleVarValue: OleVariant;
DocVar: Variable;
begin
for i := 1 to Doc.Fields.Count do begin
// Only interested in document variable fields.
if Doc.Fields.Item( i ).Type_ = wdFieldDocVariable then begin
OleVarName := ExtractVarNameFromField( Doc.Fields.Item( i ).Code.Text );
OleVarValue := ReplaceCrLfWithCr(PlaceHolderValue(OleVarName));
// Word removes fields/variables with an empty string as their value,
// adding a space prevents that.
if OleVarValue = '' then begin
OleVarValue := ' ';
end;
DocVar := Doc.Variables.Item(OleVarName);
if VarIsNull(DocVar) then begin
Doc.Variables.Add( OleVarName, OleVarValue );
end else begin
DocVar.Value := OleVarValue;
end;
end;
end;
Doc.Fields.Update;
Doc.Fields.ToggleShowCodes;
end;
В этом методе я зацикливаю все поля переменных документа и извлекаю имя переменной из кода каждого поля. Затем я пытаюсь найти переменную документа с таким именем. Если его еще нет, я добавляю его. Если он существует, я изменяю его значение. Если производительность является проблемой, а имя переменной используется во многих полях, это можно было бы немного оптимизировать, чтобы изменить значение только один раз.
О, я проверил с "сохраненным" документом, но я не зашел так далеко, как добавление новых заполнителей в документ, который уже был преобразован в заполнители в переменные поля документа. Так что, возможно, вам все равно придется немного сгладить ситуацию.
Кстати: в Word Shft-F9 переключает поле между отображением его кода и отображением его значения. Вам придется использовать диалоговое окно «Параметры» (Word2003, не знаю, где он оказался в более поздних версиях), чтобы показать / скрыть их всех одним махом. Параметр «Коды полей» в разделе «Показать» или «Показать» на вкладке «Показать» или «Просмотр» (перевод с голландского).