<< Click to Display Table of Contents >> Navigation: Tasks > Fields/Widgets and PDF form fill |
You need WPViewPDF PLUS to work width fields.
Also see the next chapter "PDF Forms" for information about the interactive form filling.
1) Get data from form, set data in form using code
Currently supported are text fields and checkboxes.
This code can be used to load all fields into a value list:
var i, l : Integer;
s : AnsiString;
begin
i := 0;
SetLength(FieldToIndex, 100);
repeat
l := WPViewPDF1.CommandEx(COMPDF_ACRO_GET, i);
if l>0 then
begin
SetLength(s, l);
WPViewPDF1.CommandEx(COMPDF_GetTextBuf, Integer(PAnsiChar(s)));
l := Pos('=', s);
if l=0 then l := Length(s)+1;
if Length(FieldToIndex)<=FieldValues.RowCount then
SetLength(FieldToIndex, FieldValues.RowCount+100);
FieldValues.InsertRow(Copy(s,1,l-1), Copy(s,l+1,Length(s)), true);
// Save the index of the field.
FieldToIndex[ FieldValues.RowCount-1 ] := i;
end;
inc(i);
until l<0;
end;
Here we use the command COMPDF_ACRO_GET - it retrieves the name and value of a field with a certain number in the range [0..N]. The value is separated by '='. If the number is too high, -1 is returned.
You can use the number -1 to initialize the internal AcroField table. It is always initialized after the viewer was cleared.
The "Value" of a field is usually the text stored in it. In case of checkboxes (Fieldtype = "Btn") the value will be 0 or 1. If the field text is "Off", 0 will be used, if the other name used by the definition of the field, 1 will be used.
This basically means that You can expect the value always to be 1 and 0 for checkboxes, although in PDF the checked state may have different names, usually "Yes" but not always.
It is possible to read a special ID for a field using
id := WPViewPDF1.CommandEx(COMPDF_ACRO_GET, Cardinal(-3));
The ID can be later used to select a certain field in case you use the interactive form filling
Use the number -4 to extract all field names as XML script, use -5 to get a comma separated list of all fields.
To write the field value this command can be used
CommandStrEx(COMPDF_ACRO_SET, NewValueString, FieldIndex);
In case of checkboxes "0" and "1" will be translated to "Off" and "Yes" (or the other name used in appearance stream).
Values for combobox fields (Fieldtype="Ch") can also be written. Right now it is not verified, that the new value is part of the "Opt" array - however the index is set accordingly, if the value is part of that list.
In case of text fields a new appearance stream will be created or an existing will be replaced. This makes sure, the screen is not only updated, but also when the PDF is written, the new value will be displayed by other PDF readers.
If Acro_Set was used, since version 3.11.6 WPViewPDF will write the parameter "NeedAppearances true" into the acroform object to make sure, Acrobat Reader displays the current values.
Example: This code fills a scrollbox with labels, edits and checkboxes.
procedure TWPViewPDFDemo.LoadAcroFieldsExClick(Sender: TObject);
var i, l, y, x, id : Integer;
s, ts : WideString;
sa : AnsiString;
ctrl : TControl;
lab : TLabel;
ed : TEdit;
chk : TCheckBox;
begin
FFields.Clear;
FieldScroll.Visible := false;
for I := FieldScroll.ControlCount - 1 downto 0 do
begin
ctrl := FieldScroll.Controls[i];
ctrl.Parent := nil;
ctrl.Free;
end;
i := 0;
y := 0;
x := 96;
SetLength(FieldToIndex, 100);
repeat
ts := WPViewPDF1.CommandGetStr(COMPDF_ACRO_GET,'FT', i);
// Get AcroID
id := WPViewPDF1.CommandEx(COMPDF_ACRO_GET, Cardinal(-3));
l := WPViewPDF1.CommandEx(COMPDF_ACRO_GET, i);
if (l>0) and ((ts='Ch') or (ts='Tx') or (ts='Btn')) then
begin
SetLength(s, l);
WPViewPDF1.CommandEx(COMPDF_GetTextBufW, Integer(PWideChar(s)));
l := Pos('=', s);
if l=0 then l := Length(s)+1;
lab := TLabelEx.Create(FieldScroll);
TLabelEx(lab).FID := id;
lab.Caption := Copy(s,1,l-1);
lab.Parent := FieldScroll;
lab.Left := 2;
lab.Top := y;
lab.Height := 18;
lab.Width := x - 2;
lab.Color := clHighlight;
lab.OnClick := FieldLabelClick; // procedure FieldLabelClick see below
FFields.Add(lab);
if ts='Btn' then
begin
chk := TCheckBoxEx.Create(FieldScroll);
TCheckBoxEx(chk).FID := id;
chk.Tag := i;
chk.Parent := FieldScroll;
chk.Left := x;
chk.Top := y;
chk.Height := 18;
chk.Width := 120;
chk.OnClick := FieldScrolUpdate;
chk.Checked := Copy(s,l+1,Length(s))='1';
FFields.Add(chk);
end else
begin
ed := TeditEx.Create(FieldScroll);
TeditEx(ed).FID := id;
ed.Text := Copy(s,l+1,Length(s));
ed.Tag := i;
ed.Parent := FieldScroll;
ed.Left := x;
ed.Top := y;
ed.Height := 18;
ed.Width := 120;
ed.OnChange := FieldScrolUpdate;
FFields.Add(ed);
end;
inc(y, 20);
end;
inc(i);
until l<0;
FieldScroll.Visible := true;
WPViewPDF1SelectDrawObject(nil,0);
end;
procedure TWPViewPDFDemo.FieldScrolUpdate(Sender: TObject);
begin
if Sender is TCheckBox then
begin
if TCheckBox(Sender).Checked then
WPViewPDF1.CommandStrEx(COMPDF_ACRO_SET,
'1', TCheckBox(Sender).Tag)
else WPViewPDF1.CommandStrEx(COMPDF_ACRO_SET,
'Off', TCheckBox(Sender).Tag);
end else if Sender is TEdit then
begin
WPViewPDF1.CommandStrEx(COMPDF_ACRO_SET,
TEdit(Sender).Text, TCheckBox(Sender).Tag)
end;
end;
procedure TWPViewPDFDemo.CurrObjChange(Sender: TObject);
begin
WPViewPDF1.CommandStrEx(COMPDF_ACRO_SET,
TEdit(Sender).Text, Cardinal(-2));
end;
2) Activate interactive form filling:
Activate the flag wpAllowFormEdit in the ViewOptions!
For interactive form filling the text and checkbox form fields have to be converted to draw objects first.
This is done by command COMPDF_ACRO_MAKEDRAWOBJ (=117):
WPViewPDF1.CommandStrEx(COMPDF_ACRO_MAKEDRAWOBJ,'',2+8+16);
This commmand converts Acroform fields and annotations into draw objects. This makes the fields EDITABLE!
After that command it is possible to move them however it is not recommended to use the command COMPDF_RenderDrawobjects
The following flags are possible in IntPar
1: The created objects cannot be selected
2: The created objects cannot be moved (create locked objects)
8: Create objects only for selected annotations:
16: only Widgets (editfields, checkboxes ...)
32: only Highlights
64: only Links
128: only FreeText
256: only squares
512: only popups
1024: Read the Annotation F property to select locked and redonly state
2048: Prohibit sizing of the objects (moving is not disabled)
4096: Prohibit edit mode for the widgets (=readonly)
8192: Automatic Mode - whenever a new PDF is loaded, COMPDF_ACRO_MAKEDRAWOBJ is executed with the
given parameters! We recommend to use this for a PDF viewer which should be used to edit PDF forms.
The string parameter can further list the annots which are converted or
which are NOT converted, i.e. +all, -all, +popup, -popup
You want to convert the fields into draw objects also without using wpAllowFormEdit. In this case the fields are still selectable.
You can use the ID read with CommandEx(COMPDF_ACRO_GET, Cardinal(-3)) to get and change the current field selection, for example to select the current field which is displayed outside of the PDF in Your application.
This code select a certain field in the PDF form after a click on a label:
procedure TWPViewPDFDemo.FieldLabelClick(Sender: TObject);
begin
WPViewPDF1.command(COMPDF_DrawObjectDeSelectAll);
WPViewPDF1.command(COMPDF_DrawObjectSelect, TLabelEx(Sender).FID );
end;
You can use the list SelectedDrawObjects inside the event OnSelectedDrawObjects to check which objects are currently selected:
Example - we use a TLabelEx and TEditEx control which has an additional FID element to store the ID. We do not use the Tag, since we use that already for the index of the field.
procedure TWPViewPDFDemo.WPViewPDF1SelectDrawObject
(Sender: TObject; const ObjID: Integer);
var
I, J, ID : Integer;
ctrl : TControl;
begin
for J := 0 to FFields.Count - 1 do
begin
ctrl := TControl(FFields[J]);
if ctrl is TLabelEx then
begin
TLabelEx(ctrl).Transparent := true;
end;
end;
for I := 0 to WPViewPDF1.SelectedDrawObjects.Count - 1 do
begin
WPViewPDF1.command(COMPDF_DrawObjectGetSelected, I+1 );
ID := WPViewPDF1.command( COMPDF_DrawObjectReadProp , OBJPRP_ACROID);
for J := 0 to FFields.Count - 1 do
begin
ctrl := TControl(FFields[J]);
if ctrl is TEditEx then
begin
if TEditEx(ctrl).FID=ID then
begin
TEditEx(ctrl).SetFocus;
end;
end
else if ctrl is TCheckBoxEx then
begin
if TCheckBoxEx(ctrl).FID=ID then
begin
TCheckBoxEx(ctrl).SetFocus;
end;
end
else if ctrl is TLabelEx then
begin
if TLabelEx(ctrl).FID=ID then
begin
TLabelEx(ctrl).Transparent := false; // Highlights the field
end;
end;
end;
end;
end;
The list SelectedDrawObjects is updated by this code:
var i, j : Integer;
n : String;
begin
FSelectedDrawObjects.Clear;
j := 1;
if CommandEx( COMPDF_DrawObjectGetSelected, 0 )>0 then
repeat
i := CommandEx( COMPDF_DrawObjectGetSelected, j);
if i<>-1 then
begin
n := CommandGetStr( COMPDF_DrawObjectReadProp, '', OBJPRP_NAME );
FSelectedDrawObjects.AddObject(n, TObject(i))
end;
inc(j);
until i=-1;
end;
OnSelectedDrawObjects is triggered by the windows message WM_PDF_DELAYED_UPDATE=$0400 + 88 with wparam=1