scheduler — u_pbt_scheduler #
← Référence des composants · Sommaire du guide
Un calendrier à la manière d'Outlook : vues jour, semaine de travail, semaine, mois et agenda, bande « journée entière », glisser-déposer pour déplacer et redimensionner, ressources côte à côte, catégories de couleur, et des cartes et des info-bulles écrites par modèles. Il se remplit rendez-vous par rendez-vous, ou d'un seul appel depuis un DataStore — et chaque geste de l'utilisateur vous rend la ligne à mettre à jour.
▶ Le voir en vrai — Application de démonstration, tuile Scheduler : l'aperçu, le code qui le produit et cette page, côte à côte.
En bref #
| Userobject | u_pbt_scheduler |
| Classes d'items | n_pbt_scheduler_appointment (un rendez-vous, of_appointment) · n_pbt_scheduler_resource (une ressource, of_resource) · n_pbt_scheduler_category (une catégorie, of_category) |
| Sert à | Planning d'une équipe, réservation de salles ou de machines, agenda d'un commercial, rendez-vous de patients — tout ce qui se pose sur des jours et des heures |
| Limite en mode démo | Les 12 premiers rendez-vous de la plage à l'écran, par heure de début ; les autres restent en mémoire sans être affichés — voir le mode démo |
Démarrage rapide #
// open event of the window : a few appointments of the week, in one repaint
uo_sched.of_set_redraw(/*on*/ false)
uo_sched.is_date = "2026-09-21"
// A colour category, then the appointments : a key, a subject, a start and an end
uo_sched.of_add_category(/*key*/ "customer", /*label*/ "Customer", /*color*/ RGB(216, 90, 48))
uo_sched.of_add_appointment(/*key*/ "a1", /*subject*/ "Weekly meeting", /*start*/ "2026-09-21 09:00", /*end*/ "2026-09-21 10:00")
uo_sched.of_appointment(/*key*/ "a1").is_location = "Room 3"
uo_sched.of_add_appointment(/*key*/ "a2", /*subject*/ "ACME visit", /*start*/ "2026-09-23 14:00", /*end*/ "2026-09-23 16:30")
uo_sched.of_appointment(/*key*/ "a2").is_category = "customer"
// Dates only : an all-day appointment, both days included
uo_sched.of_add_appointment(/*key*/ "a3", /*subject*/ "Trade fair", /*start*/ "2026-09-24", /*end*/ "2026-09-25")
uo_sched.of_appointment(/*key*/ "a3").ib_all_day = true
uo_sched.of_set_redraw(/*on*/ true)
// ue_appointment_opened event of uo_sched : (string as_key)
// A double-click, or Enter on the selected appointment : open YOUR editor
wf_edit_appointment(as_key)
Comprendre le calendrier #
Les vues #
is_view choisit la vue, is_date le jour autour duquel elle se construit : sa semaine, son mois. L'utilisateur change l'une et l'autre depuis la barre d'outils du composant (Aujourd'hui, précédent, suivant, menu des vues) — les deux propriétés se relisent en direct, et ue_view_changed / ue_date_changed le disent, que le changement vienne de l'utilisateur ou de votre code.
| Vue | Ce qu'elle montre |
|---|---|
VIEW_DAY | Un jour sur une grille horaire |
VIEW_WORK_WEEK | Les jours ouvrés de la semaine (is_work_days) — la vue par défaut |
VIEW_WEEK | Les sept jours, à partir de ii_first_day_of_week |
VIEW_MONTH | Six semaines ; un rendez-vous de plusieurs jours s'étire en barre sur ses jours |
VIEW_AGENDA | Une liste, jour par jour, sur ii_agenda_days jours |
Les dates #
Une date voyage en texte, "yyyy-mm-dd hh:mm" — dans les méthodes, les propriétés et les événements. C'est une heure locale flottante : ni fuseau horaire, ni heure d'été ; "2026-09-22 09:00" s'affiche à 09:00, sur tous les postes.
- La fin est exclusive. Un rendez-vous de 09:00 à 10:00 finit à 10:00 : le suivant, qui commence à 10:00, ne le chevauche pas. Sans fin, un rendez-vous dure 30 minutes.
- Une date sans heure inclut ses deux jours.
"2026-09-24"→"2026-09-25"avecib_all_day = true, c'est le 24 et le 25. Pour une journée entière, l'heure est ignorée : une colonne datetime de DataWindow, qui porte00:00:00, donne des jours, le dernier inclus. - Ce que le calendrier accepte aussi :
"2026-09-22T09:30", des secondes, et le texte d'une colonne datetime de DataWindow.of_add_appointmenta une surcharge qui prend deuxdatetime. - Ce que les événements rendent : les dates sous la forme où vous les avez écrites —
"yyyy-mm-dd hh:mm", fin exclusive, pour un rendez-vous horaire ; des dates seules, les deux jours inclus, pour une journée entière. C'est aussi ce queis_startetis_endrelisent sur le handle.
// Local variables
datetime ldt_start
// A "yyyy-mm-dd hh:mm" text back into a PowerBuilder datetime
ldt_start = DateTime(Date(Left(as_start, 10)), Time(Mid(as_start, 12)))
La bande « journée entière » #
Au-dessus de la grille horaire des vues jour et semaine, une bande reçoit les rendez-vous ib_all_day et ceux qui durent 24 heures ou plus : un séminaire de trois jours y tient en une barre au lieu d'écraser trois colonnes. ib_all_day_band = false la retire. Dans la vue mois, ces rendez-vous sont des barres qui traversent leurs jours ; les autres, une ligne écrite par is_month_template.
Les rendez-vous d'un DataStore #
of_from_datastore(ids) charge le calendrier d'un seul appel : une ligne = un rendez-vous, et sa clé est son numéro de ligne — c'est elle que chaque événement vous rend, prête pour SetItem. Une colonne joue un rôle quand elle en porte le nom, ou quand of_map le lui donne :
| Rôle | Noms reconnus sans of_map |
|---|---|
ROLE_SUBJECT | subject, title |
ROLE_START · ROLE_END | start, start_date, starts · end, end_date, ends |
ROLE_ALL_DAY · ROLE_READ_ONLY | all_day, allday · read_only, readonly |
ROLE_KEY · ROLE_LOCATION · ROLE_ORGANIZER · ROLE_DESCRIPTION · ROLE_RESOURCE · ROLE_CATEGORY · ROLE_STATUS · ROLE_RECURRING · ROLE_PRIVATE · ROLE_REMINDER · ROLE_CANCELLED | le nom du rôle : key, location, organizer, description, resource, category, status, recurring, private, reminder, cancelled |
- Une colonne booléenne vaut vrai pour
1,true,Youyes. Une colonnestatusporte les valeurs deSTATUS_*(busy,tentative,free,oof,elsewhere). Chaque nom se reconnaît aussi préfixéis_: is_private, puisqueprivateest un mot réservé de PowerScript. - Toutes les colonnes, rôle ou non, sont des champs des modèles : une colonne
customers'écrit{customer}sur la carte, et se lit parof_get_field. - Une colonne qui joue
ROLE_KEYremplace le numéro de ligne comme clé : à réserver aux données que vous ne rechargez pas depuis ce DataStore. Ses valeurs doivent être uniques et non vides : une ligne qui ne le respecte pas (ou dont la valeur contient/ou|) garde son numéro de ligne comme clé, etue_script_errorle dit une fois. - Le calendrier ne modifie jamais le DataStore : il vous dit ce que l'utilisateur a fait (
ue_appointment_moved,ue_appointment_resized), vous faitesSetItem, puisUpdate()quand votre application le décide. - Après un
InsertRow, unDeleteRow, unSortou unFilter, les numéros de ligne changent : rappelezof_from_datastore.
Ressources et regroupement #
Une ressource est ce sur quoi on réserve : une personne, une salle, une machine (of_add_resource). Un rendez-vous la nomme par is_resource. Avec is_group_by = GROUP_RESOURCE, chaque jour des vues jour et semaine se divise en une colonne par ressource, et glisser une carte dans une autre colonne change sa ressource — ue_appointment_moved la rend dans as_resource. ib_visible = false sur une ressource masque sa colonne et ses rendez-vous, comme décocher un calendrier dans Outlook.
Couleurs, catégories et statut #
La couleur d'une carte se décide dans cet ordre : l'il_accent posé sur ce rendez-vous, puis la couleur de sa catégorie (of_add_category, is_category), puis celle de sa ressource, puis l'accent du thème. Le liseré de gauche dit le statut (is_status, le « Afficher comme » d'Outlook : occupé, provisoire, libre, absent, ailleurs) ; un rendez-vous ib_cancelled est dessiné creux, et ib_recurring, ib_private, ib_reminder posent un petit signe sur la carte.
Propriétés #
| Propriété | Type | Défaut | Rôle |
|---|---|---|---|
is_view | string | VIEW_WORK_WEEK | La vue affichée (VIEW_*). Relue en direct : l'utilisateur la change depuis la barre d'outils. La poser lève ue_view_changed, comme le menu des vues (rien si la vue ne change pas) |
is_date | string | aujourd'hui | Le jour affiché, "yyyy-mm-dd" : la vue se construit autour (sa semaine, son mois). Relue en direct : les flèches la déplacent. Une fois posée, is_now ne la déplace plus ; "" rend la vue à aujourd'hui |
is_now | string | "" | « Maintenant », pour la ligne de l'heure courante et le bouton Aujourd'hui : "" = l'horloge du poste ; "yyyy-mm-dd hh:mm" la fige (démonstration, test, rejeu). Tant que is_date n'a jamais été posée, la vue va à son jour |
ii_first_day_of_week | integer | 1 | Premier jour de la semaine, en numéros ISO comme is_work_days : 1 = lundi … 7 = dimanche ; 0 est accepté pour dimanche |
is_work_days | string | "1|2|3|4|5" | Les jours ouvrés, numéros ISO joints par | (1 = lundi … 7 = dimanche, 0 accepté pour dimanche) : ils forment la semaine de travail, les autres sont grisés |
is_work_start · is_work_end | string | "08:00" · "17:00" | Les heures de travail, "hh:mm" : le reste de la journée est grisé |
is_day_start · is_day_end | string | "00:00" · "24:00" | Les heures que la grille horaire montre ; ce qui tombe en dehors est compté au bord de sa colonne (« ▲ 1 plus tôt », « ▼ 1 plus tard »), avec ce que le défilement cache au-dessus ou au-dessous de la vue ; un clic sur le repère amène le rendez-vous caché le plus proche |
ii_slot_minutes | integer | 30 | Le pas de la grille en minutes : 5, 10, 15, 20, 30 ou 60. Un glisser s'y aligne |
ii_hour_height | integer | 48 | La hauteur d'une heure, en pixels |
is_scroll_time | string | "08:00" | L'heure où la grille se place à l'ouverture d'une vue |
ib_show_now | boolean | true | La ligne rouge de l'heure courante |
ib_toolbar | boolean | true | La barre d'outils : Aujourd'hui, précédent, suivant, le titre, le menu des vues |
ib_week_numbers | boolean | false | Les numéros de semaine ISO, dans le coin de la grille horaire et devant chaque ligne du mois |
ib_read_only | boolean | false | Rien ne se déplace, ne se redimensionne ni ne se crée à la souris ; Suppr ne demande plus rien |
ib_all_day_band | boolean | true | La bande « journée entière » au-dessus de la grille horaire |
ib_tooltips | boolean | true | L'info-bulle de chaque rendez-vous, écrite par les modèles d'info-bulle |
ib_veto_changes | boolean | false | Demande avant d'appliquer un déplacement ou un redimensionnement : lève ue_appointment_changing, qui peut refuser |
is_card_template | string | "[b]{subject}[/b]{?location}; {location}{/location}" | Le modèle de la carte : vues jour et semaine, agenda, barres du mois — voir Les modèles |
is_month_template | string | "{!all_day}{start} {/all_day}{subject}" | Une ligne de la vue mois, pour un rendez-vous contenu dans un jour |
is_tooltip_title_template | string | "{subject}" | Le titre de l'info-bulle d'un rendez-vous |
is_tooltip_template | string | l'heure, le lieu, l'organisateur | Le texte de l'info-bulle d'un rendez-vous — voir Les modèles |
is_group_by | string | GROUP_NONE | GROUP_RESOURCE : une colonne par ressource sous chaque jour, plus une colonne (aucune) à la fin quand un rendez-vous n'a pas de ressource connue du calendrier |
is_filter | string | "" | N'affiche que les rendez-vous qui contiennent ce texte (sujet, lieu, organisateur, description, champs) ; "" les montre tous |
is_time_format | string | "hh:mm" | L'écriture d'une heure : "hh:mm", "h:mm AM/PM"… (jetons de Les modèles) |
ii_agenda_days | integer | 7 | Le nombre de jours que liste la vue agenda |
is_theme_style | string | "" | Style visuel du composant (constantes THEME_STYLE_*) ; vide = celui de l'application, suivi à chaque changement |
is_theme_mode | string | "" | Variante claire ou sombre (constantes THEME_MODE_*) ; vide = celle de l'application, suivie à chaque changement |
il_theme_accent | long | -1 | Couleur d'accent de ce composant (-1 = l'accent de l'application, ou celui du thème) |
is_tooltip | string | "" | Info-bulle simple du composant (un rendez-vous a la sienne, écrite par les modèles) |
is_super_tooltip_title | string | "" | Titre de l'info-bulle enrichie (prend le pas sur is_tooltip) |
is_super_tooltip_text | string | "" | Texte de l'info-bulle enrichie (balisage riche accepté) |
is_super_tooltip_image | string | "" | Image de l'info-bulle enrichie |
Propriétés d'un rendez-vous #
Un rendez-vous se pilote par son handle, of_appointment("clé") — créé au premier accès, il reste valable ensuite. Une propriété lue demande au composant ce qu'elle vaut maintenant : après un glisser, is_start et is_end disent déjà où l'utilisateur l'a déposé.
// A handle used once fits on one line
uo_sched.of_appointment(/*key*/ "a1").is_status = n_pbt_scheduler_appointment.STATUS_TENTATIVE
| Propriété | Type | Défaut | Rôle |
|---|---|---|---|
is_subject | string | celui d'of_add_appointment | Le sujet, ce que la carte montre d'abord ({subject}) |
is_start · is_end | string | ceux d'of_add_appointment | Début et fin, "yyyy-mm-dd hh:mm", fin exclusive ; pour une journée entière, des dates "yyyy-mm-dd", les deux jours inclus. Une autre écriture (22/09/2026 09:00) est gardée mais jamais dessinée |
ib_all_day | boolean | false | Occupe des journées entières : dessiné dans la bande « journée entière » |
is_location · is_organizer · is_description | string | "" | Le lieu ({location}), l'organisateur ({organizer}), un texte plus long ({description}) |
is_resource | string | "" | La clé de sa ressource : sa colonne quand le calendrier regroupe par ressource, sa couleur quand il n'a pas de catégorie |
is_category | string | "" | La clé de sa catégorie : la couleur de la carte |
is_status | string | STATUS_BUSY | Le « Afficher comme » d'Outlook (STATUS_*), dessiné par le liseré de gauche |
ib_recurring · ib_private · ib_reminder | boolean | false | Petits signes sur la carte : une périodicité, un rendez-vous privé, un rappel |
ib_cancelled | boolean | false | Un rendez-vous annulé est dessiné creux |
ib_read_only | boolean | false | L'utilisateur ne peut ni le déplacer, ni le redimensionner, ni demander sa suppression |
ib_visible | boolean | true | Le masque sans le retirer |
Comme tout item, un rendez-vous porte aussi l'info-bulle commune (is_tooltip, is_super_tooltip_title, is_super_tooltip_text, is_super_tooltip_image) — elle remplace alors celle des modèles — et les couleurs d'item : il_accent recolore la carte et son liseré, il_back_color, il_text_color, il_back_color_hover et il_text_color_hover la peignent au repos et au survol.
Propriétés d'une ressource et d'une catégorie #
| Propriété | Handle | Rôle |
|---|---|---|
is_label | n_pbt_scheduler_resource | Le nom affiché au-dessus de sa colonne quand le calendrier regroupe par ressource ({resource_label}) |
il_color | n_pbt_scheduler_resource | La couleur de ses rendez-vous qui n'ont pas de catégorie ; -1 = l'accent |
ib_visible | n_pbt_scheduler_resource | false masque sa colonne et ses rendez-vous |
is_label | n_pbt_scheduler_category | Son nom ({category_label}) |
il_color | n_pbt_scheduler_category | La couleur de ses rendez-vous ; -1 = l'accent. Une catégorie n'est pas dessinée pour elle-même : l'info-bulle et les cinq couleurs d'item qu'elle hérite sont gardées et relues, sans effet visible |
Constantes #
| Famille | Constantes | Portées par |
|---|---|---|
| Vue | VIEW_DAY, VIEW_WORK_WEEK, VIEW_WEEK, VIEW_MONTH, VIEW_AGENDA | le composant (is_view) |
| Regroupement | GROUP_NONE, GROUP_RESOURCE | le composant (is_group_by) |
| Rôle d'une colonne | ROLE_KEY, ROLE_SUBJECT, ROLE_START, ROLE_END, ROLE_ALL_DAY, ROLE_LOCATION, ROLE_ORGANIZER, ROLE_DESCRIPTION, ROLE_RESOURCE, ROLE_CATEGORY, ROLE_STATUS, ROLE_RECURRING, ROLE_PRIVATE, ROLE_REMINDER, ROLE_CANCELLED, ROLE_READ_ONLY | le composant (of_map) |
| Statut | STATUS_BUSY, STATUS_TENTATIVE, STATUS_FREE, STATUS_OOF, STATUS_ELSEWHERE | le handle de rendez-vous (is_status) |
Les constantes se lisent sur l'objet qui les porte :
u_pbt_scheduler.VIEW_MONTHpour une propriété du composant,n_pbt_scheduler_appointment.STATUS_OOFpour une propriété de rendez-vous.
Méthodes #
Rendez-vous #
| Méthode | Rôle | |
|---|---|---|
of_add_appointment (string as_key, string as_subject, string as_start, string as_end) | Ajoute un rendez-vous : sa clé (unique), son sujet, son début et sa fin "yyyy-mm-dd hh:mm". Tout le reste passe par son handle. Rend 0 une fois ajouté, -5 quand la clé est vide, contient / ou ` | , ou est **déjà prise** (un rendez-vous ne se met pas à jour par là : son handle le fait), ou quand le début — ou une fin donnée — n'est pas écrit yyyy-mm-dd ou yyyy-mm-dd hh:mm (String(ldt) écrit 22/09/2026 sur un poste français : prenez la surcharge datetime), -2` quand le composant n'est pas créé |
of_add_appointment (string as_key, string as_subject, datetime adt_start, datetime adt_end) | La même, depuis deux datetime ; une fin nulle vaut le début. Pour une journée entière, la fin est le dernier jour lui-même, inclus : deux fois la même date = un jour. Rend 0 une fois ajouté, -5 quand la clé est vide, contient / ou ` | ou est déjà prise, ou quand le début est nul, -2` quand le composant n'est pas créé |
of_appointment (string as_key) | Le handle d'un rendez-vous (n_pbt_scheduler_appointment), créé au premier accès — voir Propriétés d'un rendez-vous | |
of_remove_appointment (string as_key) | Retire un rendez-vous. Rend 0 une fois retiré, -5 quand le calendrier n'a aucun rendez-vous de cette clé, -2 quand le composant n'est pas créé | |
of_clear_appointments ( ) | Retire tous les rendez-vous ; ressources, catégories et options restent. Rend 0 une fois envoyé, -2 quand le composant n'est pas créé | |
of_set_field (string as_key, string as_field, string as_value) | Donne à un rendez-vous un champ à vous, pour les modèles : après of_set_field("a1", "customer", "ACME"), {customer} écrit ACME sur sa carte. Rend 0 une fois posé, -5 quand le champ est vide ou que le calendrier n'a aucun rendez-vous de cette clé, -2 quand le composant n'est pas créé | |
of_get_field (string as_key, string as_field) | Lit en direct un champ d'un rendez-vous : un des vôtres (of_set_field) ou une colonne du DataStore dont il vient ; "" quand il n'en a pas |
DataStore #
| Méthode | Rôle |
|---|---|
of_from_datastore (datastore ads) | Le pont DataStore : une ligne = un rendez-vous, sa clé = son numéro de ligne, chaque colonne = un champ des modèles. Remplace les rendez-vous affichés. Rend 0 une fois chargé, -5 quand le DataStore n'est pas valide ou n'a aucune colonne, -2 quand le composant n'est pas créé |
of_map (string as_role, string as_column) | Donne un rôle (ROLE_*) à une colonne dont le nom ne le dit pas : of_map(ROLE_SUBJECT, "title_text"). Avant ou après of_from_datastore : après, chaque ligne est relue telle qu'elle est maintenant — un rendez-vous retiré le reste, un rendez-vous glissé reste où il a été lâché, les champs d'of_set_field et les rendez-vous ajoutés à la main restent. Rend 0 une fois posé, -5 quand le rôle n'est pas une des constantes ROLE_* ou quand la colonne n'est pas une de celles du DataStore du dernier of_from_datastore ; un nouveau ROLE_KEY donne à chaque ligne une nouvelle clé, et les handles des anciennes sont libérés, -2 quand le composant n'est pas créé |
Ressources et catégories #
| Méthode | Rôle | |
|---|---|---|
of_add_resource (string as_key, string as_label) | Ajoute une ressource — une personne, une salle, une machine ; sa couleur et sa visibilité passent par of_resource. Rend 0 une fois ajoutée, -5 quand la clé est vide, contient / ou ` | , ou est déjà prise, -2` quand le composant n'est pas créé |
of_resource (string as_key) | Le handle d'une ressource (n_pbt_scheduler_resource), créé au premier accès | |
of_remove_resource (string as_key) | Retire une ressource ; ses rendez-vous restent — regroupés par ressource, dans la colonne (aucune). Rend 0 une fois retirée, -5 quand le calendrier n'a aucune ressource de cette clé, -2 quand le composant n'est pas créé | |
of_clear_resources ( ) | Retire toutes les ressources. Rend 0 une fois envoyé, -2 quand le composant n'est pas créé | |
of_add_category (string as_key, string as_label, long al_color) | Ajoute une catégorie de couleur : les rendez-vous dont is_category la nomme prennent sa couleur (-1 = l'accent). Rend 0 une fois ajoutée, -5 quand la clé est vide, contient / ou ` | , ou est déjà prise, -2` quand le composant n'est pas créé |
of_category (string as_key) | Le handle d'une catégorie (n_pbt_scheduler_category), créé au premier accès | |
of_remove_category (string as_key) | Retire une catégorie ; ses rendez-vous reviennent à l'accent. Rend 0 une fois retirée, -5 quand le calendrier n'a aucune catégorie de cette clé, -2 quand le composant n'est pas créé | |
of_clear_categories ( ) | Retire toutes les catégories. Rend 0 une fois envoyé, -2 quand le composant n'est pas créé |
Navigation et sélection #
| Méthode | Rôle |
|---|---|
of_next ( ) | Le jour, la semaine ou le mois suivant — la flèche de la barre d'outils. Rend 0 une fois envoyé, -2 quand le composant n'est pas créé |
of_previous ( ) | Le jour, la semaine ou le mois précédent. Rend 0 une fois envoyé, -2 quand le composant n'est pas créé |
of_go_to_today ( ) | Revient à aujourd'hui — le bouton Aujourd'hui. Rend 0 une fois envoyé, -2 quand le composant n'est pas créé |
of_select_appointment (string as_key) | Sélectionne un rendez-vous ("" = aucun), comme un clic : lève ue_selection_changed (rien s'il est déjà la sélection). Rend 0 une fois sélectionné, -5 quand le calendrier n'a aucun rendez-vous de cette clé, -2 quand le composant n'est pas créé |
of_selected_key ( ) | La clé du rendez-vous sélectionné, "" quand aucun — lue en direct |
of_show_appointment (string as_key) | Amène un rendez-vous à l'écran : va à son jour, fait défiler jusqu'à son heure et le sélectionne, comme un clic : lève ue_selection_changed. Un jour que la semaine de travail ne montre pas (un samedi) fait passer la vue en semaine entière, et ue_view_changed le dit. Rend 0 une fois montré, -5 quand le calendrier n'a aucun rendez-vous de cette clé, -2 quand le composant n'est pas créé |
of_scroll_to_time (string as_time) | Fait défiler la grille horaire jusqu'à une heure, "hh:mm". Rend 0 une fois envoyé, -5 quand l'heure est vide, -2 quand le composant n'est pas créé |
of_first_visible_date ( ) · of_last_visible_date ( ) | Le premier et le dernier jour que la vue montre, "yyyy-mm-dd" — lus en direct |
of_shown_count ( ) | Rend le nombre de rendez-vous affichés dans la plage à l'écran : après is_filter, les masqués, les ressources masquées et le plafond du mode démo (les 12 premiers de cette plage) ; of_count compte tout le calendrier |
Événements #
| Événement | Déclenché quand |
|---|---|
ue_appointment_clicked (string as_key) | Un rendez-vous est cliqué (et sélectionné) |
ue_appointment_opened (string as_key) | Double-clic sur un rendez-vous, ou Entrée sur celui qui est sélectionné : ouvrez votre éditeur |
ue_appointment_rclicked (string as_key, long al_x, long al_y) | Clic droit sur un rendez-vous. al_x / al_y sont des pixels écran |
ue_appointment_changing (string as_key, string as_start, string as_end, string as_resource) | Avant qu'un déplacement ou un redimensionnement soit appliqué, seulement si ib_veto_changes est vrai. Rendez false pour remettre le rendez-vous où il était ; true par défaut |
ue_appointment_moved (string as_key, string as_start, string as_end, string as_resource) | L'utilisateur a glissé un rendez-vous : son nouveau début, sa nouvelle fin et sa ressource. Le calendrier le montre déjà là ; enregistrez-le (une ligne de DataStore : SetItem sur la ligne Long(as_key)) |
ue_appointment_resized (string as_key, string as_start, string as_end) | L'utilisateur a tiré un bord d'un rendez-vous : son nouveau début et sa nouvelle fin |
ue_range_selected (string as_start, string as_end, boolean ab_all_day, string as_resource) | L'utilisateur a balayé des cases vides à la souris : la plage, pour y créer un rendez-vous. Balayée dans la bande « journée entière » ou dans le mois, ce sont des jours entiers : ab_all_day vaut true, dates seules, la dernière incluse |
ue_new_requested (string as_start, string as_end, boolean ab_all_day, string as_resource) | L'utilisateur demande un nouveau rendez-vous : double-clic sur une case ou un jour vide, ou le + d'un en-tête de jour (regroupé par ressource : d'un en-tête de ressource). Un jour entier arrive en dates seules, la fin incluse : deux fois la même date = un jour |
ue_delete_requested (string as_key) | Suppr a été pressée sur le rendez-vous sélectionné. Retirez-le (of_remove_appointment) une fois que votre application est d'accord |
ue_slot_rclicked (string as_start, boolean ab_all_day, string as_resource, long al_x, long al_y) | Clic droit sur une case ou un jour vide ; pour un jour, as_start est sa date seule. al_x / al_y sont des pixels écran |
ue_selection_changed (string as_key) | Le rendez-vous sélectionné a changé ("" = aucun) : un clic, ou of_select_appointment / of_show_appointment depuis votre code |
ue_view_changed (string as_view) | La vue a changé : l'utilisateur en a choisi une autre dans la barre d'outils ou a ouvert un jour par son « +N », votre code a posé is_view, ou of_show_appointment a fait passer la semaine de travail en semaine entière pour montrer un jour chômé |
ue_date_changed (string as_first, string as_last) | La plage visible a changé (navigation, vue, date) : son premier et son dernier jour, "yyyy-mm-dd", inclus. Levé aussi au premier affichage (sur la plage d'aujourd'hui), puis de nouveau quand votre code pose is_date ou is_view : une fenêtre qui les pose à l'ouverture en reçoit deux ; et après chaque of_reset, qui vide le calendrier : c'est une demande de données, pas un geste. C'est ici qu'on charge les rendez-vous de la plage |
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) |
Les modèles #
Ce qu'une carte, une ligne du mois et une info-bulle disent n'est pas figé : c'est un modèle que vous écrivez, en texte riche ([b], [br], [color=…], [symbol=…]…) avec des champs entre accolades. Quatre propriétés les portent : is_card_template (cartes des vues jour et semaine, agenda, barres du mois), is_month_template (une ligne de la vue mois), is_tooltip_title_template et is_tooltip_template (l'info-bulle). Le modèle d'info-bulle par défaut est :
[symbol=clock] {when}{?location}[br][symbol=location] {location}{/location}{?organizer}[br][symbol=person] {organizer}{/organizer}
La syntaxe #
| Écriture | Effet |
|---|---|
{subject} | La valeur du champ, échappée : un [ dans le sujet s'affiche, il n'ouvre pas de balise |
{start:dddd d mmmm} | Un champ date dans un format (jetons ci-dessous) |
{?location}…{/location} | Écrit le bloc seulement si le champ dit quelque chose qui n'est pas un NON : ni vide, ni 0, N, no ou false |
{!all_day}…{/all_day} | Écrit le bloc seulement si le champ est vide (ou faux) |
{description:raw} | Insère la valeur comme du balisage, sans l'échapper — pour un champ qui contient déjà des balises |
{{ · }} | Une accolade littérale |
Les formats de date #
Les jetons sont ceux de PowerBuilder ; les noms de jours et de mois suivent la langue d'affichage. Un texte entre guillemets est écrit tel quel. Les mêmes jetons servent à is_time_format.
| Jeton | Écrit |
|---|---|
yyyy · yy | L'année, 2026 · 26 |
mmmm · mmm | Le nom du mois, long · court |
mm · m | Le mois, 09 · 9 — ou les minutes juste après une heure, comme dans PowerBuilder |
dddd · ddd | Le nom du jour, long · court |
dd · d | Le jour du mois, 05 · 5 |
hh · h | L'heure, 09 · 9 (sur 12 heures avec AM/PM) |
nn · n | Les minutes, 05 · 5 |
AM/PM · am/pm | Le repère du matin ou de l'après-midi |
Les champs #
| Champ | Valeur |
|---|---|
key · subject · location · organizer · description | La clé et les textes du rendez-vous |
resource · resource_label | La clé de sa ressource · son nom |
category · category_label | La clé de sa catégorie · son nom |
status · status_label | Le statut (busy…) · son libellé, traduit dans la langue d'affichage |
all_day · recurring · private · reminder · cancelled | true, ou vide : faits pour {?…} et {!…} |
start · end | L'heure de début · de fin, au format is_time_format (vide pour une journée entière) ; avec un format, la date et l'heure — pour une journée entière, {end:…} est le dernier jour, comme is_end le relit |
date | Le premier jour, en toutes lettres ; avec un format, le début formaté |
time | 09:00-10:30, ou « Toute la journée » |
when | La phrase complète : jour, heures, et le jour de fin quand il diffère |
duration | 45 min, 1 h 30, 2 days (traduit) |
| les vôtres | Tout champ posé par of_set_field, et toute colonne du DataStore d'of_from_datastore, sous son nom. Une valeur qui est une date accepte un format : {due_date:dd/mm} |
Un champ inconnu écrit une chaîne vide.
Les symboles #
La balise [symbol=nom] du texte riche pose un symbole intégré, monochrome, dessiné dans la couleur du texte qui l'entoure — il suit le thème, le survol et la couleur de la carte, sans fichier à livrer : clock, location, person, people, calendar, repeat, lock, bell, phone, mail, video, note, tag, link, check, star, info, warning. Un nom inconnu s'affiche tel quel.
Ce que l'utilisateur peut faire sans une ligne de code #
- naviguer : Aujourd'hui, précédent, suivant, et le menu des vues de la barre d'outils ;
- déplacer un rendez-vous vers une autre heure, un autre jour ou une autre ressource, en le glissant — le pas suit
ii_slot_minutes; - redimensionner un rendez-vous en tirant son bord ;
- balayer des cases vides pour choisir une plage →
ue_range_selected— dans la bande « journée entière » ou dans le mois, des jours entiers ; - demander un rendez-vous par double-clic sur une case vide ou par le + d'un en-tête de jour (d'un en-tête de ressource quand le calendrier est regroupé) →
ue_new_requested; - ouvrir un rendez-vous par double-clic →
ue_appointment_opened, et cliquer droit sur un rendez-vous ou une case vide pour votre menu.
Le calendrier ne crée, ne modifie ni ne supprime rien de lui-même au-delà du glisser : il demande, votre application décide. ib_read_only coupe tous ces gestes d'un coup, ib_read_only sur un rendez-vous les coupe pour lui seul.
Au clavier, une fois le calendrier atteint :
| Touche | Effet |
|---|---|
| Entrée | Ouvre le rendez-vous sélectionné → ue_appointment_opened |
| Suppr | Demande la suppression du rendez-vous sélectionné → ue_delete_requested (rien si le calendrier ou le rendez-vous est en lecture seule) |
| Flèche haut / Flèche bas | Sélectionne le rendez-vous précédent / suivant de la vue, dans l'ordre des heures de début → ue_selection_changed |
| Page haut / Page bas | Le jour, la semaine ou le mois précédent / suivant |
| Alt+Début | Revient à aujourd'hui |
| Échap | Annule un glisser en cours |
Exemples #
Les rendez-vous d'un DataStore, et ce que l'utilisateur en fait #
Le DataStore ids_appts (variable d'instance) a les colonnes subject, start_date, end_date, location, room, category et customer. Les quatre premières jouent leur rôle par leur nom ; room le reçoit d'of_map.
// open event of the window : the appointments, retrieved the way your application already does
ids_appts = create datastore
ids_appts.dataobject = "d_appointments"
ids_appts.SetTransObject(SQLCA)
ids_appts.Retrieve()
// "room" is not a role name : say which role it plays, then load every row
uo_sched.of_map(/*role*/ u_pbt_scheduler.ROLE_RESOURCE, /*column*/ "room")
uo_sched.of_from_datastore(/*ads*/ ids_appts)
// ue_appointment_moved event of uo_sched : (string as_key, string as_start, string as_end, string as_resource)
// Local variables
long ll_row
// The key of a row loaded by of_from_datastore is its row number
ll_row = Long(as_key)
ids_appts.SetItem(ll_row, "start_date", DateTime(Date(Left(as_start, 10)), Time(Mid(as_start, 12))))
ids_appts.SetItem(ll_row, "end_date", DateTime(Date(Left(as_end, 10)), Time(Mid(as_end, 12))))
ids_appts.SetItem(ll_row, "room", as_resource)
// Save when YOUR application decides : here, at once
ids_appts.Update()
// ue_appointment_resized event of uo_sched : (string as_key, string as_start, string as_end)
// Local variables
long ll_row
// Only the times change : same row, same two columns
ll_row = Long(as_key)
ids_appts.SetItem(ll_row, "start_date", DateTime(Date(Left(as_start, 10)), Time(Mid(as_start, 12))))
ids_appts.SetItem(ll_row, "end_date", DateTime(Date(Left(as_end, 10)), Time(Mid(as_end, 12))))
ids_appts.Update()
Créer et supprimer #
// ue_new_requested event of uo_sched : (string as_start, string as_end, boolean ab_all_day, string as_resource)
// Local variables
long ll_row
// A new row, prefilled with the slot the user chose
ll_row = ids_appts.InsertRow(0)
ids_appts.SetItem(ll_row, "subject", "New appointment")
ids_appts.SetItem(ll_row, "start_date", DateTime(Date(Left(as_start, 10)), Time(Mid(as_start, 12))))
ids_appts.SetItem(ll_row, "end_date", DateTime(Date(Left(as_end, 10)), Time(Mid(as_end, 12))))
ids_appts.SetItem(ll_row, "room", as_resource)
// Reload (the row numbers are the keys), then bring the new one into view
uo_sched.of_from_datastore(/*ads*/ ids_appts)
uo_sched.of_show_appointment(/*key*/ String(ll_row))
// ue_delete_requested event of uo_sched : (string as_key)
// Ask first : the calendar never deletes by itself
if MessageBox("Delete", "Delete this appointment?", Question!, YesNo!) = 2 then return
ids_appts.DeleteRow(Long(as_key))
ids_appts.Update()
// The rows after it changed number : reload
uo_sched.of_from_datastore(/*ads*/ ids_appts)
Une colonne par salle #
// The rooms, each with its own colour, side by side under each day
uo_sched.of_set_redraw(/*on*/ false)
uo_sched.of_add_resource(/*key*/ "r1", /*label*/ "Room A")
uo_sched.of_add_resource(/*key*/ "r2", /*label*/ "Room B")
uo_sched.of_resource(/*key*/ "r1").il_color = RGB(15, 108, 189)
uo_sched.of_resource(/*key*/ "r2").il_color = RGB(31, 158, 117)
uo_sched.is_group_by = u_pbt_scheduler.GROUP_RESOURCE
uo_sched.is_view = u_pbt_scheduler.VIEW_DAY
// Each appointment names its room
uo_sched.of_add_appointment(/*key*/ "k1", /*subject*/ "Kickoff", /*start*/ "2026-09-22 09:00", /*end*/ "2026-09-22 10:00")
uo_sched.of_appointment(/*key*/ "k1").is_resource = "r1"
uo_sched.of_add_appointment(/*key*/ "k2", /*subject*/ "Interview", /*start*/ "2026-09-22 10:30", /*end*/ "2026-09-22 11:30")
uo_sched.of_appointment(/*key*/ "k2").is_resource = "r2"
uo_sched.of_set_redraw(/*on*/ true)
// A checkbox of the window hides Room B and its appointments, like unticking a calendar in Outlook
uo_sched.of_resource(/*key*/ "r2").ib_visible = cbx_room_b.checked
Des cartes et des info-bulles à vous #
// The card : the time, the subject in bold, the customer (a DataStore column) when there is one
uo_sched.is_card_template = "{start} [b]{subject}[/b]{?customer}[br][symbol=people] {customer}{/customer}"
// The month line : a small lock on the private ones
uo_sched.is_month_template = "{?private}[symbol=lock] {/private}{subject}"
// The tooltip : the date written out, the duration, the status
uo_sched.is_tooltip_title_template = "{subject}"
uo_sched.is_tooltip_template = "[symbol=calendar] {start:dddd d mmmm}, {time} ({duration})[br][symbol=info] {status_label}"
Refuser un déplacement #
// Ask before any move or resize is applied
uo_sched.ib_veto_changes = true
// ue_appointment_changing event of uo_sched : (string as_key, string as_start, string as_end, string as_resource) returns boolean
// Nothing on a Saturday or a Sunday : returning false puts the appointment back
if DayNumber(Date(Left(as_start, 10))) = 1 or DayNumber(Date(Left(as_start, 10))) = 7 then return false
return true
Ne charger que ce qui se voit #
Sur des années d'historique, inutile de tout lire : ue_date_changed donne la plage à l'écran à chaque navigation, et au premier affichage. Ici d_appointments prend deux arguments datetime, début et fin de la plage.
// ue_date_changed event of uo_sched : (string as_first, string as_last)
// The last day is INCLUDED : read up to the start of the day after
ids_appts.Retrieve(DateTime(Date(as_first)), DateTime(RelativeDate(Date(as_last), 1)))
uo_sched.of_from_datastore(/*ads*/ ids_appts)
Votre menu sur un rendez-vous #
// ue_appointment_rclicked event of uo_sched : (string as_key, long al_x, long al_y)
// Local variables
m_appointment lm_menu
// Remember which appointment the menu is about, then open YOUR menu under the pointer
is_menu_key = as_key
lm_menu = create m_appointment
lm_menu.m_popup.PopMenu(parent.PointerX(), parent.PointerY())
destroy lm_menu
Bonnes pratiques #
- Encadrez une série d'ajouts par
of_set_redraw(/*on*/ false)/of_set_redraw(/*on*/ true): les rendez-vous apparaissent d'un seul coup. - Pour des données qui vivent en base, préférez
of_from_datastoreà une boucle d'of_add_appointment: un seul transfert, et chaque événement vous rend la ligne. - Rechargez (
of_from_datastore) après toutInsertRow,DeleteRow,SortouFilterdu DataStore : la clé d'un rendez-vous est un numéro de ligne. - Écrivez les dates en
"yyyy-mm-dd hh:mm", jamais dans le format régional du poste : c'est le seul que le calendrier lit partout. - Dans un modèle, entourez un champ facultatif de
{?champ}…{/champ}: une carte sans lieu n'affiche pas un « ; » orphelin. - Sur un historique long, chargez la plage visible dans
ue_date_changedplutôt que tout le DataStore. - Pour une règle métier (pas de rendez-vous le week-end, pas de chevauchement dans une salle),
ib_veto_changesetue_appointment_changingrefusent avant que la carte bouge.
Limites de la 4.0 #
Ce que le calendrier ne fait pas — à savoir avant de le choisir :
- Récurrence : ni séries (règles RRULE), ni exceptions, ni édition « cette occurrence / toute la série ».
ib_recurringpose seulement un signe sur la carte : chaque occurrence est un rendez-vous (une ligne du DataStore) que votre application déroule elle-même. Un moteur de récurrence est prévu pour une version suivante. - Fuseaux horaires : l'heure est locale flottante (voir Les dates) ; aucune seconde échelle horaire, aucune conversion.
- Vue chronologie (ressources en lignes, temps en colonnes) et mini-calendrier de navigation : absents ; regroupez par ressource (
GROUP_RESOURCE) dans les vues jour et semaine. - iCalendar : ni import ni export de fichiers
.ics. - Impression : aucune ; le calendrier se dessine à l'écran seulement.
- Clavier : on sélectionne, ouvre, supprime et navigue au clavier, mais on ne crée ni ne déplace un rendez-vous sans la souris.
- Date et heure en deux colonnes : un début écrit dans deux colonnes du DataStore ne se mappe pas ; assemblez-le en une colonne
datetimedans la requête.
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.
| Membres | Rôle | Détaillé dans |
|---|---|---|
of_count · of_keys_at · of_has | Parcourir ce que le composant contient | 3.2 Les items |
of_reset | Remettre le composant à zéro | 3.6 Remettre un composant à zéro : of_reset() |
of_register_shortcut · of_clear_shortcuts | Raccourcis clavier du composant | 3.5 Les raccourcis clavier |
of_is_created · of_is_ready · of_get_last_error | S'il est né, s'il est prêt, ce qui a échoué | 3.7 Diagnostic |
of_save_as_png · of_save_as_jpg | Exporter le rendu en image | 3.8 Exporter le rendu en image |
of_set_redraw | Grouper les modifications en un seul repaint | 3.10 Bonnes pratiques |
of_preload_icons | Icônes affichées sans délai | Affichage instantané : of_icon |
of_set_translation | Traduire un libellé du composant | 5.2 Adapter un libellé : of_set_translation |
of_focus_webview | Donner le focus au composant | 6.4 Clavier et focus |
of_print · of_print_to_pdf | Imprimer, ou écrire un PDF | 6.9 Imprimer |
of_set_property · of_get_property · of_component_name | Piloter une propriété par son nom | 3.1 Le moteur de propriétés |
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.