> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/core/get-started/samples/interactiveformstest.md).

# Flatten, Create, Modify PDF Forms - InteractiveForms

Sample code for using Apryse SDK with interactive forms (also known as AcroForms).  Sample code provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby and VB.  Creating new fields and widg

Sample code for using Apryse SDK with interactive forms (also known as AcroForms). Capabilities include programatically creating new fields and widget annotations, form filling, modifying existing field values, form templating, and flattening form fields. Sample code provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby and VB.

Learn more about our full [PDF Data Extraction SDK Capabilities](https://apryse.com/capabilities/extraction).

To start your free trial, [get stated with Server SDK](/core/get-started/get-started.md).

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using pdftron;
using pdftron.Common;
using pdftron.SDF;
using pdftron.PDF;
using pdftron.PDF.Annots;

namespace FormsTestCS
{
	/// <summary>
	///---------------------------------------------------------------------------------------
	/// This sample illustrates basic PDFNet capabilities related to interactive 
	/// forms (also known as AcroForms). 
	///---------------------------------------------------------------------------------------
	/// </summary>
	class Class1
	{
		private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
		static Class1() {}
		
		static void Main(string[] args)
		{
			PDFNet.Initialize(PDFTronLicense.Key);

			// Relative path to the folder containing test files.
			// string input_path =  "../../../../TestFiles/";
			string output_path = "../../../../TestFiles/Output/";

			// The vector used to store the name and count of all fields.
			// This is used later on to clone the fields
			Dictionary<string, int> field_names = new Dictionary<string, int>();

			//----------------------------------------------------------------------------------
			// Example 1: Programatically create new Form Fields and Widget Annotations.
			//----------------------------------------------------------------------------------
			try
			{
				using (PDFDoc doc = new PDFDoc())
				{
					// Create a blank new page and add some form fields.
					Page blank_page = doc.PageCreate();

					// Text Widget Creation 
					// Create an empty text widget with black text.
					TextWidget text1 = TextWidget.Create(doc, new Rect(110, 700, 380, 730));
					text1.SetText("Basic Text Field");
					text1.RefreshAppearance();
					blank_page.AnnotPushBack(text1);
					// Create a vertical text widget with blue text and a yellow background.
					TextWidget text2 = TextWidget.Create(doc, new Rect(50, 400, 90, 730));
					text2.SetRotation(90);
					// Set the text content.
					text2.SetText("    ****Lucky Stars!****");
					// Set the font type, text color, font size, border color and background color.
					text2.SetFont(Font.Create(doc, Font.StandardType1Font.e_helvetica_oblique));
					text2.SetFontSize(28);
					text2.SetTextColor(new ColorPt(0, 0, 1), 3);
					text2.SetBorderColor(new ColorPt(0, 0, 0), 3);
					text2.SetBackgroundColor(new ColorPt(1, 1, 0), 3);
					text2.RefreshAppearance();
					// Add the annotation to the page.
					blank_page.AnnotPushBack(text2);
					// Create two new text widget with Field names employee.name.first and employee.name.last
					// This logic shows how these widgets can be created using either a field name string or
					// a Field object
					TextWidget text3 = TextWidget.Create(doc, new Rect(110, 660, 380, 690), "employee.name.first");
					text3.SetText("Levi");
					text3.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_bold));
					text3.RefreshAppearance();
					blank_page.AnnotPushBack(text3);
					Field emp_last_name = doc.FieldCreate("employee.name.last", Field.Type.e_text, "Ackerman");
					TextWidget text4 = TextWidget.Create(doc, new Rect(110, 620, 380, 650), emp_last_name);
					text4.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_bold));
					text4.RefreshAppearance();
					blank_page.AnnotPushBack(text4);

					// Signature Widget Creation (unsigned)
					SignatureWidget signature1 = SignatureWidget.Create(doc, new Rect(110, 560, 260, 610));
					signature1.RefreshAppearance();
					blank_page.AnnotPushBack(signature1);

					// CheckBox Widget Creation
					// Create a check box widget that is not checked.
					CheckBoxWidget check1 = CheckBoxWidget.Create(doc, new Rect(140, 490, 170, 520));
					check1.RefreshAppearance();
					blank_page.AnnotPushBack(check1);
					// Create a check box widget that is checked.
					CheckBoxWidget check2 = CheckBoxWidget.Create(doc, new Rect(190, 490, 250, 540), "employee.name.check1");
					check2.SetBackgroundColor(new ColorPt(1, 1, 1), 3);
					check2.SetBorderColor(new ColorPt(0, 0, 0), 3);
					// Check the widget (by default it is unchecked).
					check2.SetChecked(true);
					check2.RefreshAppearance();
					blank_page.AnnotPushBack(check2);

					// PushButton Widget Creation
					PushButtonWidget pushbutton1 = PushButtonWidget.Create(doc, new Rect(380, 490, 520, 540));
					pushbutton1.SetTextColor(new ColorPt(1, 1, 1), 3);
					pushbutton1.SetFontSize(36);
					pushbutton1.SetBackgroundColor(new ColorPt(0, 0, 0), 3);
					// Add a caption for the pushbutton.
					pushbutton1.SetStaticCaptionText("PushButton");
					pushbutton1.RefreshAppearance();
					blank_page.AnnotPushBack(pushbutton1);

					// ComboBox Widget Creation
					ComboBoxWidget combo1 = ComboBoxWidget.Create(doc, new Rect(280, 560, 580, 610));
					// Add options to the combobox widget.
					combo1.AddOption("Combo Box No.1");
					combo1.AddOption("Combo Box No.2");
					combo1.AddOption("Combo Box No.3");
					// Make one of the options in the combo box selected by default.
					combo1.SetSelectedOption("Combo Box No.2");
					combo1.SetTextColor(new ColorPt(1, 0, 0), 3);
					combo1.SetFontSize(28);
					combo1.RefreshAppearance();
					blank_page.AnnotPushBack(combo1);

					// ListBox Widget Creation
				   ListBoxWidget list1 = ListBoxWidget.Create(doc, new Rect(400, 620, 580, 730));
					// Add one option to the listbox widget.
					list1.AddOption("List Box No.1");
					// Add multiple options to the listbox widget in a batch.
					string[] list_options = new string[2] {"List Box No.2", "List Box No.3"};
					list1.AddOptions(list_options);
					// Select some of the options in list box as default options
					list1.SetSelectedOptions(list_options);
					// Enable list box to have multi-select when editing. 
					list1.GetField().SetFlag(Field.Flag.e_multiselect, true);
					list1.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_italic));
					list1.SetTextColor(new ColorPt(1, 0, 0), 3);
					list1.SetFontSize(28);
					list1.SetBackgroundColor(new ColorPt(1, 1, 1), 3);
					list1.RefreshAppearance();
					blank_page.AnnotPushBack(list1);

					// RadioButton Widget Creation
					// Create a radio button group and add three radio buttons in it. 
					RadioButtonGroup radio_group = RadioButtonGroup.Create(doc, "RadioGroup");
					RadioButtonWidget radiobutton1 = radio_group.Add(new Rect(140, 410, 190, 460));
					radiobutton1.SetBackgroundColor(new ColorPt(1, 1, 0), 3);
					radiobutton1.RefreshAppearance();
					RadioButtonWidget radiobutton2 = radio_group.Add(new Rect(310, 410, 360, 460));
					radiobutton2.SetBackgroundColor(new ColorPt(0, 1, 0), 3);
					radiobutton2.RefreshAppearance();
					RadioButtonWidget radiobutton3 = radio_group.Add(new Rect(480, 410, 530, 460));
					// Enable the third radio button. By default the first one is selected
					radiobutton3.EnableButton();
					radiobutton3.SetBackgroundColor(new ColorPt(0, 1, 1), 3);
					radiobutton3.RefreshAppearance();
					radio_group.AddGroupButtonsToPage(blank_page);

					// Custom push button annotation creation
					PushButtonWidget custom_pushbutton1 = PushButtonWidget.Create(doc, new Rect(260, 320, 360, 360));
					// Set the annotation appearance.
					custom_pushbutton1.SetAppearance(CreateCustomButtonAppearance(doc, false), Annot.AnnotationState.e_normal);
					// Create 'SubmitForm' action. The action will be linked to the button.
					FileSpec url = FileSpec.CreateURL(doc, "http://www.pdftron.com");
					pdftron.PDF.Action button_action = pdftron.PDF.Action.CreateSubmitForm(url);
					// Associate the above action with 'Down' event in annotations action dictionary.
					Obj annot_action = custom_pushbutton1.GetSDFObj().PutDict("AA");
					annot_action.Put("D", button_action.GetSDFObj());
					blank_page.AnnotPushBack(custom_pushbutton1);

					// Add the page as the last page in the document.
					doc.PagePushBack(blank_page);

					// If you are not satisfied with the look of default auto-generated appearance 
					// streams you can delete "AP" entry from the Widget annotation and set 
					// "NeedAppearances" flag in AcroForm dictionary:
					//    doc.GetAcroForm().PutBool("NeedAppearances", true);
					// This will force the viewer application to auto-generate new appearance streams 
					// every time the document is opened.
					//
					// Alternatively you can generate custom annotation appearance using ElementWriter 
					// and then set the "AP" entry in the widget dictionary to the new appearance
					// stream.
					//
					// Yet another option is to pre-populate field entries with dummy text. When 
					// you edit the field values using PDFNet the new field appearances will match 
					// the old ones.
					doc.RefreshFieldAppearances();				

					doc.Save(output_path + "forms_test1.pdf", 0);

					Console.WriteLine("Done.");
				}
			}
			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
			}

			//----------------------------------------------------------------------------------
			// Example 2: 
			// Fill-in forms / Modify values of existing fields.
			// Traverse all form fields in the document (and print out their names). 
			// Search for specific fields in the document.
			//----------------------------------------------------------------------------------
			try  
			{
				using (PDFDoc doc = new PDFDoc(output_path + "forms_test1.pdf"))
				{
					doc.InitSecurityHandler();

					FieldIterator itr;
					for(itr=doc.GetFieldIterator(); itr.HasNext(); itr.Next()) 
					{
						Field field = itr.Current();
						string cur_field_name = field.GetName();
						// Add one to the count for this field name for later processing
						field_names[cur_field_name] = (field_names.ContainsKey(cur_field_name) ? field_names[cur_field_name] + 1 : 1);

						Console.WriteLine("Field name: {0}", field.GetName());
						Console.WriteLine("Field partial name: {0}", field.GetPartialName());
						string str_val = field.GetValueAsString();

						Console.Write("Field type: ");
						Field.Type type = field.GetType();
						switch(type)
						{
						case Field.Type.e_button: 
							Console.WriteLine("Button");
							break;
						case Field.Type.e_radio: 
							Console.WriteLine("Radio button: Value = " + str_val);
							break;
						case Field.Type.e_check: 
							field.SetValue(true);
							Console.WriteLine("Check box: Value = " + str_val);
							break;
						case Field.Type.e_text:
							{
								Console.WriteLine("Text"); 

								// Edit all variable text in the document
								String old_value = "none";
								if (field.GetValue() != null)
									old_value = field.GetValue().GetAsPDFText();

								field.SetValue("This is a new value. The old one was: " + old_value);
							}
							break;
						case Field.Type.e_choice:
							Console.WriteLine("Choice"); 
							break;
						case Field.Type.e_signature:
							Console.WriteLine("Signature"); 
							break;
						}

						Console.WriteLine("------------------------------");
					}

					// Search for a specific field
					Field fld = doc.GetField("employee.name.first");
					if (fld != null) 
					{
						Console.WriteLine("Field search for {0} was successful", fld.GetName());
					}
					else 
					{
						Console.WriteLine("Field search failed.");
					}

					// Regenerate field appearances.
					doc.RefreshFieldAppearances();
					doc.Save(output_path + "forms_test_edit.pdf", 0);
					Console.WriteLine("Done.");
				}
			}
			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
			}

			//----------------------------------------------------------------------------------
			// Sample: Form templating
			// Replicate pages and form data within a document. Then rename field names to make 
			// them unique.
			//----------------------------------------------------------------------------------
			try  
			{
				// Sample: Copying the page with forms within the same document
				using (PDFDoc doc = new PDFDoc(output_path + "forms_test1.pdf"))
				{
					doc.InitSecurityHandler();

					Page src_page = doc.GetPage(1);
					doc.PagePushBack(src_page);  // Append several copies of the second page
					doc.PagePushBack(src_page);	 // Note that forms are successfully copied
					doc.PagePushBack(src_page);
					doc.PagePushBack(src_page);

					// Now we rename fields in order to make every field unique.
					// You can use this technique for dynamic template filling where you have a 'master'
					// form page that should be replicated, but with unique field names on every page. 
					foreach (KeyValuePair<string, int> cur_field in field_names)
					{
						RenameAllFields(doc, cur_field.Key, cur_field.Value);
					}

					doc.Save(output_path + "forms_test1_cloned.pdf", 0);
					Console.WriteLine("Done.");
				}
			}
			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
			}

			//----------------------------------------------------------------------------------
			// Sample: 
			// Flatten all form fields in a document.
			// Note that this sample is intended to show that it is possible to flatten
			// individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
			// that will automatically flatten all fields.
			//----------------------------------------------------------------------------------
			try  
			{
				using (PDFDoc doc = new PDFDoc(output_path + "forms_test1.pdf"))
				{
					doc.InitSecurityHandler();

					bool auto = true;
					if (auto)
					{
						doc.FlattenAnnotations();
					}
					else  // Manual flattening 
					{
						// Traverse all pages
						PageIterator pitr = doc.GetPageIterator();
						for (; pitr.HasNext(); pitr.Next())
						{
							Page page = pitr.Current();
							for (int i = page.GetNumAnnots() - 1; i >= 0; --i)
							{
								Annot annot = page.GetAnnot(i);
								if (annot != null && annot.GetType() == Annot.Type.e_Widget)
								{
									annot.Flatten(page);
								}
							}
						}
					}

					doc.Save(output_path + "forms_test1_flattened.pdf", 0);
					Console.WriteLine("Done.");
				}
			}
			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
			}
			PDFNet.Terminate();
		}

		// field_nums has to be greater than 0.
		static void RenameAllFields(PDFDoc doc, String name, int field_nums = 1)
		{
			Field fld = doc.GetField(name);
			for (int counter = 1; fld != null; ++counter)
			{
				string field_new_name = name;
				int update_count = System.Convert.ToInt32(Math.Ceiling(counter / (double)field_nums));
				fld.Rename(name + "-" + update_count.ToString());
				fld = doc.GetField(name);
			}
		}

		static Obj CreateCustomButtonAppearance(PDFDoc doc, bool button_down) 
		{
			// Create a button appearance stream ------------------------------------
			using (ElementBuilder builder = new ElementBuilder())
			using (ElementWriter writer = new ElementWriter())
			{
				writer.Begin(doc); 

				// Draw background
				Element element = builder.CreateRect(0, 0, 101, 37);
				element.SetPathFill(true);
				element.SetPathStroke(false);
				element.GetGState().SetFillColorSpace(ColorSpace.CreateDeviceGray());
				element.GetGState().SetFillColor(new ColorPt(0.75, 0.0, 0.0));
				writer.WriteElement(element); 

				// Draw 'Submit' text
				writer.WriteElement(builder.CreateTextBegin()); 
		
				element = builder.CreateTextRun("Submit", Font.Create(doc, Font.StandardType1Font.e_helvetica_bold), 12);
				element.GetGState().SetFillColor(new ColorPt(0, 0, 0));

				if (button_down) 
					element.SetTextMatrix(1, 0, 0, 1, 33, 10);
				else 
					element.SetTextMatrix(1, 0, 0, 1, 30, 13);
				writer.WriteElement(element);
				writer.WriteElement(builder.CreateTextEnd());

				Obj stm = writer.End();

				// Set the bounding box
				stm.PutRect("BBox", 0, 0, 101, 37);
				stm.PutName("Subtype", "Form");
				return stm;
			}
		}
	}
}
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

#include <PDF/PDFNet.h>
#include <PDF/PDFDoc.h>
#include <PDF/Annot.h>
#include <PDF/Field.h>
#include <PDF/Font.h>
#include <PDF/ElementBuilder.h>
#include <PDF/ElementWriter.h>
#include <PDF/Annots/Widget.h>
#include <PDF/ViewChangeCollection.h>
#include <PDF/Annots/TextWidget.h>
#include <PDF/Annots/CheckBoxWidget.h>
#include <PDF/Annots/ComboBoxWidget.h>
#include <PDF/Annots/ListBoxWidget.h>
#include <PDF/Annots/PushButtonWidget.h>
#include <PDF/Annots/RadioButtonWidget.h>
#include <PDF/Annots/RadioButtonGroup.h>
#include <PDF/Annots/SignatureWidget.h>
#include <iostream>
#include <map>
#include <cmath>
#include "../../LicenseKey/CPP/LicenseKey.h"

using namespace std;
using namespace pdftron;
using namespace SDF;
using namespace PDF;
using namespace Annots;
//---------------------------------------------------------------------------------------
// This sample illustrates basic PDFNet capabilities related to interactive 
// forms (also known as AcroForms). 
//---------------------------------------------------------------------------------------

// field_nums has to be greater than 0.
void RenameAllFields(PDFDoc& doc, const UString& name, int field_nums = 1)
{
	char tmp[32];
	FieldIterator itr = doc.GetFieldIterator(name);
	for (int counter = 1; itr.HasNext();
		itr = doc.GetFieldIterator(name), ++counter)
	{
		Field f = itr.Current();
		int update_count = int(ceil(counter/(double)field_nums));
		sprintf(tmp, "-%d", update_count);
		f.Rename(name + tmp);	
	}
}

Obj CreateCustomButtonAppearance(PDFDoc& doc, bool button_down) 
{
	// Create a button appearance stream ------------------------------------
	ElementBuilder build;
	ElementWriter writer;
	writer.Begin(doc); 

	// Draw background
	Element element = build.CreateRect(0, 0, 101, 37);
	element.SetPathFill(true);
	element.SetPathStroke(false);
	element.GetGState().SetFillColorSpace(ColorSpace::CreateDeviceGray());
	element.GetGState().SetFillColor(ColorPt(0.75));
	writer.WriteElement(element); 

	// Draw 'Submit' text
	writer.WriteElement(build.CreateTextBegin()); 
	{
		const char* text = "Submit";
		element = build.CreateTextRun(text, UInt32(strlen(text)), Font::Create(doc, PDF::Font::e_helvetica_bold), 12);
		element.GetGState().SetFillColor(ColorPt(0));

		if (button_down) 
			element.SetTextMatrix(1, 0, 0, 1, 33, 10);
		else 
			element.SetTextMatrix(1, 0, 0, 1, 30, 13);
		writer.WriteElement(element);
	}
	writer.WriteElement(build.CreateTextEnd());

	Obj stm = writer.End(); 

	// Set the bounding box
	stm.PutRect("BBox", 0, 0, 101, 37);
	stm.PutName("Subtype","Form");
	return stm;
}

int main(int argc, char *argv[])
{
	int ret = 0;
	PDFNet::Initialize(LicenseKey);

	// Relative path to the folder containing test files.
	// string input_path =  "../../TestFiles/";
	string output_path = "../../TestFiles/Output/";

	// The vector used to store the name and count of all fields.
	// This is used later on to clone the fields
	map<UString, int> field_names;

	//----------------------------------------------------------------------------------
	// Example 1: Programatically create new Form Fields and Widget Annotations.
	//----------------------------------------------------------------------------------
	try  
	{
		PDFDoc doc;
		// Create a blank new page and add some form fields.
		Page blank_page = doc.PageCreate();

		// Text Widget Creation 
		// Create an empty text widget with black text.
		TextWidget text1 = TextWidget::Create(doc, Rect(110, 700, 380, 730));
		text1.SetText(UString("Basic Text Field"));
		text1.RefreshAppearance();
		blank_page.AnnotPushBack(text1);
		// Create a vertical text widget with blue text and a yellow background.
		TextWidget text2 = TextWidget::Create(doc, Rect(50, 400, 90, 730));
		text2.SetRotation(90);
		// Set the text content.
		text2.SetText(UString("    ****Lucky Stars!****"));
		// Set the font type, text color, font size, border color and background color.
		text2.SetFont(Font::Create(doc, Font::e_helvetica_oblique));
		text2.SetFontSize(28);
		text2.SetTextColor(ColorPt(0, 0, 1), 3);
		text2.SetBorderColor(ColorPt(0, 0, 0), 3);
		text2.SetBackgroundColor(ColorPt(1, 1, 0), 3);
		text2.RefreshAppearance();
		// Add the annotation to the page.
		blank_page.AnnotPushBack(text2);
		// Create two new text widget with Field names employee.name.first and employee.name.last
		// This logic shows how these widgets can be created using either a field name string or
		// a Field object
		TextWidget text3 = TextWidget::Create(doc, Rect(110, 660, 380, 690), "employee.name.first");
		text3.SetText(UString("Levi"));
		text3.SetFont(Font::Create(doc, Font::e_times_bold));
		text3.RefreshAppearance();
		blank_page.AnnotPushBack(text3);
		Field emp_last_name = doc.FieldCreate("employee.name.last", Field::e_text, "Ackerman");
		TextWidget text4 = TextWidget::Create(doc, Rect(110, 620, 380, 650), emp_last_name);
		text4.SetFont(Font::Create(doc, Font::e_times_bold));
		text4.RefreshAppearance();
		blank_page.AnnotPushBack(text4);

		// Signature Widget Creation (unsigned)
		SignatureWidget signature1 = SignatureWidget::Create(doc, Rect(110, 560, 260, 610));
		signature1.RefreshAppearance();
		blank_page.AnnotPushBack(signature1);

		// CheckBox Widget Creation
		// Create a check box widget that is not checked.
		CheckBoxWidget check1 = CheckBoxWidget::Create(doc, Rect(140, 490, 170, 520));
		check1.RefreshAppearance();
		blank_page.AnnotPushBack(check1);
		// Create a check box widget that is checked.
		CheckBoxWidget check2 = CheckBoxWidget::Create(doc, Rect(190, 490, 250, 540), "employee.name.check1");
		check2.SetBackgroundColor(ColorPt(1, 1, 1), 3);
		check2.SetBorderColor(ColorPt(0, 0, 0), 3);
		// Check the widget (by default it is unchecked).
		check2.SetChecked(true);
		check2.RefreshAppearance();
		blank_page.AnnotPushBack(check2);

		// PushButton Widget Creation
		PushButtonWidget pushbutton1 = PushButtonWidget::Create(doc, Rect(380, 490, 520, 540));
		pushbutton1.SetTextColor(ColorPt(1, 1, 1), 3);
		pushbutton1.SetFontSize(36);
		pushbutton1.SetBackgroundColor(ColorPt(0, 0, 0), 3);
		// Add a caption for the pushbutton.
		pushbutton1.SetStaticCaptionText("PushButton");
		pushbutton1.RefreshAppearance();
		blank_page.AnnotPushBack(pushbutton1);

		// ComboBox Widget Creation
		ComboBoxWidget combo1 = ComboBoxWidget::Create(doc, Rect(280, 560, 580, 610));
		// Add options to the combobox widget.
		combo1.AddOption("Combo Box No.1");
		combo1.AddOption("Combo Box No.2");
		combo1.AddOption("Combo Box No.3");
		// Make one of the options in the combo box selected by default.
		combo1.SetSelectedOption(UString("Combo Box No.2"));
		combo1.SetTextColor(ColorPt(1, 0, 0), 3);
		combo1.SetFontSize(28);
		combo1.RefreshAppearance();
		blank_page.AnnotPushBack(combo1);

		// ListBox Widget Creation
		ListBoxWidget list1 = ListBoxWidget::Create(doc, Rect(400, 620, 580, 730));
		// Add one option to the listbox widget.
		list1.AddOption("List Box No.1");
		// Add multiple options to the listbox widget in a batch.
		vector<UString> list_options;
		list_options.push_back("List Box No.2");
		list_options.push_back("List Box No.3");
		list1.AddOptions(list_options);
		// Select some of the options in list box as default options
		list1.SetSelectedOptions(list_options);
		// Enable list box to have multi-select when editing. 
		list1.GetField().SetFlag(Field::e_multiselect, true);
		list1.SetFont(Font::Create(doc, Font::e_times_italic));
		list1.SetTextColor(ColorPt(1, 0, 0), 3);
		list1.SetFontSize(28);
		list1.SetBackgroundColor(ColorPt(1, 1, 1), 3);
		list1.RefreshAppearance();
		blank_page.AnnotPushBack(list1);

		// RadioButton Widget Creation
		// Create a radio button group and add three radio buttons in it. 
		RadioButtonGroup radio_group = RadioButtonGroup::Create(doc, "RadioGroup");
		RadioButtonWidget radiobutton1 = radio_group.Add(Rect(140, 410, 190, 460));
		radiobutton1.SetBackgroundColor(ColorPt(1, 1, 0), 3);
		radiobutton1.RefreshAppearance();
		RadioButtonWidget radiobutton2 = radio_group.Add(Rect(310, 410, 360, 460));
		radiobutton2.SetBackgroundColor(ColorPt(0, 1, 0), 3);
		radiobutton2.RefreshAppearance();
		RadioButtonWidget radiobutton3 = radio_group.Add(Rect(480, 410, 530, 460));
		// Enable the third radio button. By default the first one is selected
		radiobutton3.EnableButton();
		radiobutton3.SetBackgroundColor(ColorPt(0, 1, 1), 3);
		radiobutton3.RefreshAppearance();
		radio_group.AddGroupButtonsToPage(blank_page);

		// Custom push button annotation creation
		PushButtonWidget custom_pushbutton1 = PushButtonWidget::Create(doc, Rect(260, 320, 360, 360));
		// Set the annotation appearance.
		custom_pushbutton1.SetAppearance(CreateCustomButtonAppearance(doc, false), Annot::e_normal);
		// Create 'SubmitForm' action. The action will be linked to the button.
		FileSpec url = FileSpec::CreateURL(doc, "http://www.pdftron.com");
		Action button_action = Action::CreateSubmitForm(url);
		// Associate the above action with 'Down' event in annotations action dictionary.
		Obj annot_action = custom_pushbutton1.GetSDFObj().PutDict("AA");
		annot_action.Put("D", button_action.GetSDFObj());
		blank_page.AnnotPushBack(custom_pushbutton1);

		// Add the page as the last page in the document.
		doc.PagePushBack(blank_page);	
		// If you are not satisfied with the look of default auto-generated appearance 
		// streams you can delete "AP" entry from the Widget annotation and set 
		// "NeedAppearances" flag in AcroForm dictionary:
		//    doc.GetAcroForm().PutBool("NeedAppearances", true);
		// This will force the viewer application to auto-generate new appearance streams 
		// every time the document is opened.
		//
		// Alternatively you can generate custom annotation appearance using ElementWriter 
		// and then set the "AP" entry in the widget dictionary to the new appearance
		// stream.
		//
		// Yet another option is to pre-populate field entries with dummy text. When 
		// you edit the field values using PDFNet the new field appearances will match 
		// the old ones.

		//doc.GetAcroForm().PutBool("NeedAppearances", true);
		// NOTE: RefreshFieldAppearances will replace previously generated appearance streams
		doc.RefreshFieldAppearances();

		doc.Save((output_path + "forms_test1.pdf").c_str(), 0, 0);
		cout << "Done." << endl;
	}
	catch(Common::Exception& e)
	{
		cout << e << endl;
		ret = 1;
	}
	catch(...)
	{
		cout << "Unknown Exception" << endl;
		ret = 1;
	}

	//----------------------------------------------------------------------------------
	// Example 2: 
	// Fill-in forms / Modify values of existing fields.
	// Traverse all form fields in the document (and print out their names). 
	// Search for specific fields in the document.
	//----------------------------------------------------------------------------------
	try  
	{
		PDFDoc doc((output_path + "forms_test1.pdf").c_str());
		doc.InitSecurityHandler();

		FieldIterator itr = doc.GetFieldIterator();
		for(; itr.HasNext(); itr.Next()) 
		{
			UString cur_field_name = itr.Current().GetName();

			// Add one to the count for this field name for later processing
			field_names[cur_field_name] = (field_names.count(cur_field_name) ? field_names[cur_field_name] + 1 : 1);

			cout << "Field name: " << itr.Current().GetName() << endl;
			cout << "Field partial name: " << itr.Current().GetPartialName() << endl;
			cout << "Field type: ";
			Field::Type type = itr.Current().GetType();
			UString str_val = itr.Current().GetValueAsString();

			switch(type)
			{
			case Field::e_button: 
				cout << "Button" << endl; 
				break;
			case Field::e_radio: 
				cout << "Radio button: Value = " << str_val << endl; 
				break;
			case Field::e_check: 
				itr.Current().SetValue(true);
				cout << "Check box: Value = " << str_val << endl; 
				break;
			case Field::e_text: 
				{
					cout << "Text" << endl;
					// Edit all variable text in the document
					itr.Current().SetValue(UString("This is a new value. The old one was: ") + str_val);
				}
				break;
			case Field::e_choice: cout << "Choice" << endl; break;
			case Field::e_signature: cout << "Signature" << endl; break;
			}

			cout << "------------------------------" << endl;
		}

		// Search for a specific field
		Field f = doc.GetField("employee.name.first");
		if (f) 
		{
			cout << "Field search for " << f.GetName() << " was successful" << endl;
		}
		else 
		{
			cout << "Field search failed" << endl;
		}

		// Regenerate field appearances.
		doc.RefreshFieldAppearances();
		doc.Save((output_path + "forms_test_edit.pdf").c_str(), 0, NULL);
		cout << "Done." << endl;
	}
	catch(Common::Exception& e)
	{
		cout << e << endl;
		ret = 1;
	}
	catch(...)
	{
		cout << "Unknown Exception" << endl;
		ret = 1;
	}

	//----------------------------------------------------------------------------------
	// Sample: Form templating
	// Replicate pages and form data within a document. Then rename field names to make 
	// them unique.
	//----------------------------------------------------------------------------------
	try  
	{
		// Sample: Copying the page with forms within the same document
		PDFDoc doc((output_path + "forms_test1.pdf").c_str());
		doc.InitSecurityHandler();

		Page src_page = doc.GetPage(1);
		doc.PagePushBack(src_page);  // Append several copies of the first page
		doc.PagePushBack(src_page);	 // Note that forms are successfully copied
		doc.PagePushBack(src_page);
		doc.PagePushBack(src_page);

		// Now we rename fields in order to make every field unique.
		// You can use this technique for dynamic template filling where you have a 'master'
		// form page that should be replicated, but with unique field names on every page. 
		for (map<UString, int>::iterator i = field_names.begin(); i != field_names.end(); i++)
		{
			RenameAllFields(doc, i->first, i->second);
		}

		doc.Save((output_path + "forms_test1_cloned.pdf").c_str(), 0, 0);
		cout << "Done." << endl;
	}
	catch(Common::Exception& e)
	{
		cout << e << endl;
		ret = 1;
	}
	catch(...)
	{
		cout << "Unknown Exception" << endl;
		ret = 1;
	}

	//----------------------------------------------------------------------------------
	// Sample: 
	// Flatten all form fields in a document.
	// Note that this sample is intended to show that it is possible to flatten
	// individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
	// that will automatically flatten all fields.
	//----------------------------------------------------------------------------------
	try  
	{
		PDFDoc doc((output_path + "forms_test1.pdf").c_str());
		doc.InitSecurityHandler();

		// Traverse all pages
		if (true) {
			doc.FlattenAnnotations();
		}
		else // Manual flattening
		{			
			for (PageIterator pitr = doc.GetPageIterator(); 
				pitr.HasNext(); pitr.Next())  
			{
				Page page = pitr.Current();
				for (Int32 i = ((Int32)page.GetNumAnnots()) - 1; i >= 0; --i)
				{
					Annot annot = page.GetAnnot(i);
					if (annot.GetType() == Annot::e_Widget)
					{
						annot.Flatten(page);
					}
				}
			}
		}

		doc.Save((output_path + "forms_test1_flattened.pdf").c_str(), 0, 0);
		cout << "Done." << endl;
	}
	catch(Common::Exception& e)
	{
		cout << e << endl;
		ret = 1;
	}
	catch(...)
	{
		cout << "Unknown Exception" << endl;
		ret = 1;
	}

	PDFNet::Terminate();
	return ret;
}
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

```go
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2021 by PDFTron Systems Inc. All Rights Reserved.
// Consult LICENSE.txt regarding license information.
//---------------------------------------------------------------------------------------

package main
import (
	"fmt"
	"strconv"
	"os"
	"math"
	. "pdftron"
)

import  "pdftron/Samples/LicenseKey/GO"

// Relative path to the folder containing the test files.
var inputPath = "../../TestFiles/"
var outputPath = "../../TestFiles/Output/"

//---------------------------------------------------------------------------------------
// This sample illustrates basic PDFNet capabilities related to interactive 
// forms (also known as AcroForms). 
//---------------------------------------------------------------------------------------

// fieldNums has to be greater than 0.
func RenameAllFields(doc PDFDoc, name string, fieldNums int){
    itr := doc.GetFieldIterator(name)
    counter := 1
    for itr.HasNext(){
        f := itr.Current()
        radioCounter := (int)(math.Ceil(float64(counter/fieldNums)))
        f.Rename(name + "-" + strconv.Itoa(radioCounter))
        itr = doc.GetFieldIterator(name)
        counter = counter + 1
	}
}
func CreateCustomButtonAppearance(doc PDFDoc, buttonDown bool) Obj {
    // Create a button appearance stream ------------------------------------
    build := NewElementBuilder()
    writer := NewElementWriter()
    writer.Begin(doc.GetSDFDoc())
    
    // Draw background
    element := build.CreateRect(0.0, 0.0, 101.0, 37.0)
    element.SetPathFill(true)
    element.SetPathStroke(false)
    element.GetGState().SetFillColorSpace(ColorSpaceCreateDeviceGray())
    element.GetGState().SetFillColor(NewColorPt(0.75, 0.0, 0.0))
    writer.WriteElement(element)
    
    // Draw 'Submit' text
    writer.WriteElement(build.CreateTextBegin())
    text := "Submit"
    element = build.CreateTextRun(text, FontCreate(doc.GetSDFDoc(), FontE_helvetica_bold), 12.0)
    element.GetGState().SetFillColor(NewColorPt(0.0, 0.0, 0.0))
    
    if buttonDown{
        element.SetTextMatrix(1.0, 0.0, 0.0, 1.0, 33.0, 10.0)
	}else{
        element.SetTextMatrix(1.0, 0.0, 0.0, 1.0, 30.0, 13.0)
	}
    writer.WriteElement(element)
    
    writer.WritePlacedElement(build.CreateTextEnd())
    
    stm := writer.End()
    
    // Set the bounding box
    stm.PutRect("BBox", 0.0, 0.0, 101.0, 37.0)
    stm.PutName("Subtype","Form")
    return stm
}    
func main(){
    PDFNetInitialize(PDFTronLicense.Key)
    
    // The map (vector) used to store the name and count of all fields.
    // This is used later on to clone the fields
	fieldNames:= make(map[string]int)
    //----------------------------------------------------------------------------------
    // Example 1: Programatically create new Form Fields and Widget Annotations.
    //----------------------------------------------------------------------------------
    
    doc := NewPDFDoc()

    // Create a blank new page and Add some form fields.
    blankPage := doc.PageCreate()

    // Text Widget Creation 
    // Create an empty text widget with black text.
    text1 := TextWidgetCreate(doc, NewRect(110.0, 700.0, 380.0, 730.0))
    text1.SetText("Basic Text Field")
    text1.RefreshAppearance()
    blankPage.AnnotPushBack(text1)
    // Create a vertical text widget with blue text and a yellow background.
    text2 := TextWidgetCreate(doc, NewRect(50.0, 400.0, 90.0, 730.0))
    text2.SetRotation(90)
    // Set the text content.
    text2.SetText("    ****Lucky Stars!****");
    // Set the font type, text color, font size, border color and background color.
    text2.SetFont(FontCreate(doc.GetSDFDoc(), FontE_helvetica_oblique))
    text2.SetFontSize(28)
    text2.SetTextColor(NewColorPt(0.0, 0.0, 1.0), 3)
    text2.SetBorderColor(NewColorPt(0.0, 0.0, 0.0), 3)
    text2.SetBackgroundColor(NewColorPt(1.0, 1.0, 0.0), 3)
    text2.RefreshAppearance()
    // Add the annotation to the page.
    blankPage.AnnotPushBack(text2)
    // Create two new text widget with Field names employee.name.first and employee.name.last
    // This logic shows how these widgets can be created using either a field name string or
    // a Field object
    text3 := TextWidgetCreate(doc, NewRect(110.0, 660.0, 380.0, 690.0), "employee.name.first")
    text3.SetText("Levi")
    text3.SetFont(FontCreate(doc.GetSDFDoc(), FontE_times_bold))
    text3.RefreshAppearance()
    blankPage.AnnotPushBack(text3)
    empLastName := doc.FieldCreate("employee.name.last", FieldE_text, "Ackerman")
    text4 := TextWidgetCreate(doc, NewRect(110.0, 620.0, 380.0, 650.0), empLastName)
    text4.SetFont(FontCreate(doc.GetSDFDoc(), FontE_times_bold))
    text4.RefreshAppearance()
    blankPage.AnnotPushBack(text4)

    // Signature Widget Creation (unsigned)
    signature1 := SignatureWidgetCreate(doc, NewRect(110.0, 560.0, 260.0, 610.0))
    signature1.RefreshAppearance()
    blankPage.AnnotPushBack(signature1)

    // CheckBox Widget Creation
    // Create a check box widget that is not checked.
    check1 := CheckBoxWidgetCreate(doc, NewRect(140.0, 490.0, 170.0, 520.0))
    check1.RefreshAppearance()
    blankPage.AnnotPushBack(check1)
    // Create a check box widget that is checked.
    check2 := CheckBoxWidgetCreate(doc, NewRect(190.0, 490.0, 250.0, 540.0), "employee.name.check1")
    check2.SetBackgroundColor(NewColorPt(1.0, 1.0, 1.0), 3)
    check2.SetBorderColor(NewColorPt(0.0, 0.0, 0.0), 3)
    // Check the widget (by default it is unchecked).
    check2.SetChecked(true)
    check2.RefreshAppearance()
    blankPage.AnnotPushBack(check2)

    // PushButton Widget Creation
    pushbutton1 := PushButtonWidgetCreate(doc, NewRect(380.0, 490.0, 520.0, 540.0))
    pushbutton1.SetTextColor(NewColorPt(1.0, 1.0, 1.0), 3)
    pushbutton1.SetFontSize(36)
    pushbutton1.SetBackgroundColor(NewColorPt(0.0, 0.0, 0.0), 3)
    // Add a caption for the pushbutton.
    pushbutton1.SetStaticCaptionText("PushButton")
    pushbutton1.RefreshAppearance()
    blankPage.AnnotPushBack(pushbutton1)

    // ComboBox Widget Creation
    combo1 := ComboBoxWidgetCreate(doc, NewRect(280.0, 560.0, 580.0, 610.0));
    // Add options to the combobox widget.
    combo1.AddOption("Combo Box No.1")
    combo1.AddOption("Combo Box No.2")
    combo1.AddOption("Combo Box No.3")
    // Make one of the options in the combo box selected by default.
    combo1.SetSelectedOption("Combo Box No.2")
    combo1.SetTextColor(NewColorPt(1.0, 0.0, 0.0), 3)
    combo1.SetFontSize(28)
    combo1.RefreshAppearance()
    blankPage.AnnotPushBack(combo1)

    // ListBox Widget Creation
    list1 := ListBoxWidgetCreate(doc, NewRect(400.0, 620.0, 580.0, 730.0))
    // Add one option to the listbox widget.
    list1.AddOption("List Box No.1")
    // Add multiple options to the listbox widget in a batch.
    listOptions := NewVectorString()
	listOptions.Add("List Box No.2")
	listOptions.Add("List Box No.3")
    list1.AddOptions(listOptions)
    // Select some of the options in list box as default options
    list1.SetSelectedOptions(listOptions)
    // Enable list box to have multi-select when editing. 
    list1.GetField().SetFlag(FieldE_multiselect, true)
    list1.SetFont(FontCreate(doc.GetSDFDoc(),FontE_times_italic))
    list1.SetTextColor(NewColorPt(1.0, 0.0, 0.0), 3)
    list1.SetFontSize(28)
    list1.SetBackgroundColor(NewColorPt(1.0, 1.0, 1.0), 3)
    list1.RefreshAppearance()
    blankPage.AnnotPushBack(list1)

    // RadioButton Widget Creation
    // Create a radio button group and Add three radio buttons in it. 
    radioGroup := RadioButtonGroupCreate(doc, "RadioGroup")
    radiobutton1 := radioGroup.Add(NewRect(140.0, 410.0, 190.0, 460.0))
    radiobutton1.SetBackgroundColor(NewColorPt(1.0, 1.0, 0.0), 3)
    radiobutton1.RefreshAppearance()
    radiobutton2 := radioGroup.Add(NewRect(310.0, 410.0, 360.0, 460.0))
    radiobutton2.SetBackgroundColor(NewColorPt(0.0, 1.0, 0.0), 3)
    radiobutton2.RefreshAppearance()
    radiobutton3 := radioGroup.Add(NewRect(480.0, 410.0, 530.0, 460.0))
    // Enable the third radio button. By default the first one is selected
    radiobutton3.EnableButton()
    radiobutton3.SetBackgroundColor(NewColorPt(0.0, 1.0, 1.0), 3)
    radiobutton3.RefreshAppearance()
    radioGroup.AddGroupButtonsToPage(blankPage)

    // Custom push button annotation creation
    customPushbutton1 := PushButtonWidgetCreate(doc, NewRect(260.0, 320.0, 360.0, 360.0))
    // Set the annotation appearance.
    customPushbutton1.SetAppearance(CreateCustomButtonAppearance(doc, false), AnnotE_normal)
    // Create 'SubmitForm' action. The action will be linked to the button.
    url := FileSpecCreateURL(doc.GetSDFDoc(), "http://www.pdftron.com")
    buttonAction := ActionCreateSubmitForm(url)
    // Associate the above action with 'Down' event in annotations action dictionary.
    annotAction := customPushbutton1.GetSDFObj().PutDict("AA")
    annotAction.Put("D", buttonAction.GetSDFObj())
    blankPage.AnnotPushBack(customPushbutton1)

	// Add the page as the last page in the document.
    doc.PagePushBack(blankPage)                     
                                     
    // If you are not satisfied with the look of default auto-generated appearance 
    // streams you can delete "AP" entry from the Widget annotation and set 
    // "NeedAppearances" flag in AcroForm dictionary:
    //    doc.GetAcroForm().PutBool("NeedAppearances", true);
    // This will force the viewer application to auto-generate new appearance streams 
    // every time the document is opened.
    //
    // Alternatively you can generate custom annotation appearance using ElementWriter 
    // and then set the "AP" entry in the widget dictionary to the new appearance
    // stream.
    //
    // Yet another option is to pre-populate field entries with dummy text. When 
    // you edit the field values using PDFNet the new field appearances will match 
    // the old ones.

    //doc.GetAcroForm().PutBool("NeedAppearances", true)
    doc.RefreshFieldAppearances()
    
    doc.Save(outputPath + "forms_test1.pdf", uint(0))
    doc.Close()
    fmt.Println("Done.")
    
    //----------------------------------------------------------------------------------
    // Example 2: 
    // Fill-in forms / Modify values of existing fields.
    // Traverse all form fields in the document (and sys.stdout.write(out their names). 
    // Search for specific fields in the document.
    //----------------------------------------------------------------------------------
    
    doc = NewPDFDoc(outputPath + "forms_test1.pdf")
    doc.InitSecurityHandler()
    
    itr := doc.GetFieldIterator()
    for itr.HasNext(){
        curFieldName := itr.Current().GetName()
        // Add one to the count for this field name for later processing
		if val, found := fieldNames[curFieldName]; found{
			fieldNames[curFieldName] = val + 1
		}else{
			fieldNames[curFieldName] = 1
		}

        fmt.Println("Field name: " + itr.Current().GetName())
        fmt.Println("Field partial name: " + itr.Current().GetPartialName())
        os.Stdout.Write([]byte("Field type: "))
        fieldType := itr.Current().GetType()
        strVal := itr.Current().GetValueAsString()
        if (fieldType == FieldE_button){
            os.Stdout.Write([]byte("Button\n"))
		}else if (fieldType == FieldE_radio){
            os.Stdout.Write([]byte("Radio button: Value = " + strVal + "\n"))
		}else if (fieldType == FieldE_check){
            itr.Current().SetValue(true)
            os.Stdout.Write([]byte("Check box: Value = " + strVal + "\n"))
		}else if (fieldType == FieldE_text){
            os.Stdout.Write([]byte("Text" + "\n"))
            // Edit all variable text in the document
            if itr.Current().GetValue().GetMp_obj().Swigcptr() != 0 {
                old_value := itr.Current().GetValueAsString();
                itr.Current().SetValue("This is a new value. The old one was: " + old_value)
			}
		}else if (fieldType == FieldE_choice){
            os.Stdout.Write([]byte("Choice" + "\n"))
		}else if (fieldType == FieldE_signature){
            os.Stdout.Write([]byte("Signature" + "\n"))
		}
        fmt.Println("------------------------------")
        itr.Next()
	}
    // Search for a specific field
    f := doc.GetField("employee.name.first")
    if f.GetMp_field().Swigcptr() != 0{
        fmt.Println("Field search for " + f.GetName() + " was successful")
	}else{
        fmt.Println("Field search failed")
    }
	
    // Regenerate field appearances.
    doc.RefreshFieldAppearances()
    doc.Save(outputPath + "forms_test_edit.pdf", uint(0))
    doc.Close()
    fmt.Println("Done.")
    
    //----------------------------------------------------------------------------------
    // Sample: Form templating
    // Replicate pages and form data within a document. Then rename field names to make 
    // them unique.
    //----------------------------------------------------------------------------------
    
    // Sample: Copying the page with forms within the same document
    doc = NewPDFDoc(outputPath + "forms_test1.pdf")
    doc.InitSecurityHandler()
    
    srcPage := doc.GetPage(1)
    doc.PagePushBack(srcPage) // Append several copies of the first page
    doc.PagePushBack(srcPage) // Note that forms are successfully copied
    doc.PagePushBack(srcPage)
    doc.PagePushBack(srcPage)
    
    // Now we rename fields in order to make every field unique.
    // You can use this technique for dynamic template filling where you have a 'master'
    // form page that should be replicated, but with unique field names on every page.
    for key, curField := range fieldNames{
        RenameAllFields(doc, key, curField)
    }

    doc.Save(outputPath + "forms_test1_cloned.pdf", uint(0))
    doc.Close()
    fmt.Println("Done.")
    
    //----------------------------------------------------------------------------------
    // Sample: 
    // Flatten all form fields in a document.
    // Note that this sample is intended to show that it is possible to flatten
    // individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
    // that will automatically flatten all fields.
    //----------------------------------------------------------------------------------
    doc = NewPDFDoc(outputPath + "forms_test1.pdf")
    doc.InitSecurityHandler()
     
    // Traverse all pages
    if false{
        doc.FlattenAnnotations()
	}else{ // Manual flattening
		for pitr := doc.GetPageIterator(); pitr.HasNext(); pitr.Next(){
			page := pitr.Current()
			for i := int(page.GetNumAnnots()) - 1; i >= 0; i-- {
				annot := page.GetAnnot(uint(i))
				if (annot.GetType() == AnnotE_Widget){
                    annot.Flatten(page)
				}
 			}
		}
	}
    doc.Save(outputPath + "forms_test1_flattened.pdf", uint(0))
    doc.Close()
    PDFNetTerminate()
    fmt.Println("Done.")
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

import com.pdftron.common.PDFNetException;
import com.pdftron.pdf.*;
import com.pdftron.sdf.Obj;
import com.pdftron.sdf.SDFDoc;
import com.pdftron.pdf.annots.*;
import java.util.*;  

//---------------------------------------------------------------------------------------
// This sample illustrates basic PDFNet capabilities related to interactive 
// forms (also known as AcroForms). 
//---------------------------------------------------------------------------------------

public class InteractiveFormsTest {

    // field_nums has to be greater than 0.
    static void renameAllFields(PDFDoc doc, String name, int field_nums) throws PDFNetException {
        FieldIterator itr = doc.getFieldIterator(name);
        for (int counter = 1; itr.hasNext(); itr = doc.getFieldIterator(name), ++counter) {
            Field f = itr.next();
            int update_count = (int)java.lang.Math.ceil(counter/(double)field_nums);
            f.rename(name + "-" + update_count);
        }
    }

    static Obj createCustomButtonAppearance(PDFDoc doc, boolean button_down) throws PDFNetException {
        // Create a button appearance stream ------------------------------------
        ElementBuilder build = new ElementBuilder();
        ElementWriter writer = new ElementWriter();
        writer.begin(doc);

        // Draw background
        Element element = build.createRect(0, 0, 101, 37);
        element.setPathFill(true);
        element.setPathStroke(false);
        element.getGState().setFillColorSpace(ColorSpace.createDeviceGray());
        element.getGState().setFillColor(new ColorPt(0.75, 0, 0));
        writer.writeElement(element);

        // Draw 'Submit' text
        writer.writeElement(build.createTextBegin());
        {
            String text = "Submit";
            element = build.createTextRun(text, Font.create(doc, Font.e_helvetica_bold), 12);
            element.getGState().setFillColor(new ColorPt(0, 0, 0));

            if (button_down)
                element.setTextMatrix(1, 0, 0, 1, 33, 10);
            else
                element.setTextMatrix(1, 0, 0, 1, 30, 13);
            writer.writeElement(element);
        }
        writer.writeElement(build.createTextEnd());

        Obj stm = writer.end();

        // Set the bounding box
        stm.putRect("BBox", 0, 0, 101, 37);
        stm.putName("Subtype", "Form");
        return stm;
    }

    public static void main(String[] args) {
        PDFNet.initialize(PDFTronLicense.Key());

        // Relative path to the folder containing test files.
        // string input_path =  "../../TestFiles/";
        String output_path = "../../TestFiles/Output/";

        // The vector used to store the name and count of all fields.
        // This is used later on to clone the fields
        Map<String, Integer> field_names = new HashMap<String, Integer>();

        //----------------------------------------------------------------------------------
        // Example 1: Programatically create new Form Fields and Widget Annotations.
        //----------------------------------------------------------------------------------
        try (PDFDoc doc = new PDFDoc()) {
            // Create a blank new page and add some form fields.
            Page blank_page = doc.pageCreate();

            // Text Widget Creation 
            // Create an empty text widget with black text.
            TextWidget text1 = TextWidget.create(doc, new Rect(110, 700, 380, 730));
            text1.setText("Basic Text Field");
            text1.refreshAppearance();
            blank_page.annotPushBack(text1);
            // Create a vertical text widget with blue text and a yellow background.
            TextWidget text2 = TextWidget.create(doc, new Rect(50, 400, 90, 730));
            text2.setRotation(90);
            // Set the text content.
            text2.setText("    ****Lucky Stars!****");
            // Set the font type, text color, font size, border color and background color.
            text2.setFont(Font.create(doc, Font.e_helvetica_oblique));
            text2.setFontSize(28);
            text2.setTextColor(new ColorPt(0, 0, 1), 3);
            text2.setBorderColor(new ColorPt(0, 0, 0), 3);
            text2.setBackgroundColor(new ColorPt(1, 1, 0), 3);
            text2.refreshAppearance();
            // Add the annotation to the page.
            blank_page.annotPushBack(text2);
            // Create two new text widget with Field names employee.name.first and employee.name.last
            // This logic shows how these widgets can be created using either a field name string or
            // a Field object
            TextWidget text3 = TextWidget.create(doc, new Rect(110, 660, 380, 690), "employee.name.first");
            text3.setText("Levi");
            text3.setFont(Font.create(doc, Font.e_times_bold));
            text3.refreshAppearance();
            blank_page.annotPushBack(text3);
            Field emp_last_name = doc.fieldCreate("employee.name.last", Field.e_text, "Ackerman");
            TextWidget text4 = TextWidget.create(doc, new Rect(110, 620, 380, 650), emp_last_name);
            text4.setFont(Font.create(doc, Font.e_times_bold));
            text4.refreshAppearance();
            blank_page.annotPushBack(text4);

            // Signature Widget Creation (unsigned)
            SignatureWidget signature1 = SignatureWidget.create(doc, new Rect(110, 560, 260, 610));
            signature1.refreshAppearance();
            blank_page.annotPushBack(signature1);

            // CheckBox Widget Creation
            // Create a check box widget that is not checked.
            CheckBoxWidget check1 = CheckBoxWidget.create(doc, new Rect(140, 490, 170, 520));
            check1.refreshAppearance();
            blank_page.annotPushBack(check1);
            // Create a check box widget that is checked.
            CheckBoxWidget check2 = CheckBoxWidget.create(doc, new Rect(190, 490, 250, 540), "employee.name.check1");
            check2.setBackgroundColor(new ColorPt(1, 1, 1), 3);
            check2.setBorderColor(new ColorPt(0, 0, 0), 3);
            // Check the widget (by default it is unchecked).
            check2.setChecked(true);
            check2.refreshAppearance();
            blank_page.annotPushBack(check2);

            // PushButton Widget Creation
            PushButtonWidget pushbutton1 = PushButtonWidget.create(doc, new Rect(380, 490, 520, 540));
            pushbutton1.setTextColor(new ColorPt(1, 1, 1), 3);
            pushbutton1.setFontSize(36);
            pushbutton1.setBackgroundColor(new ColorPt(0, 0, 0), 3);
            // Add a caption for the pushbutton.
            pushbutton1.setStaticCaptionText("PushButton");
            pushbutton1.refreshAppearance();
            blank_page.annotPushBack(pushbutton1);

            // ComboBox Widget Creation
            ComboBoxWidget combo1 = ComboBoxWidget.create(doc, new Rect(280, 560, 580, 610));
            // Add options to the combobox widget.
            combo1.addOption("Combo Box No.1");
            combo1.addOption("Combo Box No.2");
            combo1.addOption("Combo Box No.3");
            // Make one of the options in the combo box selected by default.
            combo1.setSelectedOption("Combo Box No.2");
            combo1.setTextColor(new ColorPt(1, 0, 0), 3);
            combo1.setFontSize(28);
            combo1.refreshAppearance();
            blank_page.annotPushBack(combo1);

            // ListBox Widget Creation
            ListBoxWidget list1 = ListBoxWidget.create(doc, new Rect(400, 620, 580, 730));
            // Add one option to the listbox widget.
            list1.addOption("List Box No.1");
            // Add multiple options to the listbox widget in a batch.
            String[] list_options = new String[] { "List Box No.2", "List Box No.3" };
            list1.addOptions(list_options);
            // Select some of the options in list box as default options
            list1.setSelectedOptions(list_options);
            // Enable list box to have multi-select when editing. 
            list1.getField().setFlag(Field.e_multiselect, true);
            list1.setFont(Font.create(doc,Font.e_times_italic));
            list1.setTextColor(new ColorPt(1, 0, 0), 3);
            list1.setFontSize(28);
            list1.setBackgroundColor(new ColorPt(1, 1, 1), 3);
            list1.refreshAppearance();
            blank_page.annotPushBack(list1);

            // RadioButton Widget Creation
            // Create a radio button group and add three radio buttons in it. 
            RadioButtonGroup radio_group = RadioButtonGroup.create(doc, "RadioGroup");
            RadioButtonWidget radiobutton1 = radio_group.add(new Rect(140, 410, 190, 460));
            radiobutton1.setBackgroundColor(new ColorPt(1, 1, 0), 3);
            radiobutton1.refreshAppearance();
            RadioButtonWidget radiobutton2 = radio_group.add(new Rect(310, 410, 360, 460));
            radiobutton2.setBackgroundColor(new ColorPt(0, 1, 0), 3);
            radiobutton2.refreshAppearance();
            RadioButtonWidget radiobutton3 = radio_group.add(new Rect(480, 410, 530, 460));
            // Enable the third radio button. By default the first one is selected
            radiobutton3.enableButton();
            radiobutton3.setBackgroundColor(new ColorPt(0, 1, 1), 3);
            radiobutton3.refreshAppearance();
            radio_group.addGroupButtonsToPage(blank_page);

            // Custom push button annotation creation
            PushButtonWidget custom_pushbutton1 = PushButtonWidget.create(doc, new Rect(260, 320, 360, 360));
            // Set the annotation appearance.
            custom_pushbutton1.setAppearance(createCustomButtonAppearance(doc, false), Annot.e_normal);
            // Create 'SubmitForm' action. The action will be linked to the button.
            FileSpec url = FileSpec.createURL(doc, "http://www.pdftron.com");
            Action button_action = Action.createSubmitForm(url);
            // Associate the above action with 'Down' event in annotations action dictionary.
            Obj annot_action = custom_pushbutton1.getSDFObj().putDict("AA");
            annot_action.put("D", button_action.getSDFObj());
            blank_page.annotPushBack(custom_pushbutton1);

            // Add the page as the last page in the document.
            doc.pagePushBack(blank_page);    

            // If you are not satisfied with the look of default auto-generated appearance
            // streams you can delete "AP" entry from the Widget annotation and set
            // "NeedAppearances" flag in AcroForm dictionary:
            //    doc.GetAcroForm().PutBool("NeedAppearances", true);
            // This will force the viewer application to auto-generate new appearance streams
            // every time the document is opened.
            //
            // Alternatively you can generate custom annotation appearance using ElementWriter
            // and then set the "AP" entry in the widget dictionary to the new appearance
            // stream.
            //
            // Yet another option is to pre-populate field entries with dummy text. When
            // you edit the field values using PDFNet the new field appearances will match
            // the old ones.

            //doc.GetAcroForm().Put("NeedAppearances", new Bool(true));
            doc.refreshFieldAppearances();

            doc.save(output_path + "forms_test1.pdf", SDFDoc.SaveMode.NO_FLAGS, null);
            System.out.println("Done.");
        } catch (Exception e) {
            e.printStackTrace();
        }

        //----------------------------------------------------------------------------------
        // Example 2:
        // Fill-in forms / Modify values of existing fields.
        // Traverse all form fields in the document (and print out their names).
        // Search for specific fields in the document.
        //----------------------------------------------------------------------------------
        try (PDFDoc doc = new PDFDoc((output_path + "forms_test1.pdf"))) {
            doc.initSecurityHandler();

            FieldIterator itr = doc.getFieldIterator();
            while (itr.hasNext()) {
                Field current = itr.next();
                String cur_field_name = current.getName();
                // Add one to the count for this field name for later processing
                if (field_names.containsKey(cur_field_name)) {
                    field_names.put(cur_field_name, field_names.get(cur_field_name) + 1);
                }
                else {
                    field_names.put(cur_field_name, 1);
                }

                System.out.println("Field name: " + current.getName());
                System.out.println("Field partial name: " + current.getPartialName());

                System.out.print("Field type: ");
                int type = current.getType();
                String str_val = current.getValueAsString();
                switch (type) {
                    case Field.e_button:
                        System.out.println("Button");
                        break;
                    case Field.e_radio:
                        System.out.println("Radio button: Value = " + str_val);
                        break;
                    case Field.e_check:
                        current.setValue(true);
                        System.out.println("Check box: Value = " + str_val);
                        break;
                    case Field.e_text: {
                        System.out.println("Text");
                        // Edit all variable text in the document
                        String old_value;
                        if (current.getValue() != null) {
                            old_value = current.getValueAsString();
                            current.setValue("This is a new value. The old one was: " + old_value);
                        }
                    }
                    break;
                    case Field.e_choice:
                        System.out.println("Choice");
                        break;
                    case Field.e_signature:
                        System.out.println("Signature");
                        break;
                }

                System.out.println("------------------------------");
            }

            // Search for a specific field
            Field f = doc.getField("employee.name.first");
            if (f != null) {
                System.out.println("Field search for " + f.getName() + " was successful");
            } else {
                System.out.println("Field search failed");
            }

            // Regenerate field appearances.
            doc.refreshFieldAppearances();
            doc.save((output_path + "forms_test_edit.pdf"), SDFDoc.SaveMode.NO_FLAGS, null);
            System.out.println("Done.");
        } catch (Exception e) {
            e.printStackTrace();
        }


        //----------------------------------------------------------------------------------
        // Sample: Form templating
        // Replicate pages and form data within a document. Then rename field names to make
        // them unique.
        //----------------------------------------------------------------------------------
        try (PDFDoc doc = new PDFDoc((output_path + "forms_test1.pdf"))) {
            // Sample: Copying the page with forms within the same document
            doc.initSecurityHandler();

            Page src_page = (Page) (doc.getPage(1));
            doc.pagePushBack(src_page);  // Append several copies of the first page
            doc.pagePushBack(src_page);     // Note that forms are successfully copied
            doc.pagePushBack(src_page);
            doc.pagePushBack(src_page);

            // Now we rename fields in order to make every field unique.
            // You can use this technique for dynamic template filling where you have a 'master'
            // form page that should be replicated, but with unique field names on every page.
            for (String cur_field : field_names.keySet()) {
                renameAllFields(doc, cur_field, field_names.get(cur_field));
            }

            doc.save(output_path + "forms_test1_cloned.pdf", SDFDoc.SaveMode.NO_FLAGS, null);
            System.out.println("Done.");
        } catch (Exception e) {
            e.printStackTrace();
        }


        //----------------------------------------------------------------------------------
        // Sample:
        // Flatten all form fields in a document.
        // Note that this sample is intended to show that it is possible to flatten
        // individual fields. PDFNet provides a utility function PDFDoc.flattenAnnotations()
        // that will automatically flatten all fields.
        //----------------------------------------------------------------------------------
        try (PDFDoc doc = new PDFDoc((output_path + "forms_test1.pdf"))) {
            doc.initSecurityHandler();

            // Traverse all pages
            if (true) {
                doc.flattenAnnotations();
            } else // Manual flattening
            {

                for (PageIterator pitr = doc.getPageIterator(); pitr.hasNext(); ) {
                    Page page = pitr.next();
                    for (int i = page.getNumAnnots() - 1; i >= 0; --i) {
                        Annot annot = page.getAnnot(i);
                        if (annot.getType() == Annot.e_Widget)
                        {
                            annot.flatten(page);
                        }
                    }
                }
            }

            doc.save(output_path + "forms_test1_flattened.pdf", SDFDoc.SaveMode.NO_FLAGS, null);
            System.out.println("Done.");
        } catch (Exception e) {
            e.printStackTrace();
        }

        PDFNet.terminate();
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------
// This sample illustrates basic PDFNet capabilities related to interactive 
// forms (also known as AcroForms). 
//---------------------------------------------------------------------------------------
const { PDFNet } = require('@pdftron/pdfnet-node');
const PDFTronLicense = require('../LicenseKey/LicenseKey');

((exports) => {
  'use strict';

  exports.runInteractiveFormsTest = () => {

    // field_nums has to be greater than 0.
    const RenameAllFields = async (doc, name, field_nums = 1) => {
      let itr = await doc.getFieldIterator(name);
      for (let counter = 0; (await itr.hasNext()); itr = (await doc.getFieldIterator(name)), ++counter) {
        const f = await itr.current();
        const update_count = Math.ceil(counter / field_nums);
        f.rename(name + update_count);
      }
    };

    const CreateCustomButtonAppearance = async (doc, buttonDown) => {
      // Create a button appearance stream ------------------------------------

      const builder = await PDFNet.ElementBuilder.create();
      const writer = await PDFNet.ElementWriter.create();
      writer.begin(doc);

      // Draw background
      let element = await builder.createRect(0, 0, 101, 37);
      element.setPathFill(true);
      element.setPathStroke(false);

      let elementGState = await element.getGState();
      elementGState.setFillColorSpace(await PDFNet.ColorSpace.createDeviceGray());
      elementGState.setFillColorWithColorPt(await PDFNet.ColorPt.init(0.75));
      writer.writeElement(element);

      // Draw 'Submit' text
      writer.writeElement((await builder.createTextBegin()));

      const text = 'Submit';
      const helveticaBoldFont = await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_helvetica_bold);
      element = await builder.createTextRun(text, helveticaBoldFont, 12);
      elementGState = await element.getGState();
      elementGState.setFillColorWithColorPt((await PDFNet.ColorPt.init(0)));

      if (buttonDown) {
        element.setTextMatrixEntries(1, 0, 0, 1, 33, 10);
      } else {
        element.setTextMatrixEntries(1, 0, 0, 1, 30, 13);
      }
      writer.writeElement(element);

      writer.writeElement((await builder.createTextEnd()));

      const stm = await writer.end();

      // Set the bounding box
      await stm.putRect('BBox', 0, 0, 101, 37);
      await stm.putName('Subtype', 'Form');
      return stm;
    };

    const main = async () => {
      const outputPath = '../TestFiles/Output/';

      //----------------------------------------------------------------------------------
      // Example 1: Programatically create new Form Fields and Widget Annotations.
      //----------------------------------------------------------------------------------
      try {
        const doc = await PDFNet.PDFDoc.create();
        doc.initSecurityHandler();

        // Create a blank new page and add some form fields.
        const blankPage = await doc.pageCreate();

        // Text Widget Creation 
        // Create an empty text widget with black text..
        const text1 = await PDFNet.TextWidget.create(doc, await PDFNet.Rect.init(110, 700, 380, 730));
        text1.setText('Basic Text Field');
        await text1.refreshAppearance();
        blankPage.annotPushBack(text1);
        // Create a vertical text widget with blue text and a yellow background.
        const text2 = await PDFNet.TextWidget.create(doc, await PDFNet.Rect.init(50, 400, 90, 730));
        text2.setRotation(90);
        // Set the text content.
        text2.setText('    ****Lucky Stars!****');
        // Set the font type, text color, font size, border color and background color.
        text2.setFont(await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_helvetica_oblique));
        text2.setFontSize(28);
        text2.setTextColor(await PDFNet.ColorPt.init(0, 0, 1), 3);
        text2.setBorderColor(await PDFNet.ColorPt.init(0, 0, 0), 3);
        text2.setBackgroundColor(await PDFNet.ColorPt.init(1, 1, 0), 3);
        await text2.refreshAppearance();
        // Add the annotation to the page.
        blankPage.annotPushBack(text2);
        // Create two new text widget with Field names employee.name.first and employee.name.last
        // This logic shows how these widgets can be created using either a field name string or
        // a Field object
        const text3 = await PDFNet.TextWidget.create(doc, await PDFNet.Rect.init(110, 660, 380, 690), 'employee.name.first');
        text3.setText('Levi');
        text3.setFont(await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_times_bold));
        await text3.refreshAppearance();
        blankPage.annotPushBack(text3);
        const empLastName = await doc.fieldCreateFromStrings('employee.name.last', PDFNet.Field.Type.e_text, 'Ackerman');
        const text4 = await PDFNet.TextWidget.createWithField(doc, await PDFNet.Rect.init(110, 620, 380, 650), empLastName);
        text4.setFont(await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_times_bold));
        await text4.refreshAppearance();
        blankPage.annotPushBack(text4);

        // Signature Widget Creation (unsigned)
        const signature1 = await PDFNet.SignatureWidget.create(doc, await PDFNet.Rect.init(110, 560, 260, 610));
        await signature1.refreshAppearance();
        blankPage.annotPushBack(signature1);

        // CheckBox Widget Creation
        // Create a check box widget that is not checked.
        const check1 = await PDFNet.CheckBoxWidget.create(doc, await PDFNet.Rect.init(140, 490, 170, 520));
        await check1.refreshAppearance();
        blankPage.annotPushBack(check1);
        // Create a check box widget that is checked.
        const check2 = await PDFNet.CheckBoxWidget.create(doc, await PDFNet.Rect.init(190, 490, 250, 540), 'employee.name.check1');
        check2.setBackgroundColor(await PDFNet.ColorPt.init(1, 1, 1), 3);
        check2.setBorderColor(await PDFNet.ColorPt.init(0, 0, 0), 3);
        // Check the widget (by default it is unchecked).
        check2.setChecked(true);
        await check2.refreshAppearance();
        blankPage.annotPushBack(check2);

        // PushButton Widget Creation
        const pushbutton1 = await PDFNet.PushButtonWidget.create(doc, await PDFNet.Rect.init(380, 490, 520, 540));
        pushbutton1.setTextColor(await PDFNet.ColorPt.init(1, 1, 1), 3);
        pushbutton1.setFontSize(36);
        pushbutton1.setBackgroundColor(await PDFNet.ColorPt.init(0, 0, 0), 3);
        // Add a caption for the pushbutton.
        pushbutton1.setStaticCaptionText('PushButton');
        await pushbutton1.refreshAppearance();
        blankPage.annotPushBack(pushbutton1);

        // ComboBox Widget Creation
        const combo1 = await PDFNet.ComboBoxWidget.create(doc, await PDFNet.Rect.init(280, 560, 580, 610));
        // Add options to the combobox widget.
        combo1.addOption('Combo Box No.1');
        combo1.addOption('Combo Box No.2');
        combo1.addOption('Combo Box No.3');
        // Make one of the options in the combo box selected by default.
        combo1.setSelectedOption('Combo Box No.2');
        combo1.setTextColor(await PDFNet.ColorPt.init(1, 0, 0), 3);
        combo1.setFontSize(28);
        await combo1.refreshAppearance();
        blankPage.annotPushBack(combo1);

        // ListBox Widget Creation
        const list1 = await PDFNet.ListBoxWidget.create(doc, await PDFNet.Rect.init(400, 620, 580, 730));
        // Add one option to the listbox widget.
        list1.addOption('List Box No.1');
        // Add multiple options to the listbox widget in a batch.
        const list_options = ['List Box No.2', 'List Box No.3'];
        list1.addOptions(list_options);
        // Select some of the options in list box as default options
        list1.setSelectedOptions(list_options);
        // Enable list box to have multi-select when editing. 
        await (await list1.getField()).setFlag(PDFNet.Field.Flag.e_multiselect, true);
        list1.setFont(await PDFNet.Font.create(doc, PDFNet.Font.StandardType1Font.e_times_italic));
        list1.setTextColor(await PDFNet.ColorPt.init(1, 0, 0), 3);
        list1.setFontSize(28);
        list1.setBackgroundColor(await PDFNet.ColorPt.init(1, 1, 1), 3);
        await list1.refreshAppearance();
        await blankPage.annotPushBack(list1);

        // RadioButton Widget Creation
        // Create a radio button group and add three radio buttons in it. 
        const radio_group = await PDFNet.RadioButtonGroup.create(doc, 'RadioGroup');
        const radiobutton1 = await radio_group.add(await PDFNet.Rect.init(140, 410, 190, 460));
        radiobutton1.setBackgroundColor(await PDFNet.ColorPt.init(1, 1, 0), 3);
        await radiobutton1.refreshAppearance();
        const radiobutton2 = await radio_group.add(await PDFNet.Rect.init(310, 410, 360, 460));
        radiobutton2.setBackgroundColor(await PDFNet.ColorPt.init(0, 1, 0), 3);
        await radiobutton2.refreshAppearance();
        const radiobutton3 = await radio_group.add(await PDFNet.Rect.init(480, 410, 530, 460));
        // Enable the third radio button. By default the first one is selected
        radiobutton3.enableButton();
        radiobutton3.setBackgroundColor(await PDFNet.ColorPt.init(0, 1, 1), 3);
        await radiobutton3.refreshAppearance();
        await radio_group.addGroupButtonsToPage(blankPage);

        // Custom push button annotation creation
        const custom_pushbutton1 = await PDFNet.PushButtonWidget.create(doc, await PDFNet.Rect.init(260, 320, 360, 360));
        // Set the annotation appearance.
        custom_pushbutton1.setAppearance(await CreateCustomButtonAppearance(doc, false), PDFNet.Annot.State.e_normal);
        // Create 'SubmitForm' action. The action will be linked to the button.
        const url = await PDFNet.FileSpec.createURL(doc, 'http://www.pdftron.com');
        const button_action = await PDFNet.Action.createSubmitForm(url);
        // Associate the above action with 'Down' event in annotations action dictionary.
        const annot_action = await (await custom_pushbutton1.getSDFObj()).putDict('AA');
        await annot_action.put('D', await button_action.getSDFObj());
        await blankPage.annotPushBack(custom_pushbutton1);

        // Add the page as the last page in the document.
        doc.pagePushBack(blankPage);
        // If you are not satisfied with the look of default auto-generated appearance 
        // streams you can delete "AP" entry from the Widget annotation and set 
        // "NeedAppearances" flag in AcroForm dictionary:
        //    doc.GetAcroForm().PutBool("NeedAppearances", true);
        // This will force the viewer application to auto-generate new appearance streams 
        // every time the document is opened.
        //
        // Alternatively you can generate custom annotation appearance using ElementWriter 
        // and then set the "AP" entry in the widget dictionary to the new appearance
        // stream.
        //
        // Yet another option is to pre-populate field entries with dummy text. When 
        // you edit the field values using PDFNet the new field appearances will match 
        // the old ones.

        //doc.GetAcroForm().PutBool("NeedAppearances", true);
        // NOTE: RefreshFieldAppearances will replace previously generated appearance streams

        doc.refreshFieldAppearances();

        await doc.save(outputPath + 'forms_test1.pdf', 0);

        console.log('Done.');
      } catch (err) {
        console.log(err.stack);
      }

      //----------------------------------------------------------------------------------
      // Example 2:
      // Fill-in forms / Modify values of existing fields.
      // Traverse all form fields in the document (and print out their names).
      // Search for specific fields in the document.
      //----------------------------------------------------------------------------------

      // This is used later on to clone the fields
      const field_names = {};
      try {
        const doc = await PDFNet.PDFDoc.createFromFilePath(outputPath + 'forms_test1.pdf');
        doc.initSecurityHandler();

        const itr = await doc.getFieldIteratorBegin();
        for (; (await itr.hasNext()); itr.next()) {
          const currentItr = await itr.current();
          const curFieldName = await currentItr.getName();

          // Add one to the count for this field name for later processing
          field_names[curFieldName] = (curFieldName in field_names ? field_names[curFieldName] + 1 : 1);

          console.log('Field name: ' + curFieldName);
          console.log('Field partial name: ' + (await currentItr.getPartialName()));

          const typeStr = 'Field type: ';
          const type = await currentItr.getType();
          const strVal = await currentItr.getValueAsString();

          switch (type) {
            case PDFNet.Field.Type.e_button:
              console.log(typeStr + 'Button');
              break;
            case PDFNet.Field.Type.e_radio:
              console.log(typeStr + 'Radio button: Value = ' + strVal);
              break;
            case PDFNet.Field.Type.e_check:
              currentItr.setValueAsBool(true);
              console.log(typeStr + 'Check box: Value = ' + strVal);
              break;
            case PDFNet.Field.Type.e_text:
              console.log(typeStr + 'Text');
              // Edit all variable text in the document
              currentItr.setValueAsString('This is a new value. The old one was: ' + strVal);
              break;
            case PDFNet.Field.Type.e_choice:
              console.log(typeStr + 'Choice');
              break;
            case PDFNet.Field.Type.e_signature:
              console.log(typeStr + 'Signature');
              break;
          }
          console.log('------------------------------');
        }
        const f = await doc.getField('employee.name.first');
        if (f) {
          console.log('Field search for ' + (await f.getName()) + ' was successful');
        } else {
          console.log('Field search failed');
        }
        // Regenerate field appearances.
        doc.refreshFieldAppearances();

        await doc.save(outputPath + 'forms_test_edit.pdf', 0);
        console.log('Done.');
      } catch (err) {
        console.log(err);
      }
      //----------------------------------------------------------------------------------
      // Sample 3: Form templating
      // Replicate pages and form data within a document. Then rename field names to make
      // them unique.
      //----------------------------------------------------------------------------------
      try {
        const doc = await PDFNet.PDFDoc.createFromFilePath(outputPath + 'forms_test1.pdf');
        doc.initSecurityHandler();

        const srcPage = await doc.getPage(1);
        doc.pagePushBack(srcPage); // Append several copies of the first page
        doc.pagePushBack(srcPage); // Note that forms are successfully copied
        doc.pagePushBack(srcPage);
        doc.pagePushBack(srcPage);

        // Now we rename fields in order to make every field unique.
        // You can use this technique for dynamic template filling where you have a 'master'
        // form page that should be replicated, but with unique field names on every page.
        for (const fieldName in field_names) {
          await RenameAllFields(doc, fieldName, field_names[fieldName]);
        }

        await doc.save(outputPath + 'forms_test1_cloned.pdf', 0);
        console.log('Done.');
      } catch (err) {
        console.log(err);
      }

      //----------------------------------------------------------------------------------
      // Sample:
      // Flatten all form fields in a document.
      // Note that this sample is intended to show that it is possible to flatten
      // individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
      // that will automatically flatten all fields.
      //----------------------------------------------------------------------------------

      try {
        const doc = await PDFNet.PDFDoc.createFromFilePath(outputPath + 'forms_test1.pdf');
        doc.initSecurityHandler();

        // Flatten all pages
        // eslint-disable-next-line no-constant-condition
        if (true) {
          doc.flattenAnnotations();
        } else {
          // Manual flattening
          for (let pitr = await doc.getPageIterator(); (await pitr.hasNext()); (await pitr.next())) {
            const page = await pitr.current();
            const annots = await page.getAnnots();

            if (annots) { // Look for all widget annotations (in reverse order)
              for (let i = parseInt(await annots.size(), 10) - 1; i >= 0; --i) {
                const annotObj = await annots.getAt(i);
                const annotObjSubtype = await annotObj.get('Subtype');
                // eslint-disable-next-line no-unused-vars
                const annotObjVal = await annotObjSubtype.value();
                const annotObjName = await annotObjVal.getName();

                if (annotObjName === 'Widget') {
                  const field = await PDFNet.Field.create(annotObj);
                  field.flatten(page);
                }
              }
            }
          }
        }

        await doc.save(outputPath + 'forms_test1_flattened.pdf', 0);
        console.log('Done.');
      } catch (err) {
        console.log(err);
      }
    };
    PDFNet.runWithCleanup(main, PDFTronLicense.Key).catch(function (error) {
      console.log('Error: ' + JSON.stringify(error));
    }).then(function () { return PDFNet.shutdown(); });
  };
  exports.runInteractiveFormsTest();
})(exports);
// eslint-disable-next-line spaced-comment
//# sourceURL=InteractiveFormsTest.js
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
<?php
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
// Consult LICENSE.txt regarding license information.
//---------------------------------------------------------------------------------------
if(file_exists("../../../PDFNetC/Lib/PDFNetPHP.php"))
include("../../../PDFNetC/Lib/PDFNetPHP.php");
include("../../LicenseKey/PHP/LicenseKey.php");

// Relative path to the folder containing the test files.
$input_path = getcwd()."/../../TestFiles/";
$output_path = $input_path."Output/";

//---------------------------------------------------------------------------------------
// This sample illustrates basic PDFNet capabilities related to interactive 
// forms (also known as AcroForms). 
//---------------------------------------------------------------------------------------

function RenameAllFields($doc, $name, $field_nums = 1)
{
	$itr = $doc->GetFieldIterator($name);
	for ($counter = 1; $itr->HasNext(); $itr = $doc->GetFieldIterator($name), ++$counter) {
		$f = $itr->Current();
		$tmp = (int)ceil($counter*1.0/$field_nums);
		$f->Rename($name."-".$tmp);

	}
}

// Note: The visual appearance of check-marks and radio-buttons in PDF documents is 
// not limited to CheckStyle-s. It is possible to create a visual appearance using 
// arbitrary glyph, text, raster image, or path object. Although most PDF producers 
// limit the options to the above 'standard' styles, using PDFNet you can generate 
// arbitrary appearances.

function CreateCheckmarkAppearance($doc) 
{
	// Create a checkmark appearance stream ------------------------------------
	$build = new ElementBuilder();
	$writer = new ElementWriter();
	$writer->Begin($doc->GetSDFDoc());
	$writer->WriteElement($build->CreateTextBegin());

	$symbol = "4";
	# other options are circle ("l"), diamond ("H"), cross ("\x35")
	# See section D.4 "ZapfDingbats Set and Encoding" in PDF Reference Manual for 
	# the complete graphical map for ZapfDingbats font.

	$checkmark = $build->CreateTextRun($symbol, Font::Create($doc->GetSDFDoc(), Font::e_zapf_dingbats), 1.0);
	$writer->WriteElement($checkmark);
	$writer->WriteElement($build->CreateTextEnd());

	$stm = $writer->End();
	$stm->PutRect("BBox", -0.2, -0.2, 1.0, 1.0); // Clip
	$stm->PutName("Subtype", "Form");
	return $stm;
}

function CreateCustomButtonAppearance($doc, $button_down) 
{
	// Create a button appearance stream ------------------------------------
	$build = new ElementBuilder();
	$writer = new ElementWriter();
	$writer->Begin($doc->GetSDFDoc()); 

	// Draw background
	$element = $build->CreateRect(0, 0, 101, 37);
	$element->SetPathFill(true);
	$element->SetPathStroke(false);
	$element->GetGState()->SetFillColorSpace(ColorSpace::CreateDeviceGray());
	$element->GetGState()->SetFillColor(new ColorPt(0.75, 0.0, 0.0));
	$writer->WriteElement($element); 

	// Draw 'Submit' text
	$writer->WriteElement($build->CreateTextBegin()); 
	
	$text = "Submit";
	$element = $build->CreateTextRun($text, Font::Create($doc->GetSDFDoc(), Font::e_helvetica_bold), 12.0);
	$element->GetGState()->SetFillColor(new ColorPt(0.0, 0.0, 0.0));

	if ($button_down) 
		$element->SetTextMatrix(1.0, 0.0, 0.0, 1.0, 33.0, 10.0);
	else 
		$element->SetTextMatrix(1.0, 0.0, 0.0, 1.0, 30.0, 13.0);
	$writer->WriteElement($element);
	
	$writer->WriteElement($build->CreateTextEnd());

	$stm = $writer->End(); 

	// Set the bounding box
	$stm->PutRect("BBox", 0, 0, 101, 37);
	$stm->PutName("Subtype","Form");
	return $stm;
}

	PDFNet::Initialize($LicenseKey);
	PDFNet::GetSystemFontList();    // Wait for fonts to be loaded if they haven't already. This is done because PHP can run into errors when shutting down if font loading is still in progress.

	//----------------------------------------------------------------------------------
	// Example 1: Programatically create new Form Fields and Widget Annotations.
	//----------------------------------------------------------------------------------

	$doc = new PDFDoc();

	// Create a blank new page and add some form fields.
	$blank_page = $doc->PageCreate();

	// Text Widget Creation 
	// Create an empty text widget with black text.
	$text1 = TextWidget::Create($doc, new Rect(110.0, 700.0, 380.0, 730.0));
	$text1->SetText("Basic Text Field");
	$text1->RefreshAppearance();
	$blank_page->AnnotPushBack($text1);
	// Create a vertical text widget with blue text and a yellow background.
	$text2 = TextWidget::Create($doc, new Rect(50.0, 400.0, 90.0, 730.0));
	$text2->SetRotation(90);
	// Set the text content.
	$text2->SetText("    ****Lucky Stars!****");
	// Set the font type, text color, font size, border color and background color.
	$text2->SetFont(Font::Create($doc->GetSDFDoc(), Font::e_helvetica_oblique));
	$text2->SetFontSize(28);
	$text2->SetTextColor(new ColorPt(0.0, 0.0, 1.0), 3);
	$text2->SetBorderColor(new ColorPt(0.0, 0.0, 0.0), 3);
	$text2->SetBackgroundColor(new ColorPt(1.0, 1.0, 0.0), 3);
	$text2->RefreshAppearance();
	// Add the annotation to the page.
	$blank_page->AnnotPushBack($text2);
	// Create two new text widget with Field names employee.name.first and employee.name.last
	// This logic shows how these widgets can be created using either a field name string or
	// a Field object
	$text3 = TextWidget::Create($doc, new Rect(110.0, 660.0, 380.0, 690.0), "employee.name.first");
	$text3->SetText("Levi");
	$text3->SetFont(Font::Create($doc->GetSDFDoc(), Font::e_times_bold));
	$text3->RefreshAppearance();
	$blank_page->AnnotPushBack($text3);
	$emp_last_name = $doc->FieldCreate("employee.name.last", Field::e_text, "Ackerman"); 
	$text4 = TextWidget::Create($doc, new Rect(110.0, 620.0, 380.0, 650.0), $emp_last_name);
	$text4->SetFont(Font::Create($doc->GetSDFDoc(), Font::e_times_bold));
	$text4->RefreshAppearance();
	$blank_page->AnnotPushBack($text4);

	// Signature Widget Creation (unsigned)
	$signature1 = SignatureWidget::Create($doc, new Rect(110.0, 560.0, 260.0, 610.0));
	$signature1->RefreshAppearance();
	$blank_page->AnnotPushBack($signature1);

	// CheckBox Widget Creation
	// Create a check box widget that is not checked.
	$check1 = CheckBoxWidget::Create($doc, new Rect(140.0, 490.0, 170.0, 520.0));
	$check1->RefreshAppearance();
	$blank_page->AnnotPushBack($check1);
	// Create a check box widget that is checked.
	$check2 = CheckBoxWidget::Create($doc, new Rect(190.0, 490.0, 250.0, 540.0), "employee.name.check1");
	$check2->SetBackgroundColor(new ColorPt(1.0, 1.0, 1.0), 3);
	$check2->SetBorderColor(new ColorPt(0.0, 0.0, 0.0), 3);
	// Check the widget (by default it is unchecked).
	$check2->SetChecked(true);
	$check2->RefreshAppearance();
	$blank_page->AnnotPushBack($check2);

	// PushButton Widget Creation
	$pushbutton1 = PushButtonWidget::Create($doc, new Rect(380.0, 490.0, 520.0, 540.0));
	$pushbutton1->SetTextColor(new ColorPt(1.0, 1.0, 1.0), 3);
	$pushbutton1->SetFontSize(36);
	$pushbutton1->SetBackgroundColor(new ColorPt(0.0, 0.0, 0.0), 3);
	// Add a caption for the pushbutton.
	$pushbutton1->SetStaticCaptionText("PushButton");
	$pushbutton1->RefreshAppearance();
	$blank_page->AnnotPushBack($pushbutton1);

	// ComboBox Widget Creation
	$combo1 = ComboBoxWidget::Create($doc, new Rect(280.0, 560.0, 580.0, 610.0));
	// Add options to the combobox widget.
	$combo1->AddOption("Combo Box No.1");
	$combo1->AddOption("Combo Box No.2");
	$combo1->AddOption("Combo Box No.3");
	// Make one of the options in the combo box selected by default.
	$combo1->SetSelectedOption("Combo Box No.2");
	$combo1->SetTextColor(new ColorPt(1.0, 0.0, 0.0), 3);
	$combo1->SetFontSize(28);
	$combo1->RefreshAppearance();
	$blank_page->AnnotPushBack($combo1);

	// ListBox Widget Creation
	$list1 = ListBoxWidget::Create($doc, new Rect(400.0, 620.0, 580.0, 730.0));
	// Add one option to the listbox widget.
	$list1->AddOption("List Box No.1");
	// Add multiple options to the listbox widget in a batch.
	$list_options = array("List Box No.2", "List Box No.3");		
	$list1->AddOptions($list_options);
	// Select some of the options in list box as default options
	$list1->SetSelectedOptions($list_options);
	// Enable list box to have multi-select when editing. 
	$list1->GetField()->SetFlag(Field::e_multiselect, true);
	$list1->SetFont(Font::Create($doc->GetSDFDoc(), Font::e_times_italic));
	$list1->SetTextColor(new ColorPt(1.0, 0.0, 0.0), 3);
	$list1->SetFontSize(28);
	$list1->SetBackgroundColor(new ColorPt(1.0, 1.0, 1.0), 3);
	$list1->RefreshAppearance();
	$blank_page->AnnotPushBack($list1);

	// RadioButton Widget Creation
	// Create a radio button group and add three radio buttons in it. 
	$radio_group = RadioButtonGroup::Create($doc, "RadioGroup");
	$radiobutton1 = $radio_group->Add(new Rect(140.0, 410.0, 190.0, 460.0));
	$radiobutton1->SetBackgroundColor(new ColorPt(1.0, 1.0, 0.0), 3);
	$radiobutton1->RefreshAppearance();
	$radiobutton2 = $radio_group->Add(new Rect(310.0, 410.0, 360.0, 460.0));
	$radiobutton2->SetBackgroundColor(new ColorPt(0.0, 1.0, 0.0), 3);
	$radiobutton2->RefreshAppearance();
	$radiobutton3 = $radio_group->Add(new Rect(480.0, 410.0, 530.0, 460.0));
	// Enable the third radio button. By default the first one is selected
	$radiobutton3->EnableButton();
	$radiobutton3->SetBackgroundColor(new ColorPt(0.0, 1.0, 1.0), 3);
	$radiobutton3->RefreshAppearance();
	$radio_group->AddGroupButtonsToPage($blank_page);

	// Custom push button annotation creation
	$custom_pushbutton1 = PushButtonWidget::Create($doc, new Rect(260.0, 320.0, 360.0, 360.0));
	// Set the annotation appearance.
	$custom_pushbutton1->SetAppearance(CreateCustomButtonAppearance($doc, false), Annot::e_normal);
	// Create 'SubmitForm' action. The action will be linked to the button.
	$url = FileSpec::CreateURL($doc->GetSDFDoc(), "http://www.pdftron.com");
	$button_action = Action::CreateSubmitForm($url);
	// Associate the above action with 'Down' event in annotations action dictionary.
	$annot_action = $custom_pushbutton1->GetSDFObj()->PutDict("AA");
	$annot_action->Put("D", $button_action->GetSDFObj());
	$blank_page->AnnotPushBack($custom_pushbutton1);

	$doc->PagePushBack($blank_page);	// Add the page as the last page in the document.

	// If you are not satisfied with the look of default auto-generated appearance 
	// streams you can delete "AP" entry from the Widget annotation and set 
	// "NeedAppearances" flag in AcroForm dictionary:
	//    $doc->GetAcroForm()->PutBool("NeedAppearances", true);
	// This will force the viewer application to auto-generate new appearance streams 
	// every time the document is opened.
	//
	// Alternatively you can generate custom annotation appearance using ElementWriter 
	// and then set the "AP" entry in the widget dictionary to the new appearance
	// stream.
	//
	// Yet another option is to pre-populate field entries with dummy text. When 
	// you edit the field values using PDFNet the new field appearances will match 
	// the old ones.

	$doc->RefreshFieldAppearances();

	$doc->Save($output_path."forms_test1.pdf", 0);
	echo "Done.\n";

	//----------------------------------------------------------------------------------
	// Example 2: 
	// Fill-in forms / Modify values of existing fields.
	// Traverse all form fields in the document (and print out their names). 
	// Search for specific fields in the document.
	//----------------------------------------------------------------------------------

	$doc = new PDFDoc($output_path."forms_test1.pdf");
	$doc->InitSecurityHandler();

	$itr = $doc->GetFieldIterator();
        $field_names = array();
	for(; $itr->HasNext(); $itr->Next()) 
	{
		$cur_field_name = $itr->Current()->GetName();
		// Add one to the count for this field name for later processing
		if(isset($field_names [$cur_field_name])){
			$field_names [$cur_field_name] += 1;
		}
		else{
		    $field_names [$cur_field_name] = 1;
		}
		echo nl2br("Field name: ".$itr->Current()->GetName()."\n");
		echo nl2br("Field partial name: ".$itr->Current()->GetPartialName()."\n");

		echo "Field type: ";
		$type = $itr->Current()->GetType();
		$str_val = $itr->Current()->GetValueAsString();

		switch($type)
		{
		case Field::e_button: 
			echo nl2br("Button\n"); 
			break;
		case Field::e_radio: 
			echo nl2br("Radio button: Value = ".$str_val."\n"); 
			break;
		case Field::e_check: 
			$itr->Current()->SetValue(true);
			echo nl2br("Check box: Value = ".$str_val."\n"); 
			break;
		case Field::e_text: 
			{
				echo nl2br("Text\n");
				// Edit all variable text in the document
				$itr->Current()->SetValue("This is a new value. The old one was: ".$str_val);
			}
			break;
		case Field::e_choice: echo nl2br("Choice\n"); break;
		case Field::e_signature: echo nl2br("Signature\n"); break;
		}

		echo "------------------------------\n";
	}
	
	// Search for a specific field
	$f = $doc->GetField("employee.name.first");
	if ($f) 
	{
		echo nl2br("Field search for ".$f->GetName()." was successful\n");
	}
	else 
	{
		echo nl2br("Field search failed\n");
	}

	// Regenerate field appearances.
	$doc->RefreshFieldAppearances();
	$doc->Save(($output_path."forms_test_edit.pdf"), 0);
	echo nl2br("Done.\n");

	//----------------------------------------------------------------------------------
	// Sample: Form templating
	// Replicate pages and form data within a document. Then rename field names to make 
	// them unique.
	//----------------------------------------------------------------------------------
	
	// Sample: Copying the page with forms within the same document
	$doc = new PDFDoc($output_path."forms_test1.pdf");
	$doc->InitSecurityHandler();

	$src_page = $doc->GetPage(1);
	$doc->PagePushBack($src_page);  // Append several copies of the first page
	$doc->PagePushBack($src_page);	 // Note that forms are successfully copied
	$doc->PagePushBack($src_page);
	$doc->PagePushBack($src_page);

	// Now we rename fields in order to make every field unique.
	// You can use this technique for dynamic template filling where you have a 'master'
	// form page that should be replicated, but with unique field names on every page. 

        foreach($field_names as $key => $val){
		RenameAllFields($doc, $key, $val);
	}

	$doc->Save($output_path."forms_test1_cloned.pdf", 0);
	echo nl2br("Done.\n");

	//----------------------------------------------------------------------------------
	// Sample: 
	// Flatten all form fields in a document.
	// Note that this sample is intended to show that it is possible to flatten
	// individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
	// that will automatically flatten all fields.
	//----------------------------------------------------------------------------------
	$doc = new PDFDoc($output_path."forms_test1.pdf");
	$doc->InitSecurityHandler();

	// Traverse all pages
	if (false) {
		$doc->FlattenAnnotations();
	}
	else // Manual flattening
	{			
			
		for ($pitr = $doc->GetPageIterator(); $pitr->HasNext(); $pitr->Next())  
		{
			$page = $pitr->Current();
			for ($i = (int)($page->GetNumAnnots())-1; $i>=0; --$i)
			{
				$annot = $page->GetAnnot($i);
				if ($annot->GetType() == Annot::e_Widget)
				{
					$annot->Flatten($page); 
				}
			}
		}
	}


	$doc->Save(($output_path."forms_test1_flattened.pdf"), 0);
	PDFNet::Terminate();
	echo nl2br("Done.\n");	
?>
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

import site
site.addsitedir("../../../PDFNetC/Lib")
import sys
from PDFNetPython import *
import math

sys.path.append("../../LicenseKey/PYTHON")
from LicenseKey import *

# Relative path to the folder containing the test files.
input_path = "../../TestFiles/"
output_path = "../../TestFiles/Output/"

#---------------------------------------------------------------------------------------
# This sample illustrates basic PDFNet capabilities related to interactive 
# forms (also known as AcroForms). 
#---------------------------------------------------------------------------------------

# field_nums has to be greater than 0.
def RenameAllFields(doc, name, field_nums):
    itr = doc.GetFieldIterator(name)
    counter = 1
    while itr.HasNext():
        f = itr.Current()
        radio_counter = (int)(math.ceil(counter/float(field_nums)))
        f.Rename(name + "-" + str(radio_counter))
        itr = doc.GetFieldIterator(name)
        counter = counter + 1

def CreateCustomButtonAppearance(doc, button_down):
    # Create a button appearance stream ------------------------------------
    build = ElementBuilder()
    writer = ElementWriter()
    writer.Begin(doc.GetSDFDoc())
    
    # Draw background
    element = build.CreateRect(0, 0, 101, 37)
    element.SetPathFill(True)
    element.SetPathStroke(False)
    element.GetGState().SetFillColorSpace(ColorSpace.CreateDeviceGray())
    element.GetGState().SetFillColor(ColorPt(0.75, 0, 0))
    writer.WriteElement(element)
    
    # Draw 'Submit' text
    writer.WriteElement(build.CreateTextBegin())
    text = "Submit"
    element = build.CreateTextRun(text, Font.Create(doc.GetSDFDoc(), Font.e_helvetica_bold), 12)
    element.GetGState().SetFillColor(ColorPt(0, 0, 0))
    
    if button_down:
        element.SetTextMatrix(1, 0, 0, 1, 33, 10)
    else:
        element.SetTextMatrix(1, 0, 0, 1, 30, 13)
    writer.WriteElement(element)
    
    writer.WritePlacedElement(build.CreateTextEnd())
    
    stm = writer.End()
    
    # Set the bounding box
    stm.PutRect("BBox", 0, 0, 101, 37)
    stm.PutName("Subtype","Form")
    return stm
    



def main():
    PDFNet.Initialize(LicenseKey)
    
    # The vector used to store the name and count of all fields.
    # This is used later on to clone the fields
    field_names = dict()

    #----------------------------------------------------------------------------------
    # Example 1: Programatically create new Form Fields and Widget Annotations.
    #----------------------------------------------------------------------------------
    
    doc = PDFDoc()

    # Create a blank new page and Add some form fields.
    blank_page = doc.PageCreate()

    # Text Widget Creation 
    # Create an empty text widget with black text.
    text1 = TextWidget.Create(doc, Rect(110, 700, 380, 730))
    text1.SetText("Basic Text Field")
    text1.RefreshAppearance()
    blank_page.AnnotPushBack(text1)
    # Create a vertical text widget with blue text and a yellow background.
    text2 = TextWidget.Create(doc, Rect(50, 400, 90, 730))
    text2.SetRotation(90)
    # Set the text content.
    text2.SetText("    ****Lucky Stars!****");
    # Set the font type, text color, font size, border color and background color.
    text2.SetFont(Font.Create(doc.GetSDFDoc(), Font.e_helvetica_oblique))
    text2.SetFontSize(28)
    text2.SetTextColor(ColorPt(0, 0, 1), 3)
    text2.SetBorderColor(ColorPt(0, 0, 0), 3)
    text2.SetBackgroundColor(ColorPt(1, 1, 0), 3)
    text2.RefreshAppearance()
    # Add the annotation to the page.
    blank_page.AnnotPushBack(text2)
    # Create two new text widget with Field names employee.name.first and employee.name.last
    # This logic shows how these widgets can be created using either a field name string or
    # a Field object
    text3 = TextWidget.Create(doc, Rect(110, 660, 380, 690), "employee.name.first")
    text3.SetText("Levi")
    text3.SetFont(Font.Create(doc.GetSDFDoc(), Font.e_times_bold))
    text3.RefreshAppearance()
    blank_page.AnnotPushBack(text3)
    emp_last_name = doc.FieldCreate("employee.name.last", Field.e_text, "Ackerman")
    text4 = TextWidget.Create(doc, Rect(110, 620, 380, 650), emp_last_name)
    text4.SetFont(Font.Create(doc.GetSDFDoc(), Font.e_times_bold))
    text4.RefreshAppearance()
    blank_page.AnnotPushBack(text4)

    # Signature Widget Creation (unsigned)
    signature1 = SignatureWidget.Create(doc, Rect(110, 560, 260, 610))
    signature1.RefreshAppearance()
    blank_page.AnnotPushBack(signature1)

    # CheckBox Widget Creation
    # Create a check box widget that is not checked.
    check1 = CheckBoxWidget.Create(doc, Rect(140, 490, 170, 520))
    check1.RefreshAppearance()
    blank_page.AnnotPushBack(check1)
    # Create a check box widget that is checked.
    check2 = CheckBoxWidget.Create(doc, Rect(190, 490, 250, 540), "employee.name.check1")
    check2.SetBackgroundColor(ColorPt(1, 1, 1), 3)
    check2.SetBorderColor(ColorPt(0, 0, 0), 3)
    # Check the widget (by default it is unchecked).
    check2.SetChecked(True)
    check2.RefreshAppearance()
    blank_page.AnnotPushBack(check2)

    # PushButton Widget Creation
    pushbutton1 = PushButtonWidget.Create(doc, Rect(380, 490, 520, 540))
    pushbutton1.SetTextColor(ColorPt(1, 1, 1), 3)
    pushbutton1.SetFontSize(36)
    pushbutton1.SetBackgroundColor(ColorPt(0, 0, 0), 3)
    # Add a caption for the pushbutton.
    pushbutton1.SetStaticCaptionText("PushButton")
    pushbutton1.RefreshAppearance()
    blank_page.AnnotPushBack(pushbutton1)

    # ComboBox Widget Creation
    combo1 = ComboBoxWidget.Create(doc, Rect(280, 560, 580, 610));
    # Add options to the combobox widget.
    combo1.AddOption("Combo Box No.1")
    combo1.AddOption("Combo Box No.2")
    combo1.AddOption("Combo Box No.3")
    # Make one of the options in the combo box selected by default.
    combo1.SetSelectedOption("Combo Box No.2")
    combo1.SetTextColor(ColorPt(1, 0, 0), 3)
    combo1.SetFontSize(28)
    combo1.RefreshAppearance()
    blank_page.AnnotPushBack(combo1)

    # ListBox Widget Creation
    list1 = ListBoxWidget.Create(doc, Rect(400, 620, 580, 730))
    # Add one option to the listbox widget.
    list1.AddOption("List Box No.1")
    # Add multiple options to the listbox widget in a batch.
    list_options = ["List Box No.2", "List Box No.3"]
    list1.AddOptions(list_options)
    # Select some of the options in list box as default options
    list1.SetSelectedOptions(list_options)
    # Enable list box to have multi-select when editing. 
    list1.GetField().SetFlag(Field.e_multiselect, True)
    list1.SetFont(Font.Create(doc.GetSDFDoc(),Font.e_times_italic))
    list1.SetTextColor(ColorPt(1, 0, 0), 3)
    list1.SetFontSize(28)
    list1.SetBackgroundColor(ColorPt(1, 1, 1), 3)
    list1.RefreshAppearance()
    blank_page.AnnotPushBack(list1)

    # RadioButton Widget Creation
    # Create a radio button group and Add three radio buttons in it. 
    radio_group = RadioButtonGroup.Create(doc, "RadioGroup")
    radiobutton1 = radio_group.Add(Rect(140, 410, 190, 460))
    radiobutton1.SetBackgroundColor(ColorPt(1, 1, 0), 3)
    radiobutton1.RefreshAppearance()
    radiobutton2 = radio_group.Add(Rect(310, 410, 360, 460))
    radiobutton2.SetBackgroundColor(ColorPt(0, 1, 0), 3)
    radiobutton2.RefreshAppearance()
    radiobutton3 = radio_group.Add(Rect(480, 410, 530, 460))
    # Enable the third radio button. By default the first one is selected
    radiobutton3.EnableButton()
    radiobutton3.SetBackgroundColor(ColorPt(0, 1, 1), 3)
    radiobutton3.RefreshAppearance()
    radio_group.AddGroupButtonsToPage(blank_page)

    # Custom push button annotation creation
    custom_pushbutton1 = PushButtonWidget.Create(doc, Rect(260, 320, 360, 360))
    # Set the annotation appearance.
    custom_pushbutton1.SetAppearance(CreateCustomButtonAppearance(doc, False), Annot.e_normal)
    # Create 'SubmitForm' action. The action will be linked to the button.
    url = FileSpec.CreateURL(doc.GetSDFDoc(), "http://www.pdftron.com")
    button_action = Action.CreateSubmitForm(url)
    # Associate the above action with 'Down' event in annotations action dictionary.
    annot_action = custom_pushbutton1.GetSDFObj().PutDict("AA")
    annot_action.Put("D", button_action.GetSDFObj())
    blank_page.AnnotPushBack(custom_pushbutton1)

	# Add the page as the last page in the document.
    doc.PagePushBack(blank_page)                     
                                     
    # If you are not satisfied with the look of default auto-generated appearance 
    # streams you can delete "AP" entry from the Widget annotation and set 
    # "NeedAppearances" flag in AcroForm dictionary:
    #    doc.GetAcroForm().PutBool("NeedAppearances", true);
    # This will force the viewer application to auto-generate new appearance streams 
    # every time the document is opened.
    #
    # Alternatively you can generate custom annotation appearance using ElementWriter 
    # and then set the "AP" entry in the widget dictionary to the new appearance
    # stream.
    #
    # Yet another option is to pre-populate field entries with dummy text. When 
    # you edit the field values using PDFNet the new field appearances will match 
    # the old ones.

    #doc.GetAcroForm().PutBool("NeedAppearances", True)
    doc.RefreshFieldAppearances()
    
    doc.Save(output_path + "forms_test1.pdf", 0)
    doc.Close()
    print("Done.")
    
    #----------------------------------------------------------------------------------
    # Example 2: 
    # Fill-in forms / Modify values of existing fields.
    # Traverse all form fields in the document (and sys.stdout.write(out their names). 
    # Search for specific fields in the document.
    #----------------------------------------------------------------------------------
    
    doc = PDFDoc(output_path + "forms_test1.pdf")
    doc.InitSecurityHandler()
    
    itr = doc.GetFieldIterator()
    while itr.HasNext():

        cur_field_name = itr.Current().GetName()
        # Add one to the count for this field name for later processing
        if sys.version_info.major >= 3:
            field_names[cur_field_name] = field_names[cur_field_name] + 1 if cur_field_name in field_names else 1
        else:
            field_names[cur_field_name] = field_names[cur_field_name] + 1 if field_names.has_key(cur_field_name) else 1

        print("Field name: " + itr.Current().GetName())
        print("Field partial name: " + itr.Current().GetPartialName())
        
        sys.stdout.write("Field type: ")
        type = itr.Current().GetType()
        str_val = itr.Current().GetValueAsString()
        if type == Field.e_button:
            sys.stdout.write("Button" + '\n')
        elif type == Field.e_radio:
            sys.stdout.write("Radio button: Value = " + str_val + '\n')
        elif type == Field.e_check:
            itr.Current().SetValue(True)
            sys.stdout.write("Check box: Value = " + str_val + '\n')
        elif type == Field.e_text:
            sys.stdout.write("Text" + '\n')
            # Edit all variable text in the document
            if itr.Current().GetValue():
                old_value = itr.Current().GetValueAsString();
                itr.Current().SetValue("This is a new value. The old one was: " + old_value)
        elif type == Field.e_choice:
            sys.stdout.write("Choice" + '\n')
        elif type == Field.e_signature:
            sys.stdout.write("Signature" + '\n')
        print("------------------------------")
        itr.Next()
    # Search for a specific field
    f = doc.GetField("employee.name.first")
    if f != None:
        print("Field search for " + f.GetName() + " was successful")
    else:
        print("Field search failed")
        
    # Regenerate field appearances.
    doc.RefreshFieldAppearances()
    doc.Save(output_path + "forms_test_edit.pdf", 0)
    doc.Close()
    print("Done.")
    
    #----------------------------------------------------------------------------------
    # Sample: Form templating
    # Replicate pages and form data within a document. Then rename field names to make 
    # them unique.
    #----------------------------------------------------------------------------------
    
    # Sample: Copying the page with forms within the same document
    doc = PDFDoc(output_path + "forms_test1.pdf")
    doc.InitSecurityHandler()
    
    src_page = doc.GetPage(1)
    doc.PagePushBack(src_page) # Append several copies of the first page
    doc.PagePushBack(src_page) # Note that forms are successfully copied
    doc.PagePushBack(src_page)
    doc.PagePushBack(src_page)
    
    # Now we rename fields in order to make every field unique.
    # You can use this technique for dynamic template filling where you have a 'master'
    # form page that should be replicated, but with unique field names on every page. 
    for cur_field in field_names.keys():
        RenameAllFields(doc, cur_field, field_names.get(cur_field))
    
    doc.Save(output_path + "forms_test1_cloned.pdf", 0)
    doc.Close()
    print("Done.")
    
    #----------------------------------------------------------------------------------
    # Sample: 
    # Flatten all form fields in a document.
    # Note that this sample is intended to show that it is possible to flatten
    # individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
    # that will automatically flatten all fields.
    #----------------------------------------------------------------------------------
    doc = PDFDoc(output_path + "forms_test1.pdf")
    doc.InitSecurityHandler()
     
    # Traverse all pages
    if False:
        doc.FlattenAnnotations()
    else: # Manual flattening
        pitr = doc.GetPageIterator()
        while pitr.HasNext():
            page = pitr.Current()
            i = page.GetNumAnnots() - 1
            while i >= 0:
                annot = page.GetAnnot(i)
                if annot.GetType() == Annot.e_Widget:
                    annot.Flatten(page)
                i = i - 1
            pitr.Next()

    doc.Save(output_path + "forms_test1_flattened.pdf", 0)
    doc.Close()
    PDFNet.Terminate()
    print("Done.")
        
if __name__ == '__main__':
    main()
```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

require '../../../PDFNetC/Lib/PDFNetRuby'
include PDFNetRuby
require '../../LicenseKey/RUBY/LicenseKey'

$stdout.sync = true

# Relative path to the folder containing the test files.
input_path = "../../TestFiles/"
output_path = "../../TestFiles/Output/"

#---------------------------------------------------------------------------------------
# This sample illustrates basic PDFNet capabilities related to interactive 
# forms (also known as AcroForms). 
#---------------------------------------------------------------------------------------

# field_nums has to be greater than 0.
def RenameAllFields(doc, name, field_nums = 1)
	itr = doc.GetFieldIterator(name)
	counter = 1
	while itr.HasNext do
		f = itr.Current
		radio_counter = ((counter*1.0/field_nums).ceil).to_i
		f.Rename(name + "-" + radio_counter.to_s)

		itr = doc.GetFieldIterator(name)
		counter = counter + 1
	end
end


def CreateCustomButtonAppearance(doc, button_down)
	# Create a button appearance stream ------------------------------------
	build = ElementBuilder.new
	writer = ElementWriter.new
	writer.Begin(doc.GetSDFDoc)
	
	# Draw background
	element = build.CreateRect(0, 0, 101, 37)
	element.SetPathFill(true)
	element.SetPathStroke(false)
	element.GetGState.SetFillColorSpace(ColorSpace.CreateDeviceGray)
	element.GetGState.SetFillColor(ColorPt.new(0.75, 0, 0))
	writer.WriteElement(element)
	
	# Draw 'Submit' text
	writer.WriteElement(build.CreateTextBegin)
	text = "Submit"
	element = build.CreateTextRun(text, Font.Create(doc.GetSDFDoc, Font::E_helvetica_bold), 12)
	element.GetGState.SetFillColor(ColorPt.new(0, 0, 0))
	
	if button_down
		element.SetTextMatrix(1, 0, 0, 1, 33, 10)
	else
		element.SetTextMatrix(1, 0, 0, 1, 30, 13)
	end
	writer.WriteElement(element)
	
	writer.WritePlacedElement(build.CreateTextEnd)
	
	stm = writer.End
	
	# Set the bounding box
	stm.PutRect("BBox", 0, 0, 101, 37)
	stm.PutName("Subtype","Form")
	return stm
end


	PDFNet.Initialize(PDFTronLicense.Key)	
	
	#----------------------------------------------------------------------------------
	# Example 1: Programatically create new Form Fields and Widget Annotations.
	#----------------------------------------------------------------------------------
	
	doc = PDFDoc.new

	# Create a blank new page and Add some form fields.
	blank_page = doc.PageCreate

	# Text Widget Creation 
	# Create an empty text widget with black text.
	text1 = TextWidget.Create(doc, Rect.new(110, 700, 380, 730))
	text1.SetText("Basic Text Field")
	text1.RefreshAppearance
	blank_page.AnnotPushBack(text1)
	# Create a vertical text widget with blue text and a yellow background.
	text2 = TextWidget.Create(doc, Rect.new(50, 400, 90, 730))
	text2.SetRotation(90)
	# Set the text content.
	text2.SetText("    ****Lucky Stars!****");
	# Set the font type, text color, font size, border color and background color.
	text2.SetFont(Font.Create(doc.GetSDFDoc, Font::E_helvetica_oblique))
	text2.SetFontSize(28)
	text2.SetTextColor(ColorPt.new(0, 0, 1), 3)
	text2.SetBorderColor(ColorPt.new(0, 0, 0), 3)
	text2.SetBackgroundColor(ColorPt.new(1, 1, 0), 3)
	text2.RefreshAppearance
	# Add the annotation to the page.
	blank_page.AnnotPushBack(text2)
	# Create two new text widget with Field names employee.name.first and employee.name.last
	# This logic shows how these widgets can be created using either a field name string or
	# a Field object
	text3 = TextWidget.Create(doc, Rect.new(110, 660, 380, 690), "employee.name.first")
	text3.SetText("Levi")
	text3.SetFont(Font.Create(doc.GetSDFDoc, Font::E_times_bold))
	text3.RefreshAppearance
	blank_page.AnnotPushBack(text3)
	emp_last_name = doc.FieldCreate("employee.name.last", Field::E_text, "Ackerman")
	text4 = TextWidget.Create(doc, Rect.new(110, 620, 380, 650), emp_last_name)
	text4.SetFont(Font.Create(doc.GetSDFDoc, Font::E_times_bold))
	text4.RefreshAppearance
	blank_page.AnnotPushBack(text4)

	# Signature Widget Creation (unsigned)
	signature1 = SignatureWidget.Create(doc, Rect.new(110, 560, 260, 610))
	signature1.RefreshAppearance
	blank_page.AnnotPushBack(signature1)

	# CheckBox Widget Creation
	# Create a check box widget that is not checked.
	check1 = CheckBoxWidget.Create(doc, Rect.new(140, 490, 170, 520))
	check1.RefreshAppearance
	blank_page.AnnotPushBack(check1)
	# Create a check box widget that is checked.
	check2 = CheckBoxWidget.Create(doc, Rect.new(190, 490, 250, 540), "employee.name.check1")
	check2.SetBackgroundColor(ColorPt.new(1, 1, 1), 3)
	check2.SetBorderColor(ColorPt.new(0, 0, 0), 3)
	# Check the widget (by default it is unchecked).
	check2.SetChecked(true)
	check2.RefreshAppearance
	blank_page.AnnotPushBack(check2)

	# PushButton Widget Creation
	pushbutton1 = PushButtonWidget.Create(doc, Rect.new(380, 490, 520, 540))
	pushbutton1.SetTextColor(ColorPt.new(1, 1, 1), 3)
	pushbutton1.SetFontSize(36)
	pushbutton1.SetBackgroundColor(ColorPt.new(0, 0, 0), 3)
	# Add a caption for the pushbutton.
	pushbutton1.SetStaticCaptionText("PushButton")
	pushbutton1.RefreshAppearance
	blank_page.AnnotPushBack(pushbutton1)

	# ComboBox Widget Creation
	combo1 = ComboBoxWidget.Create(doc, Rect.new(280, 560, 580, 610));
	# Add options to the combobox widget.
	combo1.AddOption("Combo Box No.1")
	combo1.AddOption("Combo Box No.2")
	combo1.AddOption("Combo Box No.3")
	# Make one of the options in the combo box selected by default.
	combo1.SetSelectedOption("Combo Box No.2")
	combo1.SetTextColor(ColorPt.new(1, 0, 0), 3)
	combo1.SetFontSize(28)
	combo1.RefreshAppearance
	blank_page.AnnotPushBack(combo1)

	# ListBox Widget Creation
	list1 = ListBoxWidget.Create(doc, Rect.new(400, 620, 580, 730))
	# Add one option to the listbox widget.
	list1.AddOption("List Box No.1")
	# Add multiple options to the listbox widget in a batch.
	list_options = ["List Box No.2", "List Box No.3"]
	list1.AddOptions(list_options)
	# Select some of the options in list box as default options
	list1.SetSelectedOptions(list_options)
	# Enable list box to have multi-select when editing. 
	list1.GetField().SetFlag(Field::E_multiselect, true)
	list1.SetFont(Font.Create(doc.GetSDFDoc,Font::E_times_italic))
	list1.SetTextColor(ColorPt.new(1, 0, 0), 3)
	list1.SetFontSize(28)
	list1.SetBackgroundColor(ColorPt.new(1, 1, 1), 3)
	list1.RefreshAppearance
	blank_page.AnnotPushBack(list1)

	# RadioButton Widget Creation
	# Create a radio button group and Add three radio buttons in it. 
	radio_group = RadioButtonGroup.Create(doc, "RadioGroup")
	radiobutton1 = radio_group.Add(Rect.new(140, 410, 190, 460))
	radiobutton1.SetBackgroundColor(ColorPt.new(1, 1, 0), 3)
	radiobutton1.RefreshAppearance
	radiobutton2 = radio_group.Add(Rect.new(310, 410, 360, 460))
	radiobutton2.SetBackgroundColor(ColorPt.new(0, 1, 0), 3)
	radiobutton2.RefreshAppearance
	radiobutton3 = radio_group.Add(Rect.new(480, 410, 530, 460))
	# Enable the third radio button. By default the first one is selected
	radiobutton3.EnableButton
	radiobutton3.SetBackgroundColor(ColorPt.new(0, 1, 1), 3)
	radiobutton3.RefreshAppearance
	radio_group.AddGroupButtonsToPage(blank_page)

	# Custom push button annotation creation
	custom_pushbutton1 = PushButtonWidget.Create(doc, Rect.new(260, 320, 360, 360))
	# Set the annotation appearance.
	custom_pushbutton1.SetAppearance(CreateCustomButtonAppearance(doc, false), Annot::E_normal)
	# Create 'SubmitForm' action. The action will be linked to the button.
	url = FileSpec.CreateURL(doc.GetSDFDoc, "http://www.pdftron.com")
	button_action = Action.CreateSubmitForm(url)
	# Associate the above action with 'Down' event in annotations action dictionary.
	annot_action = custom_pushbutton1.GetSDFObj.PutDict("AA")
	annot_action.Put("D", button_action.GetSDFObj)
	blank_page.AnnotPushBack(custom_pushbutton1)


	# Add the page as the last page in the document.
	doc.PagePushBack(blank_page)		
									 
	# If you are not satisfied with the look of default auto-generated appearance 
	# streams you can delete "AP" entry from the Widget annotation and set 
	# "NeedAppearances" flag in AcroForm dictionary:
	#	doc.GetAcroForm.PutBool("NeedAppearances", true);
	# This will force the viewer application to auto-generate new appearance streams 
	# every time the document is opened.
	#
	# Alternatively you can generate custom annotation appearance using ElementWriter 
	# and then set the "AP" entry in the widget dictionary to the new appearance
	# stream.
	#
	# Yet another option is to pre-populate field entries with dummy text. When 
	# you edit the field values using PDFNet the new field appearances will match 
	# the old ones.

	#doc.GetAcroForm.PutBool("NeedAppearances", true)
	doc.RefreshFieldAppearances
	
	doc.Save(output_path + "forms_test1.pdf", 0)
	doc.Close
	puts "Done."
	
	#----------------------------------------------------------------------------------
	# Example 2: 
	# Fill-in forms / Modify values of existing fields.
	# Traverse all form fields in the document (and  puts out their names). 
	# Search for specific fields in the document.
	#----------------------------------------------------------------------------------
	
	doc = PDFDoc.new(output_path + "forms_test1.pdf")
	doc.InitSecurityHandler
	
	itr = doc.GetFieldIterator
	field_names = Hash.new
	while itr.HasNext do

		cur_field_name = itr.Current.GetName
        	# Add one to the count for this field name for later processing
        	field_names[cur_field_name] = field_names.has_key?(cur_field_name) ? field_names[cur_field_name] + 1 : 1

		puts "Field name: " + itr.Current.GetName
		puts "Field partial name: " + itr.Current.GetPartialName
		
		print "Field type: "
		type = itr.Current.GetType
		str_val = itr.Current.GetValueAsString
		if type == Field::E_button
			puts "Button"
		elsif type == Field::E_radio
			puts "Radio button: Value = " + str_val
		elsif type == Field::E_check
			itr.Current.SetValue(true)
			puts "Check box: Value = " + str_val
		elsif type == Field::E_text
			puts "Text"
			# Edit all variable text in the document
			itr.Current.SetValue("This is a new value. The old one was: " + str_val)
		elsif type == Field::E_choice
			puts "Choice"
		elsif type == Field::E_signature
			puts "Signature"
		end
		puts "------------------------------"
		itr.Next
	end

	# Search for a specific field
	f = doc.GetField("employee.name.first")
	if !f.nil?
		puts "Field search for " + f.GetName + " was successful"
	else
		puts "Field search failed"
	end
		
	# Regenerate field appearances.
	doc.RefreshFieldAppearances
	doc.Save(output_path + "forms_test_edit.pdf", 0)
	doc.Close
	puts "Done."
	
	#----------------------------------------------------------------------------------
	# Sample: Form templating
	# Replicate pages and form data within a document. Then rename field names to make 
	# them unique.
	#----------------------------------------------------------------------------------
	
	# Sample: Copying the page with forms within the same document
	doc = PDFDoc.new(output_path + "forms_test1.pdf")
	doc.InitSecurityHandler
	
	src_page = doc.GetPage(1)
	doc.PagePushBack(src_page) # Append several copies of the first page
	doc.PagePushBack(src_page) # Note that forms are successfully copied
	doc.PagePushBack(src_page)
	doc.PagePushBack(src_page)
	
	# Now we rename fields in order to make every field unique.
	# You can use this technique for dynamic template filling where you have a 'master'
	# form page that should be replicated, but with unique field names on every page. 
	field_names.each do | key, val |
  		RenameAllFields(doc, key, val) 
	end
	doc.Save(output_path + "forms_test1_cloned.pdf", 0)
	doc.Close
	puts "Done."
	
	#----------------------------------------------------------------------------------
	# Sample: 
	# Flatten all form fields in a document.
	# Note that this sample is intended to show that it is possible to flatten
	# individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations
	# that will automatically flatten all fields.
	#----------------------------------------------------------------------------------
	doc = PDFDoc.new(output_path + "forms_test1.pdf")
	doc.InitSecurityHandler
	 
	# Traverse all pages
	if false
		doc.FlattenAnnotations
	else # Manual flattening
		pitr = doc.GetPageIterator
		while pitr.HasNext do
			page = pitr.Current
			i = page.GetNumAnnots - 1
			while i >= 0
				annot = page.GetAnnot(i)
				if annot.GetType == Annot::E_Widget
					annot.Flatten(page)
				end
				i = i - 1
			end
			pitr.Next
		end
	end

	doc.Save(output_path + "forms_test1_flattened.pdf", 0)
	doc.Close
	PDFNet.Terminate
	puts "Done."
```

{% endcode %}
{% endtab %}

{% tab title="VB" %}
{% code lineNumbers="true" %}

```vb
'---------------------------------------------------------------------------------------
' Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
' Consult legal.txt regarding legal and license information.
'---------------------------------------------------------------------------------------

Imports System
Imports System.Collections.Generic
Imports pdftron
Imports pdftron.Common
Imports pdftron.SDF
Imports pdftron.PDF
Imports pdftron.PDF.Annots

'---------------------------------------------------------------------------------------
' This sample illustrates basic PDFNet capabilities related to interactive 
' forms (also known as AcroForms). 
'---------------------------------------------------------------------------------------
Module InteractiveFormsTestVB
    Dim pdfNetLoader As PDFNetLoader
    Sub New()
        pdfNetLoader = pdftron.PDFNetLoader.Instance()
    End Sub

    Sub Main()

        PDFNet.Initialize(PDFTronLicense.Key)

        ' Relative path to the folder containing test files.
        ' Dim input_path As String = "../../../../TestFiles/"
        Dim output_path As String = "../../../../TestFiles/Output/"

        ' The vector used to store the name And count of all fields.
        ' This Is used later on to clone the fields
        Dim field_names As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)()

        Try
            '----------------------------------------------------------------------------------
            ' Example 1: Programatically create new Form Fields and Widget Annotations.
            '----------------------------------------------------------------------------------
            Using doc As PDFDoc = New PDFDoc
                ' Create a blank page and some new fields (aka "AcroForms").
                Dim blank_page As Page = doc.PageCreate()

                ' Text Widget Creation 
                ' Create an empty text widget with black text.
                Dim text1 As TextWidget = TextWidget.Create(doc, New Rect(110, 700, 380, 730))
                text1.SetText("Basic Text Field")
                text1.RefreshAppearance()
                blank_page.AnnotPushBack(text1)
                ' Create a vertical text widget with blue text And a yellow background.
                Dim text2 As TextWidget = TextWidget.Create(doc, New Rect(50, 400, 90, 730))
                text2.SetRotation(90)
                ' Set the text content.
                text2.SetText("    ****Lucky Stars!****")
                ' Set the font type, text color, font size, border color And background color.
                text2.SetFont(Font.Create(doc, Font.StandardType1Font.e_helvetica_oblique))
                text2.SetFontSize(28)
                text2.SetTextColor(New ColorPt(0, 0, 1), 3)
                text2.SetBorderColor(New ColorPt(0, 0, 0), 3)
                text2.SetBackgroundColor(New ColorPt(1, 1, 0), 3)
                text2.RefreshAppearance()
                ' Add the annotation to the page.
                blank_page.AnnotPushBack(text2)
                ' Create two New text widget with Field names employee.name.first And employee.name.last
                ' This logic shows how these widgets can be created using either a field name string Or
                ' a Field object
                Dim text3 As TextWidget = TextWidget.Create(doc, New Rect(110, 660, 380, 690), "employee.name.first")
                text3.SetText("Levi")
                text3.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_bold))
                text3.RefreshAppearance()
                blank_page.AnnotPushBack(text3)
                Dim emp_last_name As Field = doc.FieldCreate("employee.name.last", Field.Type.e_text, "Ackerman")
                Dim text4 As TextWidget = TextWidget.Create(doc, New Rect(110, 620, 380, 650), emp_last_name)
                text4.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_bold))
                text4.RefreshAppearance()
                blank_page.AnnotPushBack(text4)

                ' Signature Widget Creation (unsigned)
                Dim signature1 As SignatureWidget = SignatureWidget.Create(doc, New Rect(110, 560, 260, 610))
                signature1.RefreshAppearance()
                blank_page.AnnotPushBack(signature1)

                ' CheckBox Widget Creation
                ' Create a check box widget that Is Not checked.
                Dim check1 As CheckBoxWidget = CheckBoxWidget.Create(doc, New Rect(140, 490, 170, 520))
                check1.RefreshAppearance()
                blank_page.AnnotPushBack(check1)
                ' Create a check box widget that Is checked.
                Dim check2 As CheckBoxWidget = CheckBoxWidget.Create(doc, New Rect(190, 490, 250, 540), "employee.name.check1")
                check2.SetBackgroundColor(New ColorPt(1, 1, 1), 3)
                check2.SetBorderColor(New ColorPt(0, 0, 0), 3)
                ' Check the widget (by default it Is unchecked).
                check2.SetChecked(True)
                check2.RefreshAppearance()
                blank_page.AnnotPushBack(check2)

                ' PushButton Widget Creation
                Dim pushbutton1 As PushButtonWidget = PushButtonWidget.Create(doc, New Rect(380, 490, 520, 540))
                pushbutton1.SetTextColor(New ColorPt(1, 1, 1), 3)
                pushbutton1.SetFontSize(36)
                pushbutton1.SetBackgroundColor(New ColorPt(0, 0, 0), 3)
                ' Add a caption for the pushbutton.
                pushbutton1.SetStaticCaptionText("PushButton")
                pushbutton1.RefreshAppearance()
                blank_page.AnnotPushBack(pushbutton1)

                ' ComboBox Widget Creation
                Dim combo1 As ComboBoxWidget = ComboBoxWidget.Create(doc, New Rect(280, 560, 580, 610))
                ' Add options to the combobox widget.
                combo1.AddOption("Combo Box No.1")
                combo1.AddOption("Combo Box No.2")
                combo1.AddOption("Combo Box No.3")
                ' Make one of the options in the combo box selected by default.
                combo1.SetSelectedOption("Combo Box No.2")
                combo1.SetTextColor(New ColorPt(1, 0, 0), 3)
                combo1.SetFontSize(28)
                combo1.RefreshAppearance()
                blank_page.AnnotPushBack(combo1)

                ' ListBox Widget Creation
                Dim list1 As ListBoxWidget = ListBoxWidget.Create(doc, New Rect(400, 620, 580, 730))
                ' Add one option to the listbox widget.
                list1.AddOption("List Box No.1")
                ' Add multiple options to the listbox widget in a batch.
                Dim list_options As String() = New String(1) {"List Box No.2", "List Box No.3"}
                list1.AddOptions(list_options)
                ' Select some of the options in list box as default options.
                list1.SetSelectedOptions(list_options)
                ' Enable list box to have multi-select when editing.
                list1.GetField().SetFlag(Field.Flag.e_multiselect, True)
                list1.SetFont(Font.Create(doc, Font.StandardType1Font.e_times_italic))
                list1.SetTextColor(New ColorPt(1, 0, 0), 3)
                list1.SetFontSize(28)
                list1.SetBackgroundColor(New ColorPt(1, 1, 1), 3)
                list1.RefreshAppearance()
                blank_page.AnnotPushBack(list1)

                ' RadioButton Widget Creation
                ' Create a radio button group And add three radio buttons in it. 
                Dim radio_group As RadioButtonGroup = RadioButtonGroup.Create(doc, "RadioGroup")
                Dim radiobutton1 As RadioButtonWidget = radio_group.Add(New Rect(140, 410, 190, 460))
                radiobutton1.SetBackgroundColor(New ColorPt(1, 1, 0), 3)
                radiobutton1.RefreshAppearance()
                Dim radiobutton2 As RadioButtonWidget = radio_group.Add(New Rect(310, 410, 360, 460))
                radiobutton2.SetBackgroundColor(New ColorPt(0, 1, 0), 3)
                radiobutton2.RefreshAppearance()
                Dim radiobutton3 As RadioButtonWidget = radio_group.Add(New Rect(480, 410, 530, 460))
                ' Enable the third radio button. By default the first one is selected.
                radiobutton3.EnableButton()
                radiobutton3.SetBackgroundColor(New ColorPt(0, 1, 1), 3)
                radiobutton3.RefreshAppearance()
                radio_group.AddGroupButtonsToPage(blank_page)

                ' Custom push button annotation creation
                Dim custom_pushbutton1 As PushButtonWidget = PushButtonWidget.Create(doc, New Rect(260, 320, 360, 360))
                ' Set the annotation appearance.
                custom_pushbutton1.SetAppearance(CreateCustomButtonAppearance(doc, False), Annot.AnnotationState.e_normal)
                ' Create 'SubmitForm' action. The action will be linked to the button.
                Dim url As FileSpec = FileSpec.CreateURL(doc, "http://www.pdftron.com")
                Dim button_action As pdftron.PDF.Action = pdftron.PDF.Action.CreateSubmitForm(url)
                ' Associate the above action with 'Down' event in annotations action dictionary.
                Dim annot_action As Obj = custom_pushbutton1.GetSDFObj().PutDict("AA")
                annot_action.Put("D", button_action.GetSDFObj())
                blank_page.AnnotPushBack(custom_pushbutton1)

                ' Add the page as the last page in the document.
                doc.PagePushBack(blank_page)

                ' If you are not satisfied with the look of default auto-generated appearance 
                ' streams you can delete "AP" entry from the Widget annotation and set 
                ' "NeedAppearances" flag in AcroForm dictionary:
                '    doc.GetAcroForm().PutBool("NeedAppearances", true)
                '    			
                ' This will force the viewer application to auto-generate new appearance streams 
                ' every time the document is opened.
                '
                ' Alternatively you can generate custom annotation appearance using ElementWriter 
                ' and then set the "AP" entry in the widget dictionary to the new appearance
                ' stream.
                '
                ' Yet another option is to pre-populate field entries with dummy text. When 
                ' you edit the field values using PDFNet the new field appearances will match 
                ' the old ones.
                doc.RefreshFieldAppearances()

                doc.Save(output_path + "forms_test1.pdf", 0)
            End Using
            Console.WriteLine("Done.")

            '----------------------------------------------------------------------------------
            ' Example 2: 
            ' Fill-in forms / Modify values of existing fields.
            ' Traverse all form fields in the document (and print out their names). 
            ' Search for specific fields in the document.
            '----------------------------------------------------------------------------------
            Using doc As PDFDoc = New PDFDoc(output_path & "forms_test1.pdf")
                doc.InitSecurityHandler()
                Dim itr As FieldIterator
                itr = doc.GetFieldIterator()

                While itr.HasNext()
                    Dim field As Field = itr.Current()
                    Dim cur_field_name As String = field.GetName()
                    ' Add one to the count for this field name for later processing
                    field_names(cur_field_name) = (If(field_names.ContainsKey(cur_field_name), field_names(cur_field_name) + 1, 1))
                    Console.WriteLine("Field name: {0}", field.GetName())
                    Console.WriteLine("Field partial name: {0}", field.GetPartialName())
                    Dim str_val As String = field.GetValueAsString()
                    Console.Write("Field type: ")
                    Dim type As Field.Type = field.[GetType]()

                    Select Case type
                        Case Field.Type.e_button
                            Console.WriteLine("Button")
                        Case Field.Type.e_radio
                            Console.WriteLine("Radio button: Value = " & str_val)
                        Case Field.Type.e_check
                            field.SetValue(True)
                            Console.WriteLine("Check box: Value = " & str_val)
                        Case Field.Type.e_text
                            Console.WriteLine("Text")
                            Dim old_value As String = "none"
                            If field.GetValue() IsNot Nothing Then old_value = field.GetValue().GetAsPDFText()
                            ' Edit all variable text in the document
                            field.SetValue("This is a new value. The old one was: " & old_value)
                        Case Field.Type.e_choice
                            Console.WriteLine("Choice")
                        Case Field.Type.e_signature
                            Console.WriteLine("Signature")
                    End Select

                    Console.WriteLine("------------------------------")
                    itr.[Next]()
                End While

                ' Search for a specific field
                Dim fld As Field = doc.GetField("employee.name.first")

                If fld IsNot Nothing Then
                    Console.WriteLine("Field search for {0} was successful", fld.GetName())
                Else
                    Console.WriteLine("Field search failed.")
                End If

                ' Regenerate field appearances.
                doc.RefreshFieldAppearances()
                doc.Save(output_path & "forms_test_edit.pdf", 0)
                ' output PDF doc
                Console.WriteLine("Done.")
            End Using

        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try
        '----------------------------------------------------------------------------------
        ' Sample: Form templating
        ' Replicate pages and form data within a document. Then rename field names to make 
        ' them unique.
        '----------------------------------------------------------------------------------
        Try
            ' Sample: Copying the page with forms within the same document
            Using doc As PDFDoc = New PDFDoc(output_path & "forms_test1.pdf")
                doc.InitSecurityHandler()
                Dim src_page As Page = doc.GetPage(1)
                doc.PagePushBack(src_page)   ' Append several copies of the first page
                doc.PagePushBack(src_page)   ' Note that forms are successfully copied
                doc.PagePushBack(src_page)
                doc.PagePushBack(src_page)

                ' Now we rename fields in order to make every field unique.
                ' You can use this technique for dynamic template filling where you have a 'master'
                ' form page that should be replicated, but with unique field names on every page.
                For Each cur_field As KeyValuePair(Of String, Integer) In field_names
                    RenameAllFields(doc, cur_field.Key, cur_field.Value)
                Next

                doc.Save(output_path & "forms_test1_cloned.pdf", 0)
                ' output PDF doc
                Console.WriteLine("Done.")
            End Using

        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try

        '----------------------------------------------------------------------------------
        ' Sample: 
        ' Flatten all form fields in a document.
        ' Note that this sample is intended to show that it is possible to flatten
        ' individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
        ' that will automatically flatten all fields.
        '----------------------------------------------------------------------------------
        Try

            Using doc As PDFDoc = New PDFDoc(output_path & "forms_test1.pdf")
                doc.InitSecurityHandler()

                ' Traverse all pages
                Dim auto As Boolean = True

                If auto Then
                    doc.FlattenAnnotations()
                Else ' Manual flattening
                    Dim pitr As PageIterator = doc.GetPageIterator()

                    While pitr.HasNext()
                        Dim page As Page = pitr.Current()

                        For i As Integer = page.GetNumAnnots() - 1 To 0
                            Dim annot As Annot = page.GetAnnot(i)

                            If annot.[GetType]() = Annot.Type.e_Widget Then
                                annot.Flatten(page)
                            End If
                        Next

                        pitr.[Next]()
                    End While
                End If

                doc.Save(output_path & "forms_test1_flattened.pdf", 0)
                ' output PDF doc
                Console.WriteLine("Done.")
            End Using

        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try
        PDFNet.Terminate()
    End Sub

    ' field_nums has to be greater than 0.
    Sub RenameAllFields(ByVal doc As PDFDoc, ByVal name As String, ByVal Optional field_nums As Integer = 1)
        Dim fld As Field = doc.GetField(name)
        Dim counter As Integer = 1

        While fld IsNot Nothing
            Dim field_new_name As String = name
            Dim update_count As Integer = System.Convert.ToInt32(Math.Ceiling(counter / CDbl(field_nums)))
            fld.Rename(name & "-" & update_count.ToString())
            fld = doc.GetField(name)
            counter += 1
        End While
    End Sub

    Function CreateCustomButtonAppearance(ByRef doc As PDFDoc, ByVal button_down As Boolean) As Obj
        ' Create a button appearance stream ------------------------------------
        Dim builder As ElementBuilder = New ElementBuilder
        Dim writer As ElementWriter = New ElementWriter

        writer.Begin(doc.GetSDFDoc())

        ' Draw background
        Dim element As Element = builder.CreateRect(0, 0, 101, 37)
        element.SetPathFill(True)
        element.SetPathStroke(False)
        element.GetGState().SetFillColorSpace(ColorSpace.CreateDeviceGray())
        element.GetGState().SetFillColor(New ColorPt(0.75, 0, 0))
        writer.WriteElement(element)

        ' Draw 'Submit' text
        writer.WriteElement(builder.CreateTextBegin())

        element = builder.CreateTextRun("Submit", Font.Create(doc, Font.StandardType1Font.e_helvetica_bold), 12)
        element.GetGState().SetFillColor(New ColorPt(0, 0, 0))

        If (button_down) Then
            element.SetTextMatrix(1, 0, 0, 1, 33, 10)
        Else
            element.SetTextMatrix(1, 0, 0, 1, 30, 13)
        End If

        writer.WriteElement(element)
        writer.WriteElement(builder.CreateTextEnd())

        Dim stm As Obj = writer.End()

        ' Calling Dispose() on ElementReader/Writer/Builder can result in increased performance and lower memory consumption.
        writer.Dispose()
        builder.Dispose()

        ' Set the bounding box
        stm.PutRect("BBox", 0, 0, 101, 37)
        stm.PutName("Subtype", "Form")
        Return stm
    End Function

End Module
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/core/get-started/samples/interactiveformstest.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
