Dva otvorena dokumenta istovremeno, isti broj stranice, svaki u svom panelu sa skrolovanjem: to je suština uporednog čitača. PDFium VCL to omogućava kroz jednostavan objektni model gde TPdf poseduje datoteku, a TPdfView upravlja prikazom. Jedan dokument, jedan TPdf, jedan TPdfView. Ako želite tri panela, imaćete tri para. Najteži delovi nisu pozivi API-ja, već aritmetika rasporeda pri promeni veličine prozora i logika sinhronizacije stranica kada odlučujete koji prikaz treba da prati koji.
Raspored na formi
VCL forma sadrži tri TScrollBox kontejnera jedan pored drugog, od kojih svaki sadrži TPdfView sa poravnanjem alClient kako bi popunio prostor. Dve TSplitter komponente se nalaze između njih, omogućavajući korisniku da menja širinu kolona u toku rada. Traka sa alatkama iznad panela sadrži dugmad za otvaranje, kontrole zuma i prekidač za prikaz dva ili tri panela.
Režim sa tri prikaza je logička promenljiva (boolean) koju forma prati interno. Kada se njeno stanje promeni, ponovo izračunavate širine i prikazujete ili sakrivate treću kolonu. Najjednostavniji pristup je da poništite sva Align svojstva, sakrijete splitere, a zatim postavite apsolutne pozicije:
procedure TFormMain.UpdateLayout;
var
TotalWidth: Integer;
begin
TotalWidth := ClientWidth;
if ThreeViewMode then
begin
ScrollBox3.Visible := True;
ScrollBox1.Left := 0;
ScrollBox1.Width := TotalWidth div 3;
ScrollBox2.Left := ScrollBox1.Width;
ScrollBox2.Width := TotalWidth div 3;
ScrollBox3.Left := ScrollBox2.Left + ScrollBox2.Width;
ScrollBox3.Width := TotalWidth - ScrollBox3.Left;
// Apply the same (ClientHeight - toolbar height) to all three Height values
end
else
begin
ScrollBox3.Visible := False;
ScrollBox1.Left := 0;
ScrollBox1.Width := TotalWidth div 2;
ScrollBox2.Left := ScrollBox1.Width;
ScrollBox2.Width := TotalWidth - ScrollBox2.Left;
end;
end;
Postavljanje Align := alNone na sva tri polja pre celobrojne aritmetike sprečava VCL mehanizam ograničenja da ometa vaša dodeljivanja vrednosti. Vratite vidljivost splitera nakon pozicioniranja ako želite promenu veličine prevlačenjem u režimu sa dva prikaza.
Visina svakog ScrollBox-a predstavlja visinu klijentske oblasti minus visina panela sa alatkama. Pošto je traka sa alatkama pozicionirana na vrhu pomoću alTop, formula ClientHeight - PanelButtons.Height daje korisni vertikalni prostor. Dodelite ovu vrednost svim trima ScrollBox-ovima unutar istog poziva UpdateLayout kako biste izbegli situaciju u kojoj je jedan panel viši od drugih, što bi izazvalo treperenje rasporeda.
Otvaranje dokumenta
Svakom paru panela potrebna je sopstvena procedura otvaranja. Šablon je kratak: deaktivirajte komponentu, postavite ime datoteke, pokušajte da aktivirate i uhvatite EPdfError ako datoteka zahteva lozinku. Imajte na umu da TPdfView.Active kontroliše iscrtavanje, dok TPdf.Active zapravo otvara datoteku; ova dva svojstva su nezavisna. Postavljanje PdfView.Active := True kada povezani TPdf još uvek nije aktivan ne izaziva greške, ali ne prikazuje ništa.
procedure TFormMain.OpenPdfFile(PdfComponent: TPdf;
PdfViewComponent: TPdfView);
var
Password: string;
begin
if not OpenDialog.Execute then
Exit;
PdfComponent.Active := False;
PdfComponent.FileName := OpenDialog.FileName;
PdfComponent.Password := '';
try
PdfComponent.Active := True;
except
on E: EPdfError do
begin
if InputQuery('Password', 'Enter document password:', Password) then
begin
PdfComponent.Password := Password;
PdfComponent.Active := True;
end
else
raise;
end;
end;
if PdfComponent.Active then
begin
PdfViewComponent.PageNumber := 1;
SetActivePdfView(PdfViewComponent);
end;
end;
Uvek proverite PdfComponent.Active nakon dodeljivanja vrednosti; oštećena datoteka ili pogrešna lozinka dovode do toga da učitavanje ne uspe bez podizanja izuzetka u podrazumevanoj putanji. Eksplicitno postavljanje PdfViewComponent.PageNumber := 1 nakon uspešnog otvaranja sprečava zadržavanje broja stranice iz prethodnog dokumenta.
Gore navedeni kod za obradu lozinke podiže izuzetak za bilo koju drugu grešku osim poznate poruke o lozinki. To je namerno: želite da oštećene ili nepodržane datoteke odmah budu prijavljene, umesto da ostanu neprimećene kao prazan panel. Korisnik koji ne vidi ništa nema predstavu da li se datoteka učitala i jednostavno je prazna, ili ju je komponenta odbila. Podizanje izuzetka održava grešku vidljivom.
Praćenje aktivnog panela
Kada korisnik klikne unutar panela, taj panel postaje aktivan. Forma interno prati privatno polje FActivePdfView: TPdfView. Vizuelna povratna informacija je promena boje ivice kontejnerskog TScrollBox elementa: postavite je na clHighlight za aktivni panel, a na clWindow za ostale. Povežite ovo sa događajem TPdfView.OnClick i sa procedurom otvaranja kako bi fokus pratio dokument koji ste upravo otvorili.
Neke operacije se primenjuju na sve vidljive panele, a ne samo na aktivni. Logička promenljiva FAllViewsMode na formi upravlja ovom granom. Kada je ona postavljena na True, promene zuma i navigacija stranica se primenjuju na svaki panel koji ima aktivni dokument:
procedure TFormMain.ApplyZoomToAll(NewZoom: Double);
begin
if PdfView1.Active then PdfView1.Zoom := NewZoom;
if PdfView2.Active then PdfView2.Zoom := NewZoom;
if ThreeViewMode and PdfView3.Active then PdfView3.Zoom := NewZoom;
end;
Sinhronizovana navigacija stranica
Sinhronizovana navigacija je opciona, ali korisna za procese revizije dokumenata gde obe datoteke pokrivaju isti opseg stranica. Logika pripada rukovaocu događaja koji se aktivira nakon što korisnik promeni prikaz. Kada izvorni prikaz promeni svoj PageNumber, rukovalac prenosi taj broj na ostale prikaze, uz jedno ograničenje: ciljni prikaz mora imati najmanje toliko stranica, inače se korak preskače.
Svojstva PageNumber na komponentama TPdfView i TPdf su nezavisna. TPdf.PageNumber prati koju stranicu komponenta dokumenta smatra trenutnom, dok TPdfView.PageNumber prati ono što je prikazano na ekranu. Za potrebe navigacije želite svojstvo prikaza, a ne svojstvo dokumenta.
Polje za potvrdu sa oznakom kao što je „Sinhronizuj stranice” daje kontrolu korisniku. Kada nije označeno, svaki panel se navigira nezavisno i rukovalac odmah prekida rad. Ta nezavisnost je važna za slučajeve gde dva dokumenta imaju različit broj stranica ili kada korisnik želi da pronađe ekvivalentan pasus u prevodu koji počinje na drugoj stranici. Primoravanje na stalnu sinhronizaciju učinilo bi alat težim za korišćenje od običnog rasporeda sa dva prozora na radnoj površini.
Jedna stvar na koju treba obratiti pažnju: programsko podešavanje PdfView.PageNumber unutar rukovaoca sinhronizacije će samo po sebi pokrenuti događaj promene na tom prikazu. Zaštitite se od beskonačne rekurzije pomoću logičke zastavice koju postavljate pre dodeljivanja vrednosti i čistite odmah nakon toga. Zastavica se postavlja na nivou forme, a ne pojedinačnog prikaza, jer sva tri prikaza dele isti rukovalac.
Zumiranje po panelu
Svaki TPdfView ima sopstveno svojstvo Zoom, tipa Double u procentima gde je 1.0 ekvivalentno 100%. Podešavanje ove vrednosti poništava aktivni režim prilagođavanja (FitMode). Za dugme za prilagođavanje širini na aktivnom panelu, pročitajte zum iz PdfView.PageWidthZoom[PdfView.PageNumber] i dodelite ga. Za prilagođavanje celoj stranici koristite PageZoom[PageNumber]. Oba su svojstva niza indeksirana brojem stranice zasnovanim na 1, tako da se zaštitite od nultog broja stranice pre nego što im pristupite.
Kada izvozite trenutnu stranicu kao sliku, pročitajte rotaciju iz prikaza, ali pozovite RenderPage na komponenti TPdf, a ne na prikazu. Verzija metode TPdf.RenderPage koja radi sa bitmapama prima eksplicitne dimenzije u pikselima, vrednost rotacije TRotation i skup opcija rendersovanja TRenderOptions. Varijanta funkcije vraća instancu klase TBitmap u vlasništvu pozivaoca, koju morate sami osloboditi nakon čuvanja:
procedure TFormMain.SaveActiveViewAsImage;
var
Pdf: TPdf;
Bmp: TBitmap;
Jpeg: TJpegImage;
begin
if not Assigned(FActivePdfView) or not FActivePdfView.Active then
Exit;
Pdf := FActivePdfView.Pdf;
Pdf.PageNumber := FActivePdfView.PageNumber;
Bmp := Pdf.RenderPage(
0, 0,
Round(Pdf.PageWidth * 2),
Round(Pdf.PageHeight * 2),
FActivePdfView.Rotation, [], clWhite);
try
if SavePictureDialog.Execute then
begin
Jpeg := TJpegImage.Create;
try
Jpeg.Assign(Bmp);
Jpeg.CompressionQuality := 90;
Jpeg.SaveToFile(SavePictureDialog.FileName);
finally
Jpeg.Free;
end;
end;
finally
Bmp.Free;
end;
end;
Množenje širine i visine sa 2 daje oštriji izlaz za dokumente sa sitnim tekstom. Blok try/finally oko oslobađanja bitmape je obavezan; otkazivanje dijaloga TSaveDialog i dalje prolazi kroz finally blok, a vi želite da bitmapa bude oslobođena bez obzira na akciju korisnika.
Zahtevi za DLL datotekama
PDFium VCL obavija izvornu pdfium biblioteku. Za 32-bitni proces potreban je pdfium32.dll, dok je za 64-bitni potreban pdfium64.dll. Varijante sa V8 JavaScript motorom imaju sufiks v8 i zauzimaju oko 23-27 MB u poređenju sa standardnim verzijama od 5-6 MB. Za uporedni čitač koji onemogućava popunjavanje obrazaca (Pdf.FormFill := False), standardna verzija bez V8 podrške je dovoljna i smanjuje veličinu distribucije.
Postavite DLL u isti direktorijum gde se nalazi izvršna datoteka ili u bilo koji direktorijum koji je uključen u sistemsku putanju PATH. Komponenta ga učitava na zahtev kada se prvi TPdf aktivira, tako da se nedostatak DLL datoteke primećuje u tom trenutku, a ne pri pokretanju aplikacije. Ako isporučujete instalacioni paket, najsigurniji pristup je kopiranje DLL-a u instalacioni folder aplikacije umesto oslanjanja na sistemski direktorijum koji administrator kasnije može da obriše.
Verzije sa V8 podrškom su prvenstveno korisne kada je potrebno ostvariti interakciju sa JavaScript akcijama u PDF-u, na primer za pokretanje polja za proračun ili rukovalaca za slanje obrazaca. Pasivni uporedni čitač nema razloga da izvršava JavaScript; postavljanje Pdf.FormFill := False pre nego što Active := True u potpunosti preskače okruženje za popunjavanje obrazaca, što takođe znači da se JS motor ne pokreće čak i ako se koristi standardna verzija. To je ispravna podrazumevana postavka za čitač koji je namenjen samo za čitanje, bez obzira na to koju DLL varijantu isporučujete.
Za više detalja o PDFium VCL komponenti i njenom kompletnom API-ju posetite stranicu proizvoda Delphi PDFium VCL Component.