27 juin 2007

Obtenir une représentation hexadécimale d'une chaîne de caractères alphanumérique

Petite astuce lorsque l'on doit donner une forme hexadécimale à une chaine : utiliser la fonction "NumériqueVersChaine" qui permet la conversion simple d'une valeur décimale en hexadécimale. Exemple :

sChaine est une chaîne = "Bonjour, 27 juin 2007"
sChaineHexa est une chaîne

POUR i = 1 A Taille(sChaine)
sChaineHexa += NumériqueVersChaîne(Asc(sChaine[[i]]), "2X")
FIN

Info(sChaineHexa)
Une application directe, visualiser le Hash d'un fichier par exemple, car sans conversion de ce type la valeur contient des signes cabalistiques peu lisibles.

25 juin 2007

Pourquoi le fond d'une fenêtre ne change pas avec la propriété ..ImageFond ?

Pour le déploiement des applications, il faut garder dans un coin de tête que les éléments (fenêtres, états, images ...) de la bibliothèque sont prioritaires à ceux localisés sur disque.

Exemple type, dans une application on propose à l'utilisateur de changer l'image de fond de sa fenêtre principale. Pour cela, on a dans le code de déclaration des globales de la fenêtre :

MaFenêtre..ImageFond = ComplèteRep(fRepExe())+"ImageFond.jpg"
Il suffit de changer l'image "ImageFond.jpg" du répertoire de l'exécutable pour personnaliser l'image de fond de la fenêtre. Mais attention, cela ne fonctionne que si dans l'application aucune image "ImageFond.jpg" n'est utilisée par ailleurs. Dans le cas contraire, l'image utilisée par l'application est incluse dans la bibliothèque, elle est prioritaire, et une nouvelle image "ImageFond.jpg" dans le répertoire de l'exécutable est tout simplement ignorée.

10 mai 2007

Colonne combo d'une table, syntaxe de récupération de la valeur donnée par "gLien" au chargement

Lorsqu'une colonne combo d'une table est chargée par programmation avec "ListeAjoute", et que chaque élément a un identifiant donné avec "gLien", la récupération de cet identifiant n'est pas immédiate.

D'abord il ne faut pas cocher l'option "retourner la valeur spécifiée avec la fonction gLien" dans le détail de la description de la colonne combo.

Ensuite il faut utiliser dans le code la syntaxe suivante :

Info(NomTable.NomColonneCombo[NuméroLigne][NomTable.NomColonneCombo[NuméroLigne]])

Sans cette syntaxe, la récupération de l'information donnée au chargement avec "gLien" n'est que partielle.

Ndlr : ne pensez pas que j'ai trouvé cette syntaxe par moi-même, il s'agit d'une information obtenue du support !

25 avril 2007

Comment stopper un sablier récalcitrant ?

Pour faire patienter un utilisateur, l'utilisation d'un sablier est parfaitement adaptée. Mais dans la "vie" d'une application, un traitement simple au départ s'enrichie au fil du temps, fait appel à des composants, dialogues avec d'autres applications ... bref au final, il y a quelque part un Sablier(Vrai) qui persiste et ne veut plus s'enlever même avec un Sablier(Faux) dans le traitement.

Voici une méthode de contournement permettant de s'assurer de la disparition définitive d'un sablier laissé par un traitement.

Il faut créer une procédure globale "StopSablier", qui contiendra uniquement un appel de Sablier(Faux). Les automatismes de procédure feront le reste, comme le montre la copie d'écran du billet. Pour résumer, avec un seul appel de la procédure dans le code, on va appeler 3 fois Sablier(Faux), on est ainsi certain de reprendre le curseur de souris standard !

Pas forcément élégant, mais radicalement efficace !

20 avril 2007

Définir l'instruction suivante pour déboguer 10 fois plus vite !

Pendant longtemps le passage au Débogueur d'un code permettait :
- de suivre l'exécution en pas à pas (F7),
- de repérer le traitement à corriger,
- faire la correction,
- relancer un test pour s'assurer du résultat en ayant donc à refaire tout le processus permettant d'arriver au traitement...

Mais maintenant il y a le bouton que je surnomme le "bouton magique du Débogueur", qui permet de définir l'instruction suivante, tout en débogant. Il facilite en effet considérablement la mise au point et permet :
- de suivre l'exécution en pas à pas (F7),
- de repérer le traitement à corriger,
- faire la correction, et immédiatement rexécuter le code juste avant cette modification !!! Il n'est plus nécessaire de relancer le test et donc de refaire tout le processus permettant d'arriver au traitement.

Il est même possible de changer une fenêtre sous l'éditeur, et de réexécuter son ouverture. Mais là les cas d'usage sont moins fréquents.

16 avril 2007

Migrer une analyse vers une autre base de données...

Les forums contiennent souvent des sujets de la forme "comment migrer mon analyse" en Oracle, en SQL SERVER, MYSQL...

J'avais évoqué ce sujet dans un précédent billet, il n'y a aucune migration à faire au niveau des descriptions de fichiers pour utiliser une base de données ou une autre ! Si dans l'analyse un fichier est décrit en Oracle, sa description peut être appliquée en Hyper File, SQL SERVER ou tout autre base pour laquelle on dispose d'un provider OLE DB ou d'un accès natif.

La clé du mécanisme : les fonctions "HOuvreConnexion" et "HChangeConnexion".

Peu importe le type indiqué dans l'analyse, à tout moment le programme peut :
- appeler "HOuvreConnexion" pour ouvrir une connexion vers une base de données,
- puis appeler "HChangeConnexion" pour associer les tables de l'analyse, à cette nouvelle connexion.

C'est donc un mécanisme à garder dans un coin de tête, bien plus rapide que de se lancer dans des modifications de l'analyse, générations ...

14 avril 2007

Jauge en lieu et place du sablier lors de l'exécution d'une requête, la "soluce" !?

Les utilisateurs ne supportent pas les écrans figés avec un sablier, pourtant imposés lorsqu'une requête importante doit être exécutée.

Afin d'afficher une jauge durant le traitement d'une requête, il faut bien récupérer en premier lieu le nombre d'enregistrements à traiter avec la fonction "HNbEnr", et cette dernière fige l'application avec le sablier tant que toute la requête n'est pas exécutée dans sa totalité.

Et bien cela n'est plus vrai, après consultation des dernières nouveautés !!!

La fonction "HNbEnr" a été dotée d'une option "hNonBloquant". Elle permet de connaître immédiatement après l'appel de la requête, le nombre d'enregistrements déjà récupérés. Il est donc possible de débuter le traitement de la requête par son parcours, tout en affichant une jauge certes approximative, mais une jauge. Au fur et à mesure du parcours, si la propriété "..ExécutionTerminée" retourne faux, il est possible de réajuster la jauge avec le nombre d'enregistrements récupérés en rappelant "HNbEnr".

Tous ceux qui aiment observer les utilisateurs de nos applications, savent déjà que le traitement sera jugé plus rapide, du moment qu'une progression est visible !

13 avril 2007

Extraire sur disque des fichiers contenus dans une bibliothèque ?

J'ai longtemps pensé que cela n'était pas possible, et pourtant ... astuce découverte sur le forum WIN DEV, elle mérite d'être connue j'espère pouvoir la relayer par ce billet !

Je remercie son auteur que je cite (presque) directement :

- Faire un fichier Hyper File avec une rubrique mémo binaire,
- Ajouter les fichiers que l'on veut pouvoir extraire dans le mémo binaire,
- Inclure ce fichier (.fic, .ndx, .mmo) dans l'exécutable,
- dans le code indiquer que pour ce fichier il faut le rechercher dans la bibliothèque :
HChangeLocalisation(Fichier, hWDL)

Et voila.

Il suffit de rechercher dans le fichier Hyper File l'enregistrement qui contient le fichier que l'on souhaite extraire, puis de l'extraire avec :
HExtraitMémo(Fichier,MemoFichier,"C:\chemin...\FichierDestination")

Message d'origine.

Ajout de descriptions de tables MYSQL dans une analyse provoque une erreur MSVCRT.DLL ou WDHF

Rien de pire qu'une action que l'on utilise couramment, et qui sur un poste ne daigne pas s'exécuter. J'ai rencontré ce cas avec l'importation d'une table MYSQL dans une analyse. Après le listage des tables de la base MYSQL, un des messages suivants était affiché :

Une erreur système inattendue est survenue.
Si cet incident se produit de manière systématique
Module MSVCRT.DLL...
Ou :
Erreur interne à la DLL WDHF
L'origine de la panne ? Une version de LIBMYSQL.DLL qui ne convenait pas à WINDEV.
Le problème a donc disparu en installant un MYSQL et en récupérant sa LIBMYSQL.DLL standard. Précédemment il s'agissait d'un MYSQL installé avec par EasyPHP.

Pourquoi la taille d'un fichier Hyper File n'est pas réduite après un lot de suppressions ?

L'appel en série de la fonction "HSupprime()" ne provoque pas la diminution de la taille du fichier. Ceci est valable pour le fichier de données (.FIC) et pour son mémo (.MMO).

Déroutant au premier abord, mais normal en creusant un peu. En effet, pour le système de fichiers (FAT32, NTFS...) l'allocation d'un espace ou sa restitution est coûteuse en temps. Il n'y a qu'à voir la différence de temps entre un copier/coller par l'explorateur, et un couper/coller du même volume. De ce fait en cas de suppression, la taille initiale est conservée, il y a simplement un "marquage" des enregistrements laissés libres par les suppressions. Les ajouts ultérieurs viendront réutiliser ces espaces vides.

Si après une suppression importante on souhaite récupérer l'espace disque correspondant, il est possible d'exécuter la fonction "HRéindexe" avec compression : là tout l'espace est restitué.

A noter que par un parcours séquentiel du fichier sur les numéros d'enregistrements, on peut passer sur les enregistrement marqués à réutiliser (cf. fonction "HEtat").

A noter d'autre part que ce mécanisme met clairement en évidence le fait qu'il ne faut jamais baser un traitement, encore moins une liaison, sur un numéro d'enregistrement puisqu'il n'est pas fixe.

27 mars 2007

Récupération d'un variant provenant d'une DLL ActiveX...

Lorsqu'une procédure WLangage est appelée par une DLL en passant un variant en paramètre, une "gymnastique" est nécessaire pour récupérer l'information renvoyée par la DLL. Cela vaut bien un billet, pour gagner un peu de temps, car en tout premier lieu on aurait tendance à écrire l'entête de la procédure avec :

PROCEDURE AppeléeParDLL(RecupValeur est un variant)

Pourtant avec cette déclaration le message suivant sera obtenu lors de l'exécution :
"Un élément de type ne peut pas être converti vers le type variant"

La bonne déclaration, puis syntaxe de récupération du paramètre est la suivante :
PROCEDURE AppeléeParDLL(RecupValeur)

varRecupVariant est un Variant = RecupValeur
VariantConvertit(varRecupVariant, wlChaîne)
Info(varRecupVariant)

A noter que l'appel de la procédure "AppeléeParDLL" en réponse à la DLL ActiveX est initialisé avec la fonction "AutomationEvénement".

08 mars 2007

Le numéro d'enregistrement des fichiers et des requêtes.

Lors du parcours d'un fichier, on peut connaître la position physique de l'enregistrement dans le fichier avec la fonction HNumEnr(). A partir de ce numéro, il est possible par la suite d'effectuer un accès direct à l'enregistrement avec la fonction "HLit", ou une modification avec "HMofifie(,)".

Par contre lors du parcours du résultat d'une requête, cette même fonction "HNumEnr" donne un numéro d'enregistrement dans la requête, mais pas celui de l'enregistrement d'origine dans le fichier. Pour avoir le numéro de l'enregistrement du fichier, il est possible d'utiliser la variable d'état "H.NumEnr" après une lecture dans la requête. On peut ainsi envisager après une lecture d'un enregistrement du résultat d'une requête, de modifier directement l'enregistrement correspondant dans le fichier avec "HMofifie(,)".

Attention par contre à l'utilisation du numéro d'enregistrement pour accéder aux données. Cette technique convient à un instant donné dans l'application. Par contre il ne faut pas utiliser ce numéro d'enregistrement par exemple pour lier des enregistrements. En effet, la position physique d'un enregistrement dans un fichier est modifiée lors d'opérations de maintenance. Pour les liaisons, l'utilisation de l'identifiant automatique est la meilleure solution.

07 mars 2007

Copier un menu contextuel d'une fenêtre à une autre ?

Les menus contextuels n'étant pas proposés dans le volet de l'éditeur ou la zone Kouglof, il faut donc "ruser" pour récupérer un menu contextuel d'une fenêtre vers une autre. L'astuce est la suivante :
- dans la fenêtre contenant le menu contextuel, créer un bouton,
- associer ce bouton au menu contextuel,
- copier/coller ce bouton vers la fenêtre qui doit recevoir ce menu ...
et c'est fait ! La fenêtre dans laquelle le bouton a été copié contient maintenant le menu. Le bouton peut être supprimé.

02 mars 2007

Plus qu'une ligne de code : One-liner

En clin d'oeil au billet "Pour quelques lignes de code en moins", je pousse le bouchon un peu plus loin avec un programme WIN DEV qui n'a plus qu'une ligne de code, ou "one-liner". Il s'agit de remplacer dans un fichier le caractère de code ascii 10 par un traditionnel "retour-chariot" ou RC. Les adeptes auront reconnus un fichier provenant de Linux devant être transformé pour faciliter son utilisation sous Windows !

fSauveTexte(Remplace(LigneCommande(), fExtraitChemin... (LigneCommande(), fExtension), ...
"New"+fExtraitChemin(LigneCommande(), fExtension)),...
Remplace(fChargeTexte(LigneCommande()), Caract(10),RC))

Le code se trouve dans le code du projet, aucune interface n'est requise pour ce "convertisseur". Une copie du fichier dont le nom est reçu en ligne de commande est créée, avec remplacement du "Caract(10)" par un "retour-chariot". La copie garde le nom et l'emplacement d'origine, seul un "New" est ajouté au nom, juste avant l'extension.

28 février 2007

Pour quelques sourires de plus : améliorer l'accessibilité de la Loupe.

Au petit matin dans les bouchons, il y a deux attitudes. Coller le pare choc de son prédécesseur en se jurant, une main crispée sur le volant et l'autre sur le klaxon, que personne ne vous volera une place. Ce mode de conduite permet de s'assurer un gain de temps pouvant aller jusqu'à 3 secondes, pour l'arrivée au feu suivant 75 mètres plus loin. A l'inverse, il est possible de toujours laisser une distance de sécurité raisonnable avec son prédécesseur, afin de permettre aux autres usagers de prendre leur place dans le trafic. Cette attitude permet de récolter le sourire d'autres conducteurs, soulagés d'enfin trouver une âme charitable tolérant un changement de file, l'accès ou la sortie d'une place de parking... J'opte personnellement pour cette seconde attitude. Pour une journée efficace, la récolte quotidienne de 3 s/km (1) me semble une bonne moyenne.

Un bonus de sourires (2) peut être obtenu en ajoutant un "plus" à une application existante, avec un coût de programmation quasiment nul.

Cas typique, une table fichier permet de rechercher un enregistrement via la loupe. La plupart des recherches se font via une même colonne de la table (numéro de commande, de téléphone, adresse email de plus en plus souvent ...). L'opérateur arrive sur sa fenêtre de recherche, vient cliquer sur la Loupe pour entamer une nouvelle recherche. C'est le genre d'opération que l'utilisateur final peut faire 50 fois dans la journée dans bien des applications.

Pour le "bonus sourires", ajoutez un tri automatique sur la colonne qui est la plus utilisée, et forcer dès l'ouverture de la fenêtre le "focus" sur la table en question. Il suffit d'insérer les appels des fonctions "TableTrie" et "EcranPremier" dans le code d'initialisation de la fenêtre. Le résultat : l'utilisateur dès l'ouverture de sa fenêtre de recherche peut immédiatement entamer la saisie d'une valeur, le passage en saisie dans la loupe de la colonne triée devenant ainsi automatique.

Un détail diront certains. Oui, mais je peux vous assurer qu'une personne ayant pendant des mois eu à faire cette recherche en allant cliquer sur cette loupe, va gagner un grand confort d'utilisation et vous faire de grands sourires le jour ou vous lui permettrez d'éviter ce clic en plus !


(1) s/km : sourires obtenus par kilomètre parcouru à moins de 10 km/h.
(2) rassurez-vous, si vous vous êtes reconnus dans la première attitude au volant, il en faut pour que les garagistes aient encore à changer des embrayages ;-), cela n'empêche pas d'aimer les sourires des Utilisateurs de vos applications !

25 février 2007

64 Bits, mais à tous les étages

La création d'applications 64 bits peut être nécessaire pour répondre à certaines exigences de mise en exploitation.

Le passage d'une application existante en 64 bits, se fait simplement via la coche d'une option dans la description du projet. Mais attention tout de même, si c'est très simple dans une application constituée d'une unique bibliothèque, s'il y a au contraire de nombreux composants la tâche est plus importante. En effet, si l'application est compilée avec la compatibilité 64 bits activée, les composants qu'elle utilise devront également être générés avec la compatibilité 64 bits. Il faut donc penser à cocher l'option de compatibilité 64 bits dans les composants.

Rassurez-vous, l'éditeur vous indique par un message d'information la présence d'un composant qui ne serait pas à jour (ci-contre).

L'activation de la compatibilité 64 bits n'a que très peu d'effets sur les traitements. Les modifications à effectuer vont concerner les types des variables du WLangage, notamment dans les appels de fonctions des API Windows. En effet, une déclaration "est un entier système" doit être faite en lieu et place de déclarations avec "est un entier sur x octets". Là également c'est l'éditeur de code qui indique après une compilation les changements à faire, il n'est pas nécessaire de "fouiller" son code.

Il peut également être nécessaire d'ajouter des variables intermédiaires, car les fonctions du WLangage ne retournent pas des "entier système". C'est par exemple le cas de la fonction "Dimension" qui ne peut donc pas être donnée directement à la fonction "API" si la compatibilité 64 bits est active. Sur ce dernier point, PC SOFT proposera sans doute des évolutions, car cet ajout pourrait être évité.

Pour la phase finale de création de l'exécutable, il est bien d'avoir recours à une nouvelle configuration de projet. Elle permettra via un unique projet de générer un exécutable 32 bits et un exécutable 64 bits. Elle permettra également si besoin la création de composants, de Web services, le tout en une seule opération par le menu "Atelier / Génération multiple".

20 février 2007

A savoir avant de déployer sous Windows Vista...

Après, au fil des bêtas, les incertitudes sur les fonctionnalités qui seraient actives ou non par défaut, Windows VISTA est devenu une réalité. Le voile est levé, plus aucun incertitude ne subsiste l'UAC est active par défaut.

L'UAC, ou pour les initiés User Account Control, est une des fonctionnalités majeure de Windows VISTA. Elle doit permettre de redonner au système la sécurité qui faisait défaut aux précédentes versions.
Lorsqu'elle est active, et que le programmeur ne tient pas compte de ses spécificités, un panneau d'information avec l'icône ci-contre sera fréquemment donné à l'utilisateur final qui risque d'être dérouté. En effet par défaut les privilèges sont restreints, il faut jusqu'à 7 clics par exemple pour supprimer un raccourci sur le bureau.

Ainsi par défaut un message relatif à l'élévation des privilèges peut être affiché régulièrement. N'ayant qu'une expertise limitée sur le sujet, je n'aurai pas la prétention de vous décrire les méandres de ce mécanisme. En revanche un article Microsoft détaille ce qu'il faut absolument connaître de l'UAC avant d'aborder Windows VISTA. Je vous encourage donc vivement à le consulter.

Si besoin dans un tout premier temps, notamment pour le Développement, il est possible de désactiver l'UAC. Plus généralement, les fonctionnalités de VISTA peuvent être activées ou désactivées via ce mode opératoire.

30 janvier 2007

Bon à savoir, exemples revus à profusion...

Le DVD de la LST 66 contient en plus des exemples de la LST elle-même, une série d'exemples des précédentes versions ou LST, revus et améliorés.

En voici la liste un peu "brute", mais un Ctrl+F permet de rechercher un sujet qui vous intéresse :

WD Arbres en saisie, WD Calcul statistiques Hyper File, WD DerniersDocuments, WD Ecran Tactile, WD Fenêtres furtives, WD FileImpression, WD GANTT, WD Glossaire, WD JournalEvenement, WD ListeGraphique, WD ModeleImpression, WD PartageMemoire, WD Pays du Monde, WD photocopieur, WD Saisie assistée de répertoire, WD Saisie Email, WD Scanner, WD Select RTF, WD Table Etendue, WD Active Directory DotNet, WD JaugeFTP, WD Lecteur RSS, WD MotDePasse, WD ProxyPOP3, WD Threads FTP, WD VisuTIF, WD WMI DOTNET, WD APISystemes, WD Appels JAVA, WD Arbre Doublons, WD ContrôleADistance, WD ExtractionMIME, WD GroupwareCS, WD Impression de Tree View, WD Licence, WD ListeChaînée, WD Masque de saisie avancé, WD Onglets glissants, WD Paramètres Impressions, WD Persistance, WD Serveur RMI, WD Trace Socket, WW_DiagrammeGANTT, WW_ImagePass, WW_VitrineAWP, WW_ChangementCSS, WW_FlashParametrable, WW_Fraimes, WW_MapArea, WW_MiseEnEvidence, WW_ReassortXML, Pocket GANTT, Pocket Clavier Virtuel, Pocket ExtractionMIME, Pocket MotDePasse, Pocket Persistance, Socket Unicode.

Ndlr : je fais ce billet car je n'avais pas vu ce contenu lors de l'installation de cette LST, je me dis du coup pour me rassurer que je ne dois pas être le seul !

17 janvier 2007

Accélérer les applications sur les configurations limitées, ou en TSE

Si les applications sont toujours plus agréables de part leur aspect et leur richesse fonctionnelle, elles sont forcément plus gourmandes en ressources.

Il arrive donc que des configurations ne suivent plus, soit en raison des caratéristiques d'une station, soit en raison d'une limitation des ressources dans un contexte TSE.

Une astuce à connaître dans pareil situation, consiste à "jouer" de la propriété "..AffichageActif". Pendant toute la durée d'un traitement important (remplissage de champs, calculs...), il sera possible de "débrayer" l'affichage qui est généralement le plus couteux en temps.

Si cela n'est pas suffisant, la création d'un rapport "WPF" avec les fonctions "AnalyseurDébut" puis "AnalyseurFin" permet généralement de repérer le(s) traitement(s) à optimiser avec l'analyseur de performances (appelé également Profiler).

16 janvier 2007

Une interface personnalisée en quelques clics avec l'opacité des champs...

S'il y a bien un domaine dans lequel il est difficile de progresser lorsque l’on n’a pas la science infuse, c'est bien celui des interfaces !

Heureusement, les gabarits font une grosse partie du travail, en permettant d’avoir d’emblée une interface agréable, comme le montre l’image ci-contre avec une fenêtre au look Vista exécutée sur mon poste XP.

Mais avec quelques clics en plus, il y a moyen de se différencier du gabarit standard. En effet, l’opacité des champs permet d’apporter une touche esthétique supplémentaire. Il suffit de placer sous les champs une image piochée dans le catalogue. Une image en rapport avec le contenu de la fenêtre est vivement recommandée, ou une image type "splash screen" également proposée dans le catalogue.

Une fois l’image en place, il suffit de jouer sur son opacité, ainsi que sur celle des champs par-dessus pour obtenir un effet tout a fait convenable, et surtout sans passer par un outil de retouche d’image qui aurait nécessité de jouer de la transparence avec différents calques !

Voici un exemple de résultat, certes de piètre qualité car en cherchant une image d’une taille plus adaptée il aurait été possible de faire bien mieux, toujours en quelques clics.

A noter en astuce que le modifieur est très utile dans ce type de manœuvre pour par exemple changer l’opacité de plusieurs champs à la fois. D’interface austère, il est cependant parfaitement adapté à la manipulation des propriétés des champs de l’interface.

02 janvier 2007

Pour quelques lignes de code en moins...


Je profite de ce premier billet de l'année 2007 pour souhaiter une excellente année à ceux qui me lisent, régulièrement ou non !


Il n'est pas rare d'empiler des SI ... SINON ... FIN pour des affectations de variables, de paramètres... Il en résulte un "code à rallonge", qui même avec l'enroulé de l'éditeur code reste long à manipuler. Typiquement, l'affectation des paramètres d'une requête, lorsque certains ne doivent pas être pris en compte, exemple :

SI ChampNom <> "" ALORS
Req.ParamNom = ChampNom
SINON
Req.ParamNom = NULL
FIN

SI ChampDNaissance <> "" ALORS
Req.ParamDNais = ChampDNais
SINON
Req.ParamDNais = NULL
FIN

..

HExecuteRequete(Req)
FichierVersTableMémoire(Req, TableSélection)

L'alternative se nomme "instruction conditionnelle monoligne" (cf entrée d'aide "Condition, Instruction ?"). Beaucoup de vocabulaire pour un principe tout simple : affecter une variable par une valeur, ou par une autre, en fonction d'une condition. L'écriture ci-dessus est ainsi simplifiée à l'extrême tout en restant lisible, une fois l'habitude acquise :
Req.ParamNom = ChampNom <> "" ? ChampNom SINON NULL
Req.ParamDNais = ChampDNais <> "" ? ChampDNais SINON NULL
..
HExecuteRequete(Req)
FichierVersTableMémoire(Req, TableSélection)

22 décembre 2006

Fonctions WLangage dans le code SQL, mais également procédures stockées...

L'appel d'une fonction du WLangage dans une requête SQL est permis, mais bien évidement il est possible d'appeler une procédure stockée sur le serveur avec la même méthode.

La méthode est on ne peut plus simple :
- dans l'analyse, créer une collection de procédures, puis une fonction par le clic droit dans le volet,
- dans un traitement, appeler la fonction "HMiseAJourCollection" qui permet de copier la collection de procédures, sur le serveur.

A ce stade, il est possible d'insérer l'appel des procédures de la collection, dans les requetes SQL lancées. Exemple avec le même modèle de traitement que dans le précédent billet :

sNomFichierTXT est une chaîne = "c:\temp\commande.txt"
sListeCommande est une chaîne
sCodeSQL est une chaîne
sdReq est une Source de Données

sCodeSQL = [
SELECT ProcServeur(DateCommande) as DateCommandeformatée,
NumCommande,
TotalHT
FROM COMMANDE
]

HExécuteRequêteSQL(sdReq, sCodeSQL)

POUR TOUT sdReq
sListeCommande += [RC]+HRécupèreEnregistrement(sdReq,TAB)
FIN

fSauveTexte(sNomFichierTXT, sListeCommande)
LanceAppliAssociée(sNomFichierTXT)

La procédure "ProcServeur" aura un code WLangage qui pourra traiter la date reçue en paramètre, pour la formater différemment par exemple, ou pour la modifier en fonction de données, requêtes de la base.

Attention, dans la version en cours de WINDEV 11 je n'ai pu appeler la procédure que par la fonction "HExecuteRequeteSQL". Sauf mauvaise manipulation de ma part, l'éditeur de requêtes n'a pas encore l'air adapté à l'appel des procédures stockées.

20 décembre 2006

Fonctions Wlangage dans les requêtes Hyper File avec l'opérateur "WL." (WINDEV 11)

Le moteur Hyper File Client/Serveur propose les procédures stockées, et de ce fait permet l'appel de fonctions du Wlangage, directement dans le code SQL des requêtes !

J'ai fait quelques tests de procédures stockées, et au passage j'ai utilisé cette possibilité. Cela va simplifier bien des traitements nécessitant le formatage du résultat d'une requête, en vue d'une exportation par exemple.

Un cas typique, je dois générer un fichier texte contenant des dates / numéros / montants de commandes. La date doit être lisible, et non pas au format "AAAAMMJJ" utilisé pour le stockage et l'affectation des champs ou colonnes de type date des interfaces.

Le résultat peut être obtenu immédiatement dans la requête, ce qui évite un traitement des données lors du parcours qui suit la requête.

Voici un exemple utilisant cette possibilité (il s'agit du code de l'image de ce billet) :

sNomFichierTXT est une chaîne = "c:\temp\commande.txt"
sListeCommande est une chaîne
sCodeSQL est une chaîne
sdReq est une Source de Données

sCodeSQL = [
SELECT WL.DateVersChaine(DateCommande) as DateCommandeformatée,
NumCommande,
TotalHT
FROM COMMANDE
]

HExécuteRequêteSQL(sdReq, sCodeSQL)

POUR TOUT sdReq
sListeCommande += [RC]+HRécupèreEnregistrement(sdReq,TAB)
FIN

fSauveTexte(sNomFichierTXT, sListeCommande)
LanceAppliAssociée(sNomFichierTXT)
A noter qu'il est possible de donner un formatage spécifique à la date avec le code SQL suivant :
sCodeSQL = [
SELECT WL.DateVersChaine(DateCommande,'JJJ JJ MMM AAAA') as DateCommandeformatée,
NumCommande,
TotalHT
FROM COMMANDE
]
Le fichier généré aura les dates dans un format "Ven. 28 Jan. 2000" par exemple.

Ndlr : la requête est volontairement simpliste pour l'illustration, elle permet dans un cas réel une sélection de données. Ce qui est très intéressant, c'est le code d'exportation qui est simplifié à l'extrême, et qui dit code simple, dit code plus rapide avec un risque d'erreur de programmation moindre !

19 décembre 2006

Nouveau site WINDEV : Ed4u

Apparition d'un nouveau site de ressources WINDEV : Ed4u. Peu d'informations dans l'immédiat, le site basé sur un CMS vient d'être publié ces derniers jours c'est donc un peu tôt. Les auteurs semblent cependant très motivés, je leur souhaite de réussir dans leur projet !

15 décembre 2006

Exécuter une action lors du tri d'une colonne de table

Il est fréquent de devoir effectuer une action lorsque l'utilisateur trie les données d'une table. Une capture d'événement était requise jusqu'à la version 10, ce sujet a été fréquement abordé sur le forum. Le code nécessaire se trouve ci-dessous.

Il est cependant rendu obsolète, puisque WINDEV 11 permet d'ajouter aux colonnes un code "à chaque tri" !







//1. Code d'initialisation de la table :
Evenement("TRISPECIAL","TABLE1", 1529)

//2. Procédure TRISPECIAL
Procédure TRISPECIAL()
// _eve.wParam contient le numéro de la colonne
Trace("On a cliqué sur l'entête de la colonne n° "+_eve.wParam )
SI _eve.wParam = 2 ALORS
//On veut que la procédure TRISPECIAL permet d'obtenir un tri sur
//la colonne COL2 puis sur la colonne COL1:

// Annuler le tri automatique
_eve.retour = 0
tabletri("COL2"+TAB+"COL1")
FIN
Ndlr : ce code a pour origine un message du support.