Indlejring af et PDF-læsepanel i en Delphi-forretningsapplikation kræver ikke, at du skriver en renderingsløkke, en rullemaskine eller en zoommodel. losLab PDF Library leveres med TPDFlibViewer, en VCL-kontrol, der åbner et dokument med et enkelt kald og tilbyder tekstvalg, panorering, markeringszoom, snapshots, fremhævning af områder, fuldtekstsøgningsfremhævning, annoteringsinteraktion og udskrivning som indbygget adfærd. Denne artikel gennemgår de fem trin, der forvandler en tom formular til en fungerende fremviser: Placer kontrollen, tilslut de færdige handlinger, tilføj søgefremhævning, håndter annoteringsklik og udskriv
Hvorfor bruge en fremviserkontrol i stedet for at skrive en renderingsløkke?
Lagdelingsargumentet kommer først, fordi det forklarer, hvad du rent faktisk køber. At rendere en side til et bitmap er de nemme 20 procent; de øvrige 80 procent er alt det, der er pakket udenom: En side-bitmap-cache med et frigørelsesbudget, rullelayout på tværs af sider af forskellige størrelser, zoomtilstande, der genberegnes ved størrelsesændring, hit-testning, der kortlægger en musepixel tilbage til sidekoordinater ved enhver zoom og rotation, og planlægning av genoptegning, der ikke flimrer. TPDFlibViewer ejer alt dette og delegerer rasterarbejdet til den samme motor, der er beskrevet i artiklen om multirat-rendering, så kontrol- og renderingslaget forbliver separat udskiftelige. Din formularkode taler med en rullebar Windows-kontrol, ikke med en renderer
Hvordan indlejrer du en PDF-fremviser i en Delphi-applikation?
TPDFlibViewer.LoadFromFile åbner et dokument gennem kontrollens egen interne TPDFlib-instans og returnerer 1 ved succes, så den minimale fremviser er et konstruktørkald, en Parent-tildeling og en enkelt indlæsning. Hvis du allerede har en TPDFlib-instans et andet sted i applikationen, viser AttachLibrary i stedet dens valgte dokument, hvor ejerskabet forbliver på din side
uses PDFlibViewer;
procedure TMainForm.FormCreate(Sender: TObject);
begin
FViewer := TPDFlibViewer.Create(Self);
FViewer.Parent := Self;
FViewer.Align := alClient;
if FViewer.LoadFromFile('quarterly-report.pdf', '') = 1 then
FViewer.ViewerMode := vmHand; // pan by dragging; a plain click still follows links
end;
Egenskaben ViewerMode vælger, hvad musen gør, ud fra fem værdier: vmSelect er standardværktøjet til tekstvalg, vmHand panorerer ved at trække med en gribecursor, mens et almindeligt klik stadig følger links, vmZoom er en markeringszoom, der forstørrer det trukne bånd, så det udfylder visningsområdet, vmSnapshot fanger et trukket område til udklipsholderen (med en OnSnapshot-hændelse og en SnapshotToClipboard-knap), og vmHighlight maler permanente halvgennemsigtige områdefremhævninger. Fremhævningsværktøjet er værd at bemærke med hensyn til koordinater: Områder gemmes i sidens brugerområde, ikke i klientpixels, så AddHighlightRegion-markeringer overlever zoom, visningsrotation og sidenavigation uden nogen bogføring på din side. I en roteret visning kan trækretningen endda køre mod sideakserne, hvilket giver en negativ bredde eller højde efter den omvendte rotationskortlægning — kontrollen normaliserer rektanglet for dig
Hvordan forbinder du en PDF-værktøjslinje i Delphi uden limkode?
Enheden PDFlibViewerActions fjerner værktøjslinjens limkode fuldstændigt. Den indeholder tyve færdige TAction-efterkommere, der dækker sidenavigation (TPDFlibViewerFirstPage, TPDFlibViewerPriorPage, TPDFlibViewerNextPage, TPDFlibViewerLastPage), zoom (TPDFlibViewerZoomIn, TPDFlibViewerZoomOut, TPDFlibViewerFitWidth, TPDFlibViewerFitPage, TPDFlibViewerActualSize), visningsrotation (TPDFlibViewerRotateClockwise, TPDFlibViewerRotateAntiClockwise), udskrivning, dialoger til åbning og lagring af filer, kopiering af valgt tekst samt én skiftehandling pr. museværktøj (TPDFlibViewerSelectMode, TPDFlibViewerHandMode, TPDFlibViewerMarqueeZoomMode, TPDFlibViewerSnapshotMode, TPDFlibViewerHighlightMode). Hver handling peger på en kontrol via dens publicerede Viewer-egenskab og opretholder sin egen tilstand: Hver handling deaktiverer sig selv, når intet dokument er åbent, navigationshandlingerne sporer sidepositionen, kopiering sporer, om der findes et valg, og tilstands- og tilpasningshandlingerne holder deres markerede tilstand synkroniseret med det aktive værktøj og zoomtilstand. Ved designtid registreres de alle i losLab PDF-kategorien i Action List-editoren; under kørsel er de samme klasser på tre linjer hver
uses System.Actions, Vcl.ActnList, PDFlibViewer, PDFlibViewerActions;
procedure TMainForm.BuildToolbar;
var
NextPage: TPDFlibViewerNextPage;
FitWidth: TPDFlibViewerFitWidth;
HandMode: TPDFlibViewerHandMode;
begin
NextPage := TPDFlibViewerNextPage.Create(Self);
NextPage.ActionList := ActionList1;
NextPage.Viewer := FViewer;
btnNext.Action := NextPage;
FitWidth := TPDFlibViewerFitWidth.Create(Self);
FitWidth.ActionList := ActionList1;
FitWidth.Viewer := FViewer;
btnFitWidth.Action := FitWidth;
HandMode := TPDFlibViewerHandMode.Create(Self);
HandMode.ActionList := ActionList1;
HandMode.Viewer := FViewer;
btnHand.Action := HandMode;
end;
En fælde i enhedsomfang er værd at kende, hvis du bygger din egen handlingsregistrering oven på dette mønster. RegisterActions er erklæret i System.Actions, ikke i Vcl.ActnList, og den kompilatorfejl, du får med kun Vcl.ActnList i uses-klausulen, er aktivt vildledende: Literalen [TAction1, TAction2, ...] falder tilbage til at blive analyseret som et sæt, hvilket producerer en kæde af E2010 Incompatible types: 'Integer' and 'class of ...'-fejl, der ligner et typesammenstød i dine handlingsklasser. Løsningen er en enkelt uses-indtastning, men diagnosticeringen peger alle andre steder hen end på den. For zoom-værktøjslinjer rapporterer TPDFlibViewer.EffectiveZoomPercent den zoom, der rent faktisk er i kraft — inklusive den beregnede faktor i tilpas-bredde- og tilpas-side-tilstande — så et zoom-ind-trin kan bygge på den reelle aktuelle forstørrelse i stedet for på den sidste værdi, du tildelte
Søgeresultatsfremhævning og koordinatvendingen bag den
HighlightSearchHits søger i hele dokumentet efter en forespørgsel og maler en halvgennemsigtig bjælke over hvert match og returnerer antallet af hits; ClearSearchHighlights, SearchHighlightCount og egenskaben SearchHighlightColor fuldender overfladen. Fordi hit-rektanglerne gemmes i sideområdet og genprojiceres ved hver optegning, forbliver bjælkerne limet til deres tekst, mens brugeren ruller, zoomer og roterer visningen. Hvis du bruger den tilhørende TPDFlibSearchPanel, maler dens RunSearch automatisk de samme bjælker i den tilsluttede fremviser via egenskaben HighlightInView, som er slået til som standard
procedure TMainForm.btnSearchClick(Sender: TObject);
var
Hits: Integer;
begin
FViewer.SearchHighlightColor := clYellow;
Hits := FViewer.HighlightSearchHits(edtQuery.Text, False); // case-insensitive
StatusBar1.SimpleText := Format('%d matches', [Hits]);
end;
Den delikate del, og grunden til at foretrække den indbyggede sti frem for at lave din egen ud fra rå søgeresultater, er konverteringen af koordinatsystemet. Tekstmotoren rapporterer match-rektangler i koordinater, der afhænger af bibliotekets Origin-indstilling: Med Origin 0 eller 3 kører Y-aksen nedefra og op som i det indfødte PDF-brugerområde, og med Origin 2 or 3 måles X-aksen fra højre kant. Fremviserens overlejring arbejder i top-down, venstrebaseret sideområde, så hvert hit-rektangel skal vendes (Y = PageHeight - Bottom, og hvor det er relevant X = PageWidth - Right) før det gemmes — hvis man tager den rapporterede øverste kant for pålydende under standardoprindelsen, males fremhævningen i den lodret spejlede position på siden. TPDFlibViewer udfører denne konvertering i henhold til den aktive oprindelse, når den registrerer hvert hit, og anvender derefter den fremadgående rotationskortlægning ved optegning, hvilket er grunden til, at bjælkerne lander korrekt i enhver vinkel. Selve gennemsigtigheden bruger Windows AlphaBlend-API'en med en konstant kilde-alpha, da VCL-lærredet ikke har nogen indbygget alpha-komponering. De underliggende tekstsøgnings- og geometri-API'er er dækket i dybden i artiklen om tekstsøgning og numerering af sideelementer
Annoteringsklik, tips og eksport af vedhæftede filer
TPDFlibViewer behandler annoteringer som førsteklasses interaktive objekter. Klik på en ikke-link-annotering udløser OnAnnotClick med sidenummeret, det 1-baserede annoteringsindeks og undertypestrengen; AnnotAtPagePoint eksponerer den samme hit-test programmatisk og springer Popup-ledsagerannoteringer over, så du altid får den annotering, brugeren faktisk ser. Hovering over en annotering viser dens indholdstekst som kontrollens tip via AnnotHints-kontakten, som er slået til som standard og samarbejder med standard VCL-egenskaben ShowHint. For FileAttachment-annoteringer skriver SaveAnnotAttachmentToFile den indlejrede fil til disken og returnerer 1 ved succes, hvilket fuldfører et klik-for-at-gemme-workflow på få linjer
procedure TMainForm.ViewerAnnotClick(Sender: TObject; APage, AnnotIndex: Integer;
const Subtype: WideString);
begin
if Subtype = 'FileAttachment' then
if FViewer.SaveAnnotAttachmentToFile(APage, AnnotIndex,
'C:\Temp\attached-invoice.xml') = 1 then
StatusBar1.SimpleText := 'Attachment saved';
end;
Udskrivning og de grænser, du bør planlægge efter
Udskrivning kræver ingen separat integration. PrintDoc viser standard Windows-udskrivningsdialogen — printervalg, sideområde, kopier, sortering — og overgiver jobbet til bibliotekets udskrivningsmotor, mens PrintDoc(False) sender hele dokumentet til standardprinteren helt uden brugergrænseflade. PrintDocRange kører fuldt programmatisk med et eksplicit printernavn, start- og slutside, antal kopier og sorteringsflag, hvilket er det rette indgangspunkt for batch- eller serverudløste udskrivningsjob drevet fra samme fremviserinstans
To grænser fortjener ærlig omtale. For det første er TPDFlibViewer en Windows VCL-kontrol; fremviserlaget er udelukket fra NOVCL-builds, så konsoltjenester og ikke-VCL-mål bør bruge den underliggende TPDFlib-renderings-API direkte. For det andet understøttes headless brug bevidst, men er begrænset: CaptureRegion renderer enhver klientregion — sider plus fremhævninger — til et bitmap, der ejes af kalderen, og fungerer på en kontrol uden overordnet element uden et vindueshåndtag, fordi optegningsstien undgår VCL-kald, der ville tvinge oprettelse af et håndtag. Det gør verifikation på pixelniveau i automatiserede test praktisk, men alt, hvad der reelt har brug for en meddelelsesløkke, såsom de interaktive museværktøjer, hører stadig hjemme i en rigtig brugergrænsefladesession. På ydeevnesiden beholder kontrollen en hukommelsessidecache med et konfigurerbart budget via SetCacheLimit og kan bevare renderede sider på tværs af sessioner; artiklen om fremviserens disk-side-cache dækker dette lag og dets DPI-adfærd pr. skærm i detaljer
Fem trin altså: Placer kontrollen og kald LoadFromFile, tilslut de færdige handlinger fra PDFlibViewerActions, kald HighlightSearchHits for søgning på siden, håndter OnAnnotClick for annoteringsworkflows og eksponer PrintDoc. Hver del, der vises her, leveres i standarden losLab PDF Library til Delphi, hvor fremviserkontrollen, handlingsklasserne og renderingsmotoren installeres sammen