Fields/Widgets and PDF form fill

<< 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