PBToolboxAI v5 ← Site

pdfviewer — u_pbt_pdfviewer #

← Référence des composants · Sommaire du guide

Visionneuse PDF intégrée : affiche un document local ou publié sur le web, directement dans votre fenêtre, avec pagination, zoom et impression.

▶ Le voir en vrai — Application de démonstration, tuile PDF viewer : l'aperçu, le code qui le produit et cette page, côte à côte.


En bref #

Userobjectu_pbt_pdfviewer
Classe d'items— (composant sans items)
Sert àAfficher une facture, un bon de commande, un contrat ou une notice sans lancer d'application externe
Options opt-in—

Le composant remplace le classique « enregistrer le PDF dans un fichier temporaire puis appeler ShellExecute » : le document reste dans votre application, l'utilisateur ne quitte jamais l'écran en cours.


Démarrage rapide #

// event open de la fenetre : afficher un document present sur le disque
uo_pdf.is_source = "C:\factures\FA-2026-0142.pdf"
// event ue_load_completed de uo_pdf : (string as_source)
uo_status.of_panel(/*key*/ "main").is_text = "Document affiche"

C'est tout : poser is_source suffit à charger et afficher le document.


Propriétés #

PropriétéTypeDéfautRôle
is_sourcestring""Document à afficher : un chemin de fichier (absolu, relatif à l'application ou réseau ; un # fait partie du nom), une adresse file:///, une adresse web https://… servie en application/pdf, ou une adresse data:application/pdf. Poser la valeur déclenche le chargement ; poser "" (ou des espaces seuls) vide la visionneuse en gardant ses réglages. Tout le reste est refusé et signalé par ue_load_failed — http:// compris, et une adresse qui porte un nom d'utilisateur et un mot de passe (https://nom:secret@…). Un PDF tenu dans un blob s'affiche par of_load_blob. Se relit tel que vous l'avez écrit
ii_pageinteger0Page d'ouverture, comptée à partir de 1 (0 = la première page du document). Posée pendant qu'un document est affiché, c'est sa page : il se recharge, ouvert dessus. Posée quand la visionneuse est vide, elle vaut pour le document suivant ; sinon un nouveau document s'ouvre à sa première page. Pour ouvrir un document sur une page, posez is_source puis ii_page : un seul chargement. Chaque changement recharge le document et relève ue_load_completed : le lecteur ne lit sa page qu'au chargement ; la même valeur reposée ne fait rien. En écriture seule : la relire donne la dernière page demandée, pas celle affichée. Le lecteur est celui du moteur web, il ne rend compte de rien.
ii_zoominteger0Zoom en pourcentage, de 25 à 500 — la plage des boutons du lecteur (0 = laissé au lecteur). Une valeur hors de cette plage y est ramenée, et se relit telle qu'appliquée. Poser un zoom annule is_fit, qui le contredit. En écriture seule, comme ii_page : si l'utilisateur zoome avec la barre du lecteur, cette propriété ne suit pas.
is_fitstring""Ajustement : FIT_PAGE, FIT_WIDTH, FIT_HEIGHT, ou "" pour aucun. Annule ii_zoom
ib_viewer_toolbarbooleantrueAffiche la barre du lecteur (sommaire, numéro de page, zoom, rotation, recherche, impression, enregistrement). Masquez-la quand votre fenêtre porte elle-même ces commandes. Le lecteur intégré à WebView2 n'a pas de commande Plein écran
is_destinationstring""Ouvre le document sur une destination nommée du PDF — la cible d'un signet, écrite par l'outil qui a produit le fichier. "" pour aucune ; un nom que le document n'a pas l'ouvre à sa première page. Gardée pour les documents suivants tant que vous ne la changez pas. Chaque changement recharge le document affiché
ib_allow_savebooleantrueOffre les commandes Enregistrer et Enregistrer sous de la barre du lecteur et de son menu. À false, le document est montré sans proposer d'en sauver une copie. Chaque visionneuse garde son réglage : celui d'une autre fenêtre n'y change rien. Ce n'est pas une protection : le fichier reste lisible sur le disque. Chaque changement recharge le document affiché ; posé avant is_source, le document ne se charge qu'une fois
ib_allow_printbooleantrueOffre la commande Imprimer de la barre du lecteur et de son menu. of_print imprime toujours : c'est votre application qui décide. Chaque visionneuse garde son réglage. Chaque changement recharge le document affiché ; posé avant is_source, le document ne se charge qu'une fois
ib_allow_searchbooleantrueOffre la commande Rechercher de la barre du lecteur. La recherche appartient à l'utilisateur (aussi par Ctrl+F) : le lecteur n'offre aucune recherche pilotée par votre application. Chaque visionneuse garde son réglage. Chaque changement recharge le document affiché ; posé avant is_source, le document ne se charge qu'une fois
ib_allow_rotatebooleantrueOffre la commande Faire pivoter de la barre du lecteur. Chaque visionneuse garde son réglage. Chaque changement recharge le document affiché ; posé avant is_source, le document ne se charge qu'une fois
ib_allow_navigation_panebooleantrueOffre le bouton Sommaire de la barre du lecteur, en haut à gauche : il ouvre le panneau latéral avec les signets et les vignettes des pages. À false, le bouton disparaît. Que le panneau soit ouvert est l'affaire du lecteur et de l'utilisateur : votre application offre le bouton ou non. Chaque visionneuse garde son réglage. Chaque changement recharge le document affiché ; posé avant is_source, le document ne se charge qu'une fois
is_theme_stylestring""Style visuel de la surface propre au composant : ce que la visionneuse montre quand elle ne tient aucun document (avant le premier, après is_source = "" ou un document refusé). Le lecteur PDF garde son allure : il suit le thème de l'application (PBT_SetDefaultTheme), en clair ou sombre seulement, car WebView2 donne à tous ses lecteurs PDF un même jeu de couleurs. Vide = le style de l'application, suivi à chaque changement
is_theme_modestring""Variante claire ou sombre de la surface propre au composant, visible quand la visionneuse ne tient aucun document. Le lecteur PDF ne la suit pas : sa barre et ses marges prennent le clair ou le sombre du thème de l'application (PBT_SetDefaultTheme). Vide = celle de l'application, suivie à chaque changement
il_theme_accentlong-1Couleur d'accent de ce composant (-1 = l'accent de l'application, ou celui du thème). Sans effet visible ici : ni le lecteur PDF ni la visionneuse vide ne dessinent avec un accent. La valeur est gardée et se relit telle que posée

Méthodes #

MéthodeRôle
of_refresh ( )Relit le document courant (sur le disque ou le réseau) sans toucher aux réglages : le moyen d'afficher un fichier régénéré au même chemin. La position de défilement n'est pas gardée : le lecteur repart à ii_page. Après un échec, retente le même document. Un document refusé est jugé de nouveau : ue_load_failed est relevé. Renvoie 0 une fois demandé, -4 sans document (is_source vide), -2 si le composant n'est pas créé
of_load_blob (blob ablb_pdf) · of_load_blob (blob ablb_pdf, string as_name)Affiche un PDF tenu dans un blob — lu en base (SELECTBLOB) ou reçu d'un service — sans écrire de fichier, quelle que soit sa taille : les octets restent en mémoire et ne sont servis qu'à cette visionneuse. Le second argument est le nom que relisent is_source et ue_load_completed / ue_load_failed (document.pdf sans lui). Le blob affiché avant est libéré, celui-ci l'est par le document suivant ou of_reset. Renvoie 0 une fois demandé (ue_load_completed suit), -5 si le blob est vide ou n'est pas un PDF, -4 s'il est trop gros pour ce processus (64 Mo en 32 bits, 512 Mo en 64 bits) — is_last_error dit pourquoi —, -2 si le composant n'est pas créé
of_print ( ) · of_print (boolean)Ouvre l'aperçu d'impression du document — pas de la page qui l'encadre. Renvoie 0 une fois l'aperçu demandé, -4 quand aucun document n'est affiché, -2 si le composant n'est pas créé. L'argument est sans effet ici : c'est toujours l'aperçu du lecteur PDF
of_print_to_pdf (string) · of_print_to_pdf (string, boolean)Rend -4 sur ce composant, sans rien écrire : la page imprimée ne serait que le cadre du lecteur, jamais le document. Le document est déjà un PDF : copiez le fichier de is_source
of_reset ( )Vide la visionneuse et remet toutes les propriétés à leur défaut. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_set_redraw (boolean)Regroupe une rafale de modifications en un seul rendu. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_save_as_png (string) · of_save_as_jpg (string)Exporte le rendu en image. Renvoie 0 une fois l'image écrite, -4 si l'écriture échoue, -2 si le composant n'est pas créé

Événements #

ÉvénementDéclenché quand
ue_load_completed (string as_source)Le document est affiché ; as_source est is_source tel que vous l'avez écrit (pour un blob, le nom donné à of_load_blob). Relevé aussi par of_refresh et par chaque changement de page, de zoom, d'ajustement, de barre du lecteur, de destination ou d'une commande ib_allow_* — posez-les avant is_source pour un seul chargement ; la même valeur reposée ne le relève pas. Jamais levé sur un échec
ue_load_failed (string as_source, string as_reason)Le document n'a pas pu être affiché ; as_reason est l'une des constantes REASON_* ci-dessous. La visionneuse reste vide
ue_link_clicked (string as_url)L'utilisateur a suivi un lien du document. La visionneuse reste sur le document : ouvrez as_url où vous voulez (navigateur du poste, webbrowser…). as_url est l'adresse du lien telle quelle (https://…, mailto:…) ; un lien relatif d'un document local arrive en chemin disque. Un lien vers un fichier local du poste (file:///) dans un PDF n'est pas suivi : le lecteur de PDF de WebView2 le bloque ; aucun ue_link_clicked n'est levé
ue_ready ( )Le composant a fini de charger ; tout ce qui a été envoyé avant a été rejoué
ue_runtime_missing ( )Le runtime WebView2 est absent : le composant reste vide
ue_bg_color (long al_color)Le composant a calculé sa couleur de fond de thème ; l'userobject l'a déjà adoptée (backcolor)

Pourquoi un document n'est pas affiché #

as_reason de ue_load_failed est l'une de ces constantes de u_pbt_pdfviewer. Un PDF se reconnaît ainsi : un fichier local porte l'extension .pdf et commence par la signature %PDF- ; un document distant est servi avec le type application/pdf (le seul que le moteur remet à son lecteur) ; une adresse data: annonce application/pdf.

ConstanteValeurCause
REASON_NOT_FOUND"notfound"Fichier absent ou illisible, adresse qui répond 404
REASON_NOT_PDF"notpdf"Ce n'est pas un PDF : fichier local sans la signature %PDF-, réponse distante qui n'est pas application/pdf (un serveur de fichiers qui répond application/octet-stream : téléchargez le document d'abord, voir les exemples), data: ou blob d'un autre type
REASON_TOO_LARGE"toolarge"Fichier trop gros pour ce processus (au-delà de 64 Mo en 32 bits, 512 Mo en 64 bits), ou adresse data: de plus de 2 Mo de caractères (environ 1,5 Mo de PDF)
REASON_INSECURE"insecure"http:// : non pris en charge, servez le document en https://
REASON_UNSUPPORTED"unsupported"Une autre sorte d'adresse (ftp:, blob:…), ou une adresse qui porte un nom d'utilisateur et un mot de passe (https://nom:secret@…)
REASON_NETWORK"network"Serveur injoignable, nom inconnu, connexion coupée
REASON_CERTIFICATE"certificate"Certificat du site invalide, expiré ou révoqué
REASON_AUTH"auth"Le site ou le proxy demande une authentification : téléchargez le document par le restclient (jeton, identifiants), puis affichez-le (voir les exemples)
REASON_HTTP"http"Une autre erreur du serveur (403, 500…)
REASON_REFUSED"refused"Le site refuse d'être affiché dans un cadre, ou envoie le PDF en téléchargement — le fichier n'est pas téléchargé pour autant
REASON_FAILED"failed"Toute autre cause

Ce que l'utilisateur peut faire, sans une ligne de code #

La visionneuse affiche sa barre d'outils intégrée au-dessus du document. Vous n'avez rien à programmer : elle est fournie et localisée par le système.

ActionComment
PaginationMolette et barre de défilement, ou saisie directe du numéro de page dans le compteur n / total
ZoomBoutons + / −, ajustement à la page ou à la largeur
RechercheBouton de recherche de la barre d'outils, dans le texte du document
ImpressionBouton imprimante de la barre d'outils (masquable par ib_allow_print), ou of_print depuis votre code
EnregistrementBouton de téléchargement, pour sauver une copie du document (masquable par ib_allow_save)
RotationRotation des pages depuis le menu de la barre d'outils
ClavierDès que le composant a le focus (Tab ou of_focus_webview) : PageDown, flèches, Début / Fin font défiler le document, sans clic préalable

Les raccourcis du navigateur — Ctrl+F, Ctrl+P, Ctrl + molette — sont coupés dans tous les composants, celui-ci compris : passez par les boutons de la barre du lecteur.

Ce que le lecteur ne dit pas #

Le lecteur est celui qui est intégré au moteur web : aucune dépendance à installer, l'impression, la recherche et les formulaires PDF fournis. En contrepartie, il ne rend compte de rien à votre application : ni la page affichée, ni le nombre de pages, ni le zoom réel, ni le texte sélectionné, et la recherche ne se pilote pas par code : le lecteur ignore les paramètres d'ouverture qui surligneraient un texte ou ouvriraient son panneau latéral. Il n'a pas de commande Plein écran, et il suit le thème clair ou sombre de l'application, jamais celui du composant. ii_page et ii_zoom disent où ouvrir le document, pas où l'utilisateur se trouve. Un PDF protégé par un mot de passe : le lecteur le demande lui-même à l'utilisateur, votre application ne peut pas le lui fournir. Ce choix est délibéré ; un rendu scriptable demanderait une bibliothèque externe.


Exemples #

Ouvrir un document local #

// Chemin absolu, ou relatif au repertoire de l'application
uo_pdf.is_source = "doc\conditions-generales.pdf"

Ouvrir un document publié sur le web #

// Une adresse web se charge exactement comme un fichier local
uo_pdf.is_source = "https://www.monsite.fr/tarifs/catalogue-2026.pdf"

Une connexion internet est évidemment nécessaire ; le chargement est asynchrone, ue_load_completed vous signale la fin.

Afficher le PDF que vient de produire une DataWindow #

// Local variables
string ls_file

// Un fichier par jour, dans le dossier temporaire
ls_file = "C:\temp\report_" + String(Today(), "yyyymmdd") + ".pdf"

// La DataWindow produit le fichier...
dw_report.SaveAs(ls_file, PDF!, false)

// ...et la visionneuse l'affiche immediatement
uo_pdf.is_source = ls_file

Rafraîchir après régénération du fichier #

// Le fichier a ete reecrit au meme emplacement : recharger sans retoucher is_source
uo_pdf.of_refresh()

Enchaîner plusieurs documents dans la même visionneuse #

// event rowfocuschanged de dw_list : (long currentrow)
// Local variables
string ls_pdf

// Le chemin du PDF de la ligne courante
ls_pdf = dw_list.GetItemString(currentrow, "pdf_path")

// Sans piece, la visionneuse se vide (ses reglages gardes) ; sinon elle l'affiche
if ls_pdf = "" then
	uo_pdf.is_source = ""
else
	uo_pdf.is_source = ls_pdf
end if

Suivre la fin du chargement #

// event ue_load_completed de uo_pdf : (string as_source)
uo_wait.Hide()

// of_print imprime le document affiche
uo_print_button.ib_enabled = true

Dire pourquoi le document n'est pas là #

// event ue_load_failed de 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 introuvable : " + as_source
	case uo_pdf.REASON_NOT_PDF
		uo_status.of_panel(/*key*/ "main").is_text = "Ce fichier n'est pas un PDF"
	case else
		uo_status.of_panel(/*key*/ "main").is_text = "Document indisponible (" + as_reason + ")"
end choose

Ouvrir ailleurs un lien du document #

// event ue_link_clicked de uo_pdf : (string as_url)
// La visionneuse reste sur le document : le lien s'ouvre dans le navigateur de la fenetre
uo_web.is_address = as_url

Imprimer le document #

// clicked du bouton Imprimer : l'apercu du lecteur PDF, sur le document lui-meme
if uo_pdf.of_print() = -4 then
	uo_status.of_panel(/*key*/ "main").is_text = "Aucun document a imprimer"
end if

Montrer sans laisser enregistrer ni imprimer #

// Un document confidentiel : ni Enregistrer ni Imprimer dans la barre du lecteur
uo_pdf.ib_allow_save = false
uo_pdf.ib_allow_print = false
uo_pdf.is_source = is_current_document

Posez-les avant is_source : le document ne se charge qu'une fois. Chaque visionneuse garde son réglage. Ce n'est pas une protection : le fichier reste lisible sur le disque, et of_print imprime toujours.

Aperçu dans un onglet, à côté de la saisie #

// event open : la visionneuse occupe une page d'onglet, la saisie l'autre
uo_tab.of_add_page(/*key*/ "entry",  /*title*/ "Saisie",   /*page*/ uo_page_entry)
uo_tab.of_add_page(/*key*/ "preview",  /*title*/ "Apercu",   /*page*/ uo_page_preview)

// La visionneuse est posee dans uo_page_preview comme n'importe quel controle
uo_pdf.is_source = is_current_document

Le composant s'héberge sans précaution particulière dans un tab ou un panneau dockcontainer.

Vérifier le fichier avant de l'afficher #

// Local variables
string ls_path

// Le fichier de la facture affichee
ls_path = "C:\factures\" + is_number + ".pdf"

// Pas de fichier, rien a montrer : on vide la visionneuse plutot que de laisser l'ancien document
if not FileExists(ls_path) then
    uo_pdf.is_source = ""
    uo_status.of_panel(/*key*/ "main").is_text = "Facture introuvable"
    return
end if

// Sinon, la facture s'affiche
uo_pdf.is_source = ls_path

Afficher un PDF lu en base (blob) #

// Local variables
blob lblb_pdf

// La facture rangee en base, lue dans un blob
SELECTBLOB pdf_file INTO :lblb_pdf FROM invoice WHERE invoice_no = :is_number USING SQLCA;

// Affichee directement depuis la memoire : aucun fichier temporaire, quelle que soit sa taille
if SQLCA.SQLCode = 0 then
	uo_pdf.of_load_blob(/*pdf*/ lblb_pdf, /*name*/ "invoice-" + is_number + ".pdf")
end if

Le nom donné revient dans is_source et dans ue_load_completed ; le blob est libéré par le document suivant ou par of_reset.

Ouvrir sur un chapitre #

// Ouvert sur le chapitre "prices" du catalogue ; le bouton Sommaire du lecteur liste les signets
uo_pdf.is_destination = "prices"
uo_pdf.is_source = "doc\catalogue-2026.pdf"

Le nom d'une destination est celui que l'outil qui a produit le PDF a écrit : votre générateur de documents le connaît.

Un document derrière un jeton, ou servi en octet-stream #

// Local variables
long ll_status
string ls_file

// Le restclient (inv_rest, prepare a l'ouverture de la fenetre) envoie le jeton et telecharge le fichier
ls_file = "C:\temp\invoice-4152.pdf"
ll_status = inv_rest.of_download(/*url*/ "/orders/4152/invoice.pdf", /*path*/ ls_file)

// Puis la visionneuse affiche le fichier, quel que soit le type annonce par le serveur
if ll_status = 200 then
	uo_pdf.is_source = ls_file
end if

Le lecteur du moteur ne sait ni envoyer un jeton ni afficher une réponse application/octet-stream (REASON_AUTH, REASON_NOT_PDF) : le restclient le fait pour lui.


Formats et chemins acceptés #

Forme de is_sourceExempleRemarque
Chemin absolu"C:\docs\contrat.pdf"Le plus fiable
Chemin relatif"doc\notice.pdf"Relatif au répertoire de l'application
Chemin réseau"\\serveur\partage\bon.pdf"L'utilisateur doit avoir les droits de lecture
Nom avec #"C:\devis\Devis #12.pdf"Le # fait partie du nom du fichier
Adresse file:"file:///C:/docs/contrat.pdf"Convertie en chemin, comme un chemin absolu ; file://localhost/C:/… et la forme UNC à quatre barres file:////serveur/partage/… aussi
Adresse web"https://…/catalogue.pdf"Servie en application/pdf, chargement asynchrone. Un #page=… écrit dans l'adresse est ignoré : utilisez ii_page. Une adresse qui porte des identifiants (https://nom:secret@…) est refusée (REASON_UNSUPPORTED) : passez par le restclient
Document en mémoire"data:application/pdf;base64,…"Rien n'est écrit sur le disque. Au-delà de 2 Mo de caractères (environ 1,5 Mo de PDF), ue_load_failed avec REASON_TOO_LARGE : pour un document en mémoire plus gros, of_load_blob
Adresse http://"http://intranet/bon.pdf"Non prise en charge : ue_load_failed avec REASON_INSECURE. Servez le document en https://
Vide""Vide la visionneuse et garde ses réglages ; une valeur faite d'espaces aussi

Seul le PDF est pris en charge par ce composant : ce qui n'en est pas un est refusé et signalé par ue_load_failed (REASON_NOT_PDF). Pour une image, utilisez picture ; pour une page HTML, webbrowser.


Bonnes pratiques #

Hérité du socle commun #

Ces membres existent sur tous les composants visuels — ils ne sont pas propres à celui-ci. Ils sont détaillés une seule fois, dans les chapitres transverses ; cette table dit seulement où les lire.

MembresRôleDétaillé dans
of_resetRemettre le composant à zéro3.6 Remettre un composant à zéro : of_reset()
of_register_shortcut · of_clear_shortcutsRaccourcis clavier du composant3.5 Les raccourcis clavier
ib_created · ib_ready · is_last_errorS'il est né, s'il est prêt, ce qui a échoué3.7 Diagnostic
of_save_as_png · of_save_as_jpgExporter le rendu en image3.8 Exporter le rendu en image
of_set_redrawGrouper les modifications en un seul repaint3.10 Bonnes pratiques
of_preload_iconsIcônes affichées sans délaiAffichage instantané : of_icon
of_set_translationTraduire un libellé du composant5.2 Adapter un libellé : of_set_translation
of_focus_webviewDonner le focus au composant6.4 Clavier et focus
of_print · of_print_to_pdfImprimer, ou écrire un PDF6.9 Imprimer
of_set_property · of_get_property · is_component_namePiloter une propriété par son nom3.1 Le moteur de propriétés
is_accessible_name · is_accessible_descriptionLe nom et la description que dit un lecteur d'écran3.4 Propriétés et events optionnels

Deux aides ne sont pas héritées : of_icon et of_escape_markup vivent sur n_pbt_utils. Déclarez-en une — n_pbt_utils lnv_utils, rien à créer — et appelez-les dessus.


← Référence des composants · Sommaire du guide