Trykk Tab i et PDF-skjema koden din bygde, og markøren havner to felt unna der den skulle, eller hopper over den andre kolonnen helt, eller hopper tilbake til toppen etter det tredje feltet i stedet for det fjerde. Personen som fyller ut en faktura i fremviseren din, forventer at tastaturet vandrer gjennom skjemaet på samme måte som det vandrer gjennom hvert eneste nettskjema de noensinne har brukt. Når det ikke gjør det, griper de til musen, jakter på neste boks, og bestemmer stille at verktøyet ditt er uferdig. Forutsigbar feltnavigering er forskjellen mellom en dataregistreringsfremviser folk tolererer, og én de stoler på, og det handler nesten utelukkende om å bruke riktig fokus-API i stedet for å simulere tastaturinndata med falske klikk
Eksemplene under bruker PDFium Component, en PDFium-basert VCL/LCL-komponent for Delphi, C++Builder og Lazarus. Navigering er én av tre ting en skjemafremviser må få riktig; de to andre, å åpne skjemaet korrekt og å lagre utfylte verdier slik at de faktisk vises, er der de fleste overraskelsene gjemmer seg, så alle tre dekkes under
Å åpne et skjema: FormFill, FormType og XFA-spørsmålet
Felttilgang krever at delsystemet for skjemautfylling, styrt av FormFill-egenskapen, er aktivert før dokumentet åpnes. Når det er aktivt, forteller FormType deg hva slags skjema du står overfor, og svaret endrer funksjonssettet du kan love:
Pdf.FileName := FormPath;
Pdf.FormFill := True; // aktiver før Active; påkrevd for all felttilgang
Pdf.Active := True;
case Pdf.FormType of
ftNone:
DisableFormPanel('This document has no interactive form');
ftAcroForm:
BuildFieldList; // full feltnavigering og -redigering tilgjengelig
ftXfaFull:
ShowXfaNotice; // XFA rendres fra sin egen XML-mal;
// behandle feltredigering som begrenset
end;
To praktiske notater følger av det valget. AcroForm er den standard ISO 32000-skjemamodellen, og det er det alle API-ene her retter seg mot. XFA-dokumenter bygger inn sin egen XML-skjemaarkitektur, så å love en kunde full XFA-redigering etter en rask AcroForm-demo er en forpliktelse du vil angre på. Det andre notatet handler om sideeffekter: å sette FormFill til True initialiserer også dokument-JavaScript. I en dataregistreringsfremviser er det nøyaktig riktig, fordi beregningsskript er det som holder en løpende sum oppdatert mens noen skriver. I et forhåndsvisningsvindu for filer av ukjent opprinnelse er det nøyaktig feil. Artikkelen om sikker PDF-forhåndsvisning dekker FormFill := False-siden av den avveiningen
Tab-tastnavigering som lander der brukerne forventer
Tilbake til tastaturproblemet fra toppen. Fristelsen er å simulere Tab ved å syntetisere et museklikk på det neste kontrollelementets rektangel, noe som bryter sammen i det øyeblikket et felt er rullet utenfor skjermen eller to kontrollelementer overlapper. Fokus-API-et flytter i stedet skjemaets eget fokus direkte, uten noen geometrigjetning. Fem kall dekker det: FocusFormField etter indeks, FocusNextFormField og FocusPreviousFormField for steg, FocusedFormFieldIndex for å lese hvor du er, og ClearFormFieldFocus for å slippe fokus helt
procedure TFormViewer.HandleTabKey(Shift: TShiftState);
begin
if ssShift in Shift then
PdfView.FocusPreviousFormField
else
PdfView.FocusNextFormField;
UpdateFieldStatus; // f.eks. "Felt 4 av 17: InvoiceDate"
end;
Den ene atferden som snubler folk opp, er innpakningen. Navigering fungerer gjennom den gjeldende sidens tab-rekkefølge og løper rundt i den: gå forbi det siste feltet, og du er tilbake ved det første. Begge stegfunksjonene returnerer den nye feltindeksen, eller -1 når siden ikke har noen felt i det hele tatt. Den runddannelsen er per side, ikke per dokument, noe som betyr at å krysse over til neste side er din jobb, ikke bibliotekets. Sammenlign den returnerte indeksen mot den du startet fra, merk deg når den har rundet rundt, og fremskyv PageNumber selv hvis skjemaet er ment å leses som én sammenhengende sekvens. Hopp over den sjekken, og et toskjema-skjema fanger markøren stille på side én, noe som er sin egen variant av klagen om ødelagt Tab
Navigering blir nyttig når resten av UI-et reagerer på den. OnFormFieldEnter-hendelsen avfyres når fokus ankommer, og på fremviseren rapporterer OnFormFieldFocusChange den nye feltindeksen, slik at et sidepanel kan holde tritt med hva tastaturet nettopp valgte. Når du trenger den omvendte kartleggingen, fra en skjermposisjon til et felt, gjør den indekserte egenskapen FormFieldAt treffdeteksjonen for verktøytips-forhåndsvisninger og klikk-for-å-redigere-paneler. Det finnes en stille tilgjengelighetsgevinst i alt dette: fordi fokuset følger dokumentets egen feltrekkefølge, er stien du kobler opp for Tab-tasten, den samme stien en skjermleser kunngjør, uten noe ekstra arbeid
Å vise feltnavn i stedet for rå indeksnumre krever én egenskap til. FormFieldInfo[] returnerer en TPdfFormFieldInfo-post per indeks, som bærer feltnavnet, typen, skriftstørrelsen, den avkryssede tilstanden, eksportverdien og gruppemedlemskap, noe som er det en navigeringsliste bør vise ("Felt 4 av 17: InvoiceDate" fremfor "4"). Radioknapp-grupper er tilfellet som fortjener en dedikert testfil. Flere kontrollelementer kan dele ett enkelt feltnavn, så en liste satt sammen naivt fra kontrollelementer viser den samme gruppen flere ganger og forvirrer alle som leser den
Hvorfor utfylte verdier kommer ut tomme, og kallet som fikser det
Den andre klagen som fyller support-køer, er mer alarmerende enn en Tab-tast som oppfører seg feil: et skjema fylles ut programmatisk, kunden åpner det i Acrobat, og hvert felt ser tomt ut. Klikk inn i et felt, og verdien dukker opp i synsfeltet. Dataene har ligget i filen hele tiden. Det som mangler, er bildet av dataene, og grunnen er verdt å forstå én gang fordi den forklarer en hel familie av feil
Et AcroForm-tekstfelt lagrer verdien sin i /V-oppføringen i feltordboken (ISO 32000-1 §12.7.3.3). Det en fremviser faktisk maler, er noe separat: kontrollelementets visningsstrøm under /AP (§12.5.5), et lite ferdigrendret utdrag av innhold. Skriv /V og la /AP være i fred, og de to driver fra hverandre. Verdien er der; den rendrede versjonen av den er foreldet eller fraværende. Acrobat bygger tilfeldigvis om et felts visning når det får fokus, noe som er hele forklaringen på verdier som bare vises ved klikk. Det gamle NeedAppearances-flagget, som ba fremvisere regenerere visninger for deg, fungerte aldri ensartet og er avviklet i PDF 2.0, og utskriftsservere og miniatyrbilde-generatorer ignorerer det fullstendig. De maler /AP og ingenting annet, så hvis /AP er tomt, skriver de ut en tom boks
Å tilordne en verdi gjennom FormField[i] skriver bare /V. Det er derfor å fylle ut et skjema er en trestegs sekvens, og steget team dropper, er det midterste:
procedure TFormViewer.FillAndSave(const Values: array of WString;
const OutputPath: string);
var
i: Integer;
begin
for i := 0 to Pdf.FormFieldCount - 1 do
Pdf.FormField[i] := Values[i]; // skriver bare /V
// Bygg /AP-visningsstrømmene på nytt; uten dette ser skjemaet
// tomt ut i Acrobat helt til hvert felt klikkes på
Pdf.GenerateFormAppearances;
Pdf.SaveAs(OutputPath);
end;
GenerateFormAppearances er hele løsningen. Den bygger om hvert kontrollelements visningsstrøm fra de gjeldende verdiene, skriftene og teksttilpasningen, slik at en fremviser som aldri kjører en fokushendelse, en utskriftsserver eller en miniatyrbildegenerator, likevel maler den utfylte tilstanden. Kall den én gang etter batchen med tilordninger, ikke én gang per felt. Visningsgenerering gjør reelt layoutarbeid, og kall per felt multipliserer det over et stort skjema helt uten grunn
Å regenerere visninger er også øyeblikket hvor skrifter og justering gjør seg gjeldende, noe som er kilden til en overraskelse av annen orden. Den nye strømmen legger hver verdi ut inne i kontrollelementets rektangel ved bruk av feltets skrift, størrelse og teksttilpasning. En verdi som sitter komfortabelt i testskjemaet ditt, kan klippes eller krympes i en kundes kopi hvor det samme feltet er smalere. Autostørrelsesfelt (skriftstørrelse null) krymper teksten for å få den til å passe; faststørrelsesfelt klipper den bare. Begge er lovlige, og den eneste ærlige måten å vite hvilken et gitt skjema gjør, er å se på det regenererte resultatet fremfor strengen du skrev. Når noen rapporterer tekst avkuttet ved kanten av en boks, er dette nesten alltid grunnen
Behandle verifisering som en del av å fullføre arbeidet, ikke en ettertanke. Åpne den lagrede filen i Acrobat og bekreft at verdiene er synlige før du rører noe felt. Skriv den så ut til PDF eller til et bilde fra en annen fremviser, én som ignorerer skjemalogikk helt, og bekreft at verdiene overlever den stien også. Sammen fanger disse to kontrollene hver eneste variant av /V-versus-/AP-driften
Feltkonfigurasjoner som består demoen og feiler i felten
Rene demoskjemaer skjuler et sett med kantede tilfeller kundefiler ikke gjør. Fire av dem står for de fleste "det fungerte på min maskin"-rapportene
- Eksportverdier for avkrysningsbokser. "På"-tilstanden er ikke alltid
Yes. Et skjema står fritt til å definere sin egen eksportverdi, og å skrive feil streng lar boksen forbli visuelt ukrysset mens koden din er overbevist om at den satte den. Les eksportverdien fraFormFieldInfo[]fremfor å anta én - Radioknapp-grupper med delt navn. Ett felt, flere kontrollelementer. Verdien du tilordner, avgjør hvilket kontrollelement som leses som valgt, så UI-kode som antar at ett navn kartlegges til ett rektangel, ender opp med å tegne fokusringen på feil knapp
- Beregnede felt. Totaler vedlikeholdt av dokument-JavaScript oppdateres som svar på felthendelser. En programmatisk utfylling som omgår de hendelsene, må enten utløse omregning eller overskrive de beregnede feltene direkte. Et skjema hvor varelinjene og totalen er uenige, er verre enn begge løsningene
- Skjulte påkrevde felt. Betingede skjemaer skjuler felt som fortsatt er flagget som påkrevd. Bestem på forhånd om valideringen din respekterer synlighet eller det rå påkrevd-flagget, og skriv så ned den beslutningen et sted support kan finne den
Én distinksjon er verdt å avklare før den biter deg: å generere visninger er ikke flating. GenerateFormAppearances gjør verdier synlige overalt mens feltene forblir redigerbare. Flating baker visningen inn i statisk sideinnhold og fjerner interaktiviteten for godt, noe som er riktig for en arkivkopi og feil for et skjema neste person fortsatt må fylle ut. Hvis FormType rapporterer ftXfaFull fremfor ftAcroForm, gjelder ingenting av redigeringsoverflaten her rent uansett, siden dokumentet rendres fra sin egen XML-mal; oppdag det tilfellet og fortell brukeren, i stedet for å la dem finne begrensningen på egen hånd
Delsystemet for skjemautfylling, fokusnavigering og visningsgenerering vist her, er en del av PDFium Component for Delphi, C++Builder og Lazarus/FPC. Hvis fremviseren din også håndterer gjennomgangslesermarkering ved siden av skjemadata, dekker artikkelen om annotasjonsgjennomgang den tilstøtende modellen