pdfviewer — u_pbt_pdfviewer #
← Component reference · Guide contents
Built-in PDF viewer: displays a local document or one published on the web, straight inside your window, with pagination, zoom and printing.
▶ See it live — Demo application, PDF viewer tile: the preview, the code behind it and this page, side by side.
At a glance #
| Userobject | u_pbt_pdfviewer |
| Item class | — (component without items) |
| Used for | Displaying an invoice, a purchase order, a contract or a manual without launching an external application |
| Opt-in options | — |
The component replaces the classic "save the PDF to a temporary file, then call ShellExecute": the document stays inside your application, and the user never leaves the current screen.
Quick start #
// window open event : display a document stored on disk
uo_pdf.is_source = "C:\factures\FA-2026-0142.pdf"
// ue_load_completed event of uo_pdf : (string as_source)
uo_status.of_panel(/*key*/ "main").is_text = "Document displayed"
That is all: setting is_source is enough to load and display the document.
Properties #
| Property | Type | Default | Purpose |
|---|---|---|---|
is_source | string | "" | Document to display: a file path (absolute, relative to the application or on the network; a # is part of the name), a file:/// address, a web address https://… served as application/pdf, or a data:application/pdf address. Setting the value triggers the load; setting "" clears the viewer. Anything else is refused and reported by ue_load_failed — http:// included. Reads back as you wrote it |
ii_page | integer | 0 | Page displayed, counted from 1 (0 = the document's first page). A page set before is_source applies to that document; otherwise a new document opens at its first page. Every change reloads the document and raises ue_load_completed again: the reader only reads its page when a document loads. Write only: reading it back gives the last page you asked for, not the one on screen. The reader is the one built into the web engine, and it reports nothing. |
ii_zoom | integer | 0 | Zoom in percent (0 = left to the viewer). Setting a zoom cancels is_fit, which contradicts it. Write only, like ii_page: if the user zooms with the reader's own toolbar, this property does not follow. |
is_fit | string | "" | Fit mode: FIT_PAGE, FIT_WIDTH, FIT_HEIGHT, or "" for none. Cancels ii_zoom |
ib_viewer_toolbar | boolean | true | Shows the viewer's own toolbar (page number, zoom, print, download). Hide it when your window carries those commands itself |
ib_allow_save | boolean | true | Offers the Save and Save as commands of the reader's toolbar and of its menu. At false, the document is shown without offering to save a copy. It is not a protection: the file stays readable on the disk. Every change reloads the document on screen |
ib_allow_print | boolean | true | Offers the Print command of the reader's toolbar and of its menu. of_print still prints: your application decides. Every change reloads the document on screen |
is_theme_style | string | "" | Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change |
is_theme_mode | string | "" | Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change |
il_theme_accent | long | -1 | Accent colour of this component (-1 = the application accent, or the theme's) |
Methods #
| Method | Purpose |
|---|---|
of_refresh ( ) | Reads the current document again (from disk or the network) without touching the settings: the way to show a file regenerated at the same path. The scrolling position is not kept: the reader starts again at ii_page. After a failure, tries the same document again. A refused document is judged again: ue_load_failed is raised again. Returns 0 once asked, -4 without a document (is_source empty), -2 if the component is not created |
of_print ( ) · of_print (boolean) | Opens the print preview of the document — not of the page that frames it. Returns 0 once the preview is asked for, -4 when no document is on screen, -2 when the component is not created. The argument has no effect here: it is always the PDF reader's preview |
of_print_to_pdf (string) | Returns -4 on this component, without writing anything: the printed page would only be the reader's frame, never the document. The document already is a PDF: copy the file of is_source |
of_reset ( ) | Clears the viewer and resets every property to its default. Returns 0 once applied, -2 when the component is not created |
of_set_redraw (boolean) | Groups a burst of changes into a single render. Returns 0 once applied, -2 when the component is not created |
of_save_as_png (string) · of_save_as_jpg (string) | Exports the rendering as an image. Returns 0 once the image is written, -4 when writing fails, -2 when the component is not created |
Events #
| Event | Raised when |
|---|---|
ue_load_completed (string as_source) | The document is on screen; as_source is is_source as you wrote it. Also raised by of_refresh and by every change of page, zoom, fit or viewer toolbar. Never raised on a failure |
ue_load_failed (string as_source, string as_reason) | The document could not be shown; as_reason is one of the REASON_* constants below. The viewer stays empty |
ue_link_clicked (string as_url) | The user followed a link in the document. The viewer stays on the document: open as_url wherever you want (the system browser, a webbrowser…). as_url is the link's address as is (https://…, mailto:…); a link to a local file — relative to the document included — arrives as a disk path |
ue_ready ( ) | The component has finished loading; everything sent beforehand has been replayed |
ue_runtime_missing ( ) | The WebView2 runtime is missing: the component stays empty |
ue_bg_color (long al_color) | The component has computed its theme background color; the userobject has already adopted it (backcolor) |
Why a document is not shown #
as_reason of ue_load_failed is one of these u_pbt_pdfviewer constants. A PDF is recognised this way: a local file has the .pdf extension and starts with the %PDF- signature; a remote document is served with the application/pdf type (the only one the engine hands to its reader); a data: address announces application/pdf.
| Constant | Value | Cause |
|---|---|---|
REASON_NOT_FOUND | "notfound" | Missing or unreadable file, address answering 404 |
REASON_NOT_PDF | "notpdf" | Not a PDF: local file without the %PDF- signature, remote answer that is not application/pdf, data: of another type |
REASON_TOO_LARGE | "toolarge" | File too large for this process (beyond 64 MB in 32-bit, 512 MB in 64-bit), or a data: address of more than 2 MB of characters (about 1.5 MB of PDF) |
REASON_INSECURE | "insecure" | http://: not supported, serve the document over https:// |
REASON_UNSUPPORTED | "unsupported" | Another kind of address (ftp:, blob:…) |
REASON_NETWORK | "network" | Server unreachable, unknown name, connection cut |
REASON_CERTIFICATE | "certificate" | The site's certificate is invalid, expired or revoked |
REASON_AUTH | "auth" | The site or the proxy asks for authentication |
REASON_HTTP | "http" | Another server error (403, 500…) |
REASON_REFUSED | "refused" | The site refuses to be shown in a frame, or sends the PDF as a download — the file is not downloaded for all that |
REASON_FAILED | "failed" | Any other cause |
What the user can do, without a single line of code #
The viewer displays its built-in toolbar above the document. There is nothing for you to program: it is provided and localized by the system.
| Action | How |
|---|---|
| Pagination | Mouse wheel and scroll bar, or type the page number directly in the n / total counter |
| Zoom | + / − buttons, fit to page or fit to width |
| Search | The search button of the toolbar, in the text of the document |
| Printing | The printer button of the toolbar (can be hidden with ib_allow_print), or of_print from your code |
| Saving | The download button, to save a copy of the document (can be hidden with ib_allow_save) |
| Rotation | Page rotation from the toolbar menu |
| Keyboard | As soon as the component has the focus (Tab or of_focus_webview): PageDown, the arrows, Home / End scroll the document, without a click first |
The browser's shortcuts — Ctrl+F, Ctrl+P, Ctrl + wheel — are switched off in every component, this one included: use the buttons of the reader's toolbar.
What the reader does not say #
The reader is the one built into the web engine: nothing to install, printing, search, PDF forms and full screen included. In return, it reports nothing to your application: not the page on screen, not the number of pages, not the real zoom, not the selected text, and search cannot be driven from code. ii_page and ii_zoom say where to open the document, not where the user is. This is a deliberate choice for 4.0; a scriptable rendering would need an external library.
Examples #
Opening a local document #
// Absolute path, or relative to the application directory
uo_pdf.is_source = "doc\conditions-generales.pdf"
Opening a document published on the web #
// A web address loads exactly like a local file
uo_pdf.is_source = "https://www.monsite.fr/tarifs/catalogue-2026.pdf"
An internet connection is of course required; the load is asynchronous, and ue_load_completed tells you when it is done.
Displaying the PDF a DataWindow has just produced #
// Local variables
string ls_file
// One file per day, in the temporary folder
ls_file = "C:\temp\report_" + String(Today(), "yyyymmdd") + ".pdf"
// The DataWindow produces the file...
dw_report.SaveAs(ls_file, PDF!, false)
// ...and the viewer displays it immediately
uo_pdf.is_source = ls_file
Refreshing after the file has been regenerated #
// The file was rewritten in the same location : reload without touching is_source
uo_pdf.of_refresh()
Chaining several documents in the same viewer #
// ue_row_changed event of dw_list : display the attachment of the current row
string ls_pdf
// The path of the PDF of the current row
ls_pdf = dw_list.GetItemString(dw_list.GetRow(), "pdf_path")
// No attachment empties the viewer ; otherwise it shows it
if ls_pdf = "" then
uo_pdf.of_reset() // no attachment : empty viewer
else
uo_pdf.is_source = ls_pdf
end if
Tracking the end of the load #
// ue_load_completed event of uo_pdf : (string as_source)
uo_wait.Hide()
// of_print prints the document on screen
uo_print_button.ib_enabled = true
Saying why the document is not there #
// ue_load_failed event of uo_pdf : (string as_source, string as_reason)
uo_wait.Hide()
choose case as_reason
case uo_pdf.REASON_NOT_FOUND
uo_status.of_panel(/*key*/ "main").is_text = "Document not found: " + as_source
case uo_pdf.REASON_NOT_PDF
uo_status.of_panel(/*key*/ "main").is_text = "This file is not a PDF"
case else
uo_status.of_panel(/*key*/ "main").is_text = "Document unavailable (" + as_reason + ")"
end choose
Opening a link of the document elsewhere #
// ue_link_clicked event of uo_pdf : (string as_url)
// The viewer stays on the document : the link opens in the window's browser
uo_web.is_address = as_url
Printing the document #
// clicked of the Print button : the PDF reader's preview, on the document itself
if uo_pdf.of_print() = -4 then
uo_status.of_panel(/*key*/ "main").is_text = "No document to print"
end if
Showing without letting save or print #
// A confidential document : neither Save nor Print in the reader's bar
uo_pdf.ib_allow_save = false
uo_pdf.ib_allow_print = false
uo_pdf.is_source = is_current_document
Set them before is_source: every change reloads the document. It is not a protection: the file stays readable on the disk, and of_print still prints.
Preview in a tab, next to data entry #
// open event : the viewer takes one tab page, data entry the other
uo_tab.of_add_page(/*key*/ "entry", /*title*/ "Entry", /*page*/ uo_page_entry)
uo_tab.of_add_page(/*key*/ "preview", /*title*/ "Preview", /*page*/ uo_page_preview)
// The viewer sits inside uo_page_preview like any other control
uo_pdf.is_source = is_current_document
The component is hosted with no special precautions inside a tab or a dockcontainer panel.
Checking the file before displaying it #
// Local variables
string ls_path
// The file of the invoice on screen
ls_path = "C:\factures\" + is_number + ".pdf"
// No file, nothing to show : clear the viewer rather than leave the previous document
if not FileExists(ls_path) then
uo_pdf.of_reset()
uo_status.of_panel(/*key*/ "main").is_text = "Invoice not found"
return
end if
// Otherwise, the invoice is shown
uo_pdf.is_source = ls_path
Accepted formats and paths #
Form of is_source | Example | Note |
|---|---|---|
| Absolute path | "C:\docs\contrat.pdf" | The most reliable |
| Relative path | "doc\notice.pdf" | Relative to the application directory |
| Network path | "\\serveur\partage\bon.pdf" | The user must have read permissions |
Name with # | "C:\devis\Devis #12.pdf" | The # is part of the file name |
file: address | "file:///C:/docs/contrat.pdf" | Converted to a path, like an absolute path; file://localhost/C:/… and the four-slash UNC form file:////server/share/… too |
| Web address | "https://…/catalogue.pdf" | Served as application/pdf, asynchronous load. A #page=… written in the address is ignored: use ii_page |
| In-memory document | "data:application/pdf;base64,…" | Nothing is written to disk. Beyond 2 MB of characters (about 1.5 MB of PDF), ue_load_failed with REASON_TOO_LARGE: write the file and give its path |
http:// address | "http://intranet/bon.pdf" | Not supported: ue_load_failed with REASON_INSECURE. Serve the document over https:// |
| Empty | "" | Clears the viewer |
This component only supports PDF: anything else is refused and reported by ue_load_failed (REASON_NOT_PDF). For an image, use picture; for an HTML page, webbrowser.
Best practices #
- Watch
ue_load_failed: an invalid path, a file that is not a PDF or an unreachable site is reported there with its reason, and the viewer stays empty. - Call
of_reset()when no document should be displayed any more (moving to a row without an attachment): otherwise the previous document stays visible. of_refresh()is the way to show a file regenerated at the same path: it reads the file again without touching the settings. It does not keep the scrolling position — the reader starts again atii_page.- Every change of
ii_page,ii_zoom,is_fitorib_viewer_toolbarreloads the document (the reader only reads its settings when a document loads) and raisesue_load_completedagain: set them beforeis_sourcefor a single load. - Provide a waiting indicator for remote or large documents, and hide it on
ue_load_completedand onue_load_failed. - Give the component a comfortable area (at least half the window): the built-in toolbar and the document both need room to stay readable.
- To display a web page rather than a PDF, use webbrowser; for an image, picture.
Inherited from the common base #
These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.
| Members | Role | Detailed in |
|---|---|---|
of_reset | Put the component back to zero | 3.6 Resetting a component: of_reset() |
of_register_shortcut · of_clear_shortcuts | The component's keyboard chords | 3.5 Keyboard shortcuts |
of_is_created · of_is_ready · of_get_last_error | Whether it was born, whether it is ready, what failed | 3.7 Diagnostics |
of_save_as_png · of_save_as_jpg | Export the rendering as an image | 3.8 Exporting the rendering as an image |
of_set_redraw | Group changes into a single repaint | 3.10 Best practices |
of_preload_icons | Icons shown with no delay | Instant display: of_icon |
of_set_translation | Translate one of the component's labels | 5.2 Adapting a label: of_set_translation |
of_focus_webview | Give the component the focus | 6.4 Keyboard and focus |
of_print · of_print_to_pdf | Print, or write a PDF | 6.9 Printing |
of_set_property · of_get_property · of_component_name | Driving a property by its name | 3.1 The property engine |
Two helpers are not inherited: of_icon and of_escape_markup live on n_pbt_utils. Declare one — n_pbt_utils lnv_utils, nothing to create — and call them on it.