Le forum (ô combien francophone) des utilisateurs de Powerbuilder.
Bonjour,
J'ai un fichier texte à transformer en datawindow pou pouvoir le manipuler. l'idée est d'utiliser importfile() mais le problème c'est que je ne connais pas la taille des colonnes qu'il faut avoir dans la datawindow car je n'ai aucune idée sur le nombre de colonnes dans mon fichier.
Donc je dois créer une datawindow "dynamique" si possible ou bien ou datawindow avec un nombre très grand de colonnes. (exemple 200).
Est ce qu'il y a un moyen de le faire dynamiquement?
Dernière modification par zeineb (18-04-2013 16:37:00)
Hors ligne
C'est du texte avec des "colonnes" à largeur fixe, ou délimité (par des virgules, des tabulations ou autres) ?
Il est possible de fabriquer dynamiquement la syntaxe d'une datawindow, une fois qu'on a déjà analysé le fichier pour déterminer le nombre des colonnes.
Exemple de code pour fabriquer une dw :
public function string generate_dw_syntax (string as_colnames[], string as_labels[], string as_types[]); // string ls_syntax, ls_syntaxheader, ls_syntaxfooter, ls_coldecl, ls_textdecl, ls_vcolumndecl, ls_tmp int i, max long xpos[], widths[] unvo_gdi gdi constant long WINDOW_TEXT = 33554432 ls_syntaxheader = 'release 10.5;& datawindow(units=0 timer_interval=0 color=1073741824 processing=1 HTMLDW=no print.printername="" print.documentname="" print.orientation = 0 print.margin.left = 110 print.margin.right = 110 print.margin.top = 96 print.margin.bottom = 96 print.paper.source = 0 print.paper.size = 0 print.canusedefaultprinter=yes print.prompt=no print.buttons=no print.preview.buttons=no print.cliptext=no print.overrideprintjob=no print.collate=yes print.preview.outline=yes hidegrayline=no grid.lines=0 grid.columnmove=no )& header(height=80 color="536870912" )& summary(height=0 color="536870912" )& footer(height=0 color="536870912" )& detail(height=72 color="536870912" )~r~n& table(' ls_syntaxfooter = 'htmltable(border="1" )& htmlgen(clientevents="1" clientvalidation="1" clientcomputedfields="1" clientformatting="0" clientscriptable="0" generatejavascript="1" encodeselflinkargs="1" netscapelayers="0" pagingmethod=0 generatedddwframes="1" )& xhtmlgen() cssgen(sessionspecific="0" )& xmlgen(inline="0" )& xsltgen()& jsgen()& export.xml(headgroups="1" includewhitespace="0" metadatatype=0 savemetadata=0 )& import.xml()& export.pdf(method=0 distill.custompostscript="0" xslfop.print="0" )& export.xhtml()' ls_coldecl = 'column=(type=$type updatewhereclause=yes name=$name dbname="$name")~r~n' //dbname="chaine" ls_textdecl = 'text(band=header alignment="2" text="$text" border="6" color="$color" x="$xpos" y="8" height="64" width="$width" html.valueishtml="0" name=$name_t visible="1" font.face="Tahoma" font.height="-8" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="2" background.color="67108864" )~r~n' ls_vcolumndecl = 'column(band=detail id=$id alignment="$align" tabsequence=$tabseq border="0" color="33554432" x="$xpos" y="0" height="68" width="$width" format="[general]" html.valueishtml="0" name=$name visible="$visible" background.transparency="$trans" edit.limit=0 edit.case=any edit.focusrectangle=no edit.autoselect=yes edit.autohscroll=yes edit.displayonly=yes font.face="Tahoma" font.height="-10" font.weight="400" font.family="2" font.pitch="2" font.charset="0" background.mode="1" background.color="$backc" )~r~n' ls_syntax = "" append(ls_syntax, ls_syntaxheader) //declaration des "DB" colonnes max = upperbound(as_colnames) for i = 1 to max ls_tmp = replace_all(ls_coldecl, "$type", as_types[i], true) ls_tmp = replace_all(ls_tmp, "$name", as_colnames[i], true) append(ls_syntax, ls_tmp) next append(ls_syntax, ")~r~n") //liste des headers for i = 1 to max ls_tmp = replace_all(ls_textdecl, "$name", as_colnames[i], true) ls_tmp = replace_all(ls_tmp, "$text", as_labels[i], true) ls_tmp = replace_all(ls_tmp, "$color", iif(as_colnames[i]=EXTRA_COL,"255", "33554432"), true) if i = 1 then xpos[i] = 1 else xpos[i] = xpos[i - 1] + widths[i - 1] end if widths[i] = gdi.of_getstringwidthunits(this, as_labels[i] + "MM", "Tahoma", 8, false, false) ls_tmp = replace_all(ls_tmp, "$xpos", string(xpos[i]), true) ls_tmp = replace_all(ls_tmp, "$width", string(widths[i]), true) append(ls_syntax, ls_tmp) next //liste des colonnes "visibles" for i = 1 to max ls_tmp = replace_all(ls_vcolumndecl, "$id", string(i), true) ls_tmp = replace_all(ls_tmp, "$tabseq", string(i*10), true) ls_tmp = replace_all(ls_tmp, "$align", iif(left(as_types[i],4)="char" or left(as_types[i],4)="date", "0", "1"), true) ls_tmp = replace_all(ls_tmp, "$trans", iif(as_colnames[i]=EXTRA_COL, "0", "0~tif(isnull($name),1,0)"), true) ls_tmp = replace_all(ls_tmp, "$backc", iif(as_colnames[i]=EXTRA_COL, "536870912", "536870912~tif(isnull($name),255,536870912)"), true) ls_tmp = replace_all(ls_tmp, "$visible", iif(as_colnames[i]=EXTRA_COL, "0", "1"), true) ls_tmp = replace_all(ls_tmp, "$name", as_colnames[i], true) ls_tmp = replace_all(ls_tmp, "$xpos", string(xpos[i]), true) ls_tmp = replace_all(ls_tmp, "$width", string(widths[i]), true) append(ls_syntax, ls_tmp) next append(ls_syntax, ls_syntaxfooter) return ls_syntax end function
Remarques :
- Avant d'appeler la fonction, on a déjà trituré les données pour connaître le nombre et le type des colonnes et leur entête et on les passe en argument.
- Les fonctions replace_all(), append(), iif() sont des fonctions outils dans le projet pour remplacer du texte, ou ajouter à une chaine (append() est une "fastfunc" de Jeremy Lakeman) et iif() retourne le 2e ou 3e argument en fonction de la condition, ça simplifie la lecture du code
- "EXTRA_COL" est une valeur particulière de notre traitement qui prévoit d'afficher différemment des colonnes qui seraient "en trop" par rapport à une liste prédéfinie
- of_getstringwidthunits() est une fonction remappée sur l'api windows qui permet de savoir la taille en pixels d'une chaîne en fonction de la police utilisée, de sa taille et du style (gras, italique), je peux la publier aussi au besoin.
La syntaxe fabriquée est utilisée comme cela pour l'associer au contrôle datawindow :
ls_syntax = generate_dw_syntax(is_data_fields[], ls_hlabels[], ls_htypes[])
lb_ret = dw_data.create(ls_syntax) = 1
Dernière modification par seki (12-04-2013 11:35:10)
Hors ligne
En fait le fichier vient d'une datawindow à laquelle on a appliqué la méthode saveas() donc je pense que le séparateur est une tabulation.
Hors ligne
je vais essayer de comprendre ce code et l'adapter à mon besoin.
Merci beaucoup
Hors ligne
pour aider à comprendre le code, il peut être utile de se créer une petite DW (grid par exemple) de type "external", d'y mettre quelques colonnes de types différents et de regarder ce que ça donne dans "edit source"
Il y a plusieurs parties dans une DW
- un entête (avec la version est divers réglages de la dw, comme les couleurs, unités, sections, ...
- la liste des colonnes avec leurs types (comprendre colonnes dans le sens base de données, pas colonnes visibles) si c'est une dw basée sur une reqête, on a la liste des colonnes sélectionnées)
- en dessous on a la requête si c'est une dw basée sur une requête, si c'est une external on n'est pas concerné
- en dessous on a la liste des contrôles visibles : entêtes et colonnes, l'ordre n'est pas important mais une chose est à respecter rigoureusement (sous peine de comportement bizarre et / ou plantages) : pour un objet "column" doit avoir la propriété "id" égale au numéro de colonne dans la liste au début de la DW
Ici mon code :
- commence par utiliser un entête préconstruit (récupéré dans un "edit source") = variable ls_syntaxheader
- ajoute une liste de colonnes avec leur type (calculé avant l'appel à la fonction et donné dans les tableaux en argument) avec la variable ls_coldecl comme modèle
- ajoute la liste des entêtes de colonnes avec la variable ls_textdecl comme modèle
- ajoute la liste des colonnes avec la variable ls_vcolumndecl comme modèle
- ajoute un code "footer" qui ne bouge pas, repris aussi d'un "edit source"
Les variables "modèles" sont comme des templates de code : comme il faut répéter la même syntaxe pour chaque déclaration de colonne, entête et colonne, j'ai écrit une fois le texte dans lequel je remplace les $variables par leur véritable valeur (juste pour les id, position, nom, ... les autres propriétés sont identiques
Hors ligne
Les fonctions replace_all(), append(), iif() et la variable "EXTRA_COL" me donnent des erreurs du genre "unknown function name ou undefined variable". ainsi que unvo_gdi.
sachant que j'utilise la version 11.5 de power builder comment je peux corriger cela?
Hors ligne
Pour iif() et replacall() (à renommer en replace_all()), voir ici
Pour une implémentation simple (=naïve) de append :
global type append from function_object end type forward prototypes global subroutine append (ref string as_dest, string as_added) end prototypes global subroutine append (ref string as_dest, string as_added); as_dest += as_added end subroutine
et pour le calcul de la taille des chaînes, il y a une structure, quelques prototypes et constantes à définir en plus de 2 fonctions getstringwidth() et getstringwidthunits() à ajouter dans l'objet ou fenêtre et enlever le "unvo_gdi.":
type st_size from structure long cx long cy end type Function ULong GetDC(ULong hWnd) Library "User32.DLL" Function ULong ReleaseDC(ULong hWnd, ULong hDC) Library "User32.DLL" Function Ulong SelectObject (Ulong hDC, Ulong hObject) Library "gdi32.dll" FUNCTION ulong DeleteObject(ulong hObject) LIBRARY "gdi32.dll" function long MulDiv(long nNumber, long nNumerator, int nDenominator) library "kernel32.dll" Function ulong CreateFont(long nHeight,ulong nWidth,ulong nEscapement,ulong nOrientation,ulong fnWeight,boolean fdwItalic,boolean fdwUnderline,boolean fdwStrikeOut,ulong fdwCharSet,ulong fdwOutputPrecision,ulong fdwClipPrecision,ulong fdwQuality,ulong dwPitchAndFamily,ref string lpszFace) LIBRARY "gdi32.dll" ALIAS FOR "CreateFontW" Function ulong GetDeviceCaps(ulong hdc,ulong nIndex) library "gdi32.dll" Function Boolean GetTextExtentpoint32(ULong hdc, string lpString, int cbString, ref ST_SIZE lpSize) library "gdi32.dll" alias for "GetTextExtentPoint32W" constant integer FW_NORMAL = 400 constant integer FW_BOLD = 700 constant ulong DEFAULT_CHARSET = 1 //(x01) constant ulong LOGPIXELSX = 88 //Number of pixels per logical inch along the screen width. public function long of_getstringwidth (window aw_parent, string as_text, string as_fontname, integer ai_size, boolean ab_bold, boolean ab_italic);// computes the width in pixels of a string as drawn in the specified font ulong ll_handle, ll_hdc, ll_hdcbis ulong ll_hfont ulong weight long height long width = -1 st_size size ll_handle = handle(aw_parent) ll_hdc = GetDC(ll_handle) // create the specified font if ab_bold then weight = FW_BOLD else weight = FW_NORMAL // compute the height using the display device physical properties height = -MulDiv(ai_size, GetDeviceCaps(ll_hdc, LOGPIXELSX), 72) ll_hfont = CreateFont( height, 0, 0, 0, weight, ab_italic, false, false, 0, DEFAULT_CHARSET, 0, 0, 0, as_fontname) // use that font for the device context SelectObject(ll_hdc, ll_hfont) if GetTextExtentPoint32(ll_hdc, as_text, len(as_text), size) then width = size.cx + 1 //add 1 is better, look trhough MSDN for clues ;o) end if DeleteObject(ll_hfont) ReleaseDC(ll_handle, ll_hdc) return width end function public function long of_getstringwidthunits (window aw_parent, string as_text, string as_fontname, integer ai_size, boolean ab_bold, boolean ab_italic);// computes the size in pixels of a string as drawn in the specified font // returns a result in PB units long width = -1 width = of_getstringwidth(aw_parent, as_text, as_fontname, ai_size, ab_bold, ab_italic) width = PixelsToUnits(width, XPixelsToUnits!) return width end function
Pour EXTRA_COL, il suffit d'ajouter un "constant string EXTRA_COL = 'toto' " pour que la syntaxe soit juste, c'est une constante qui sert dans le projet d'où est extrait le code, il suffit de supprimer ce qui ne sert pas.
Hors ligne
J'ai implémenté toutes ces fonctions, jusqu'à là tous va bien mais quand j'ai fait :
ls_syntax = generate_dw_syntax(is_data_fields[], ls_hlabels[], ls_htypes[])
(avec le deboggeur j'ai vérifié que ls_syntax est bien correcte)
lb_ret = dw_data.create(ls_syntax)
ça compile bien mais j'obtiens une erreur lors de l'éxecution.
j'ai enlevé tous ce qui est graphique et je n'ai laissé que l'entete, ma table mais c'est pareil.
Dernière modification par zeineb (16-04-2013 10:46:18)
Hors ligne
C'est une erreur "boum", ou il y a un message compréhensible ?
A la ligne du dw.create(), lb_ret = true ? si non c'est que la syntaxe est incorrecte quelque part (il y a peut-être une $variable qui n'a pas été remplacée ?)
Hors ligne
l'application crashe tout simplement.
j'ai pris ls_syntax et je l'ai mise dans l'edit source d'une datawindow ça ne donne pas d'erreur.
donc je pense que l'erreur ne viens pas de ls_syntax mais plutot de la methode create.
Dernière modification par zeineb (16-04-2013 13:11:45)
Hors ligne
j'ai ajouté cette ligne : dw_check = create datawindow
ça ne crashe plus mais ça retourne -1
Hors ligne
Bonjour,
pour remédier à ce problème j'ai opté pour une datastore au lieu d'une datawindow.
je n'ai plus le problème du -1
Hors ligne
Tu ne peux pas faire dw_check = create datawindow car la dw est un objet visuel
à la rigueur tu peux faire openuserobject(dw_check) mais je pense que tu n'en a pas besoin non plus car tu as surement déjà "posé" ta DW sur ta Window.
à mon avis tu voulais plutôt faire
dw_check.create( ls_syntax, ls_errors )
Hors ligne
oui exactement j'ai fait dw_check.create( ls_syntax, ls_errors ) mais ça ne marche que dans le cas d'une datastore
Hors ligne
zeineb a écrit:
j'ai ajouté cette ligne : dw_check = create datawindow
ça ne crashe plus mais ça retourne -1
Mais... Pourquoi créer une datawindow avec create ? Il n'y a pas de contrôle datawindow (= d'objet visuel datawindow) dans la fenêtre ?
zeineb a écrit:
oui exactement j'ai fait dw_check.create( ls_syntax, ls_errors ) mais ça ne marche que dans le cas d'une datastore
Ben non, ici ça fonctionne avec une datawindow, le problème est ailleurs.
Récapitulons :
1 - dans la fenêtre on ajoute un contrôle datawindow en plus du reste (boutons, ...); on voit un rectangle vide
2 - on ne configure pas de dataobject pour cette datawindow (alors que dans le cas normal on associe un objet "datawindow" à un contrôle visuel "datawindow" (ce ne sont pas les mêmes objets ) ) en passant par la propriété "dataobject"
3 - on ne fait pas non plus de "create" car la création du contrôle a déjà été fait par pb à l'ouverture de la fenêtre (quand il remplit le tableau "controls", pour le vérifier il suffit de faire "edit source" sur la fenêtre et de chercher "on create" de la fenêtre)
4 - on traite le fichier pour en extraire la liste et le type des colonnes
5 - on appelle la fonction qui fabrique la syntaxe de la datawindow grid à partir des tableaux de paramètres
6 - la syntaxe est utilisée sur le contrôle datawindow avec dw.create(syntaxe) ATTENTION de ne pas confondre la méthode "create" de la datawindow qui permet de la construire à partir d'une syntaxe et l'instruction "create" du pbscript pour allouer un nouvel objet (ici c'est fait automatiquement)
Comme a dit rincevent, ce qui devrait être pratique c'est d'utiliser "dw_check.create( ls_syntax, ls_errors )" qui permet de récupérer une éventuelle erreur au lieu du simple "-1" indiquant que ça cafouille.
Hors ligne
zeineb a écrit:
oui exactement j'ai fait dw_check.create( ls_syntax, ls_errors ) mais ça ne marche que dans le cas d'une datastore
Je t'assure que je fais ça sur des DW's des milliers de fois par jour et que ça fonctionne très bien (à condition d'avoir une syntaxe correcte bien sûr)
Dernière modification par rincevent (18-04-2013 12:08:36)
Hors ligne
Ah j'ai oublié de mentionner le fait que ma datawindow n'est pas liée à une window!
Hors ligne
zeineb a écrit:
Ah j'ai oublié de mentionner le fait que ma datawindow n'est pas liée à une window!
euh, elle est liée à quoi ?
Hors ligne
bein elle me sert à stocker des données d'une manière temporaire.
je l'ai créé dans le clicked d'un bouton qui est sensé faire des traitements sur ces données.
Hors ligne
donc un datastore suffit...
Hors ligne
Si les données sont temporairement en mémoire et n'ont pas besoin d'être visualisées, alors le code du début de discussion qui génère la syntaxe peut-être simplifiée (sur les calculs de couleur), et surtout il n'y a aucun intérêt à appeler of_getstringwidthunits pour calculer des largeurs visibles : on peut avoir chaque colonne avec une largeur de 42 (valeur choisie arbitrairement).
Hors ligne
Oui tout ce qui est graphique je peux m'en passer.
@rincevent oui je viens de modifier mon code( j'ai créé une window, je lui est attaché une datawindow ) et ça marche.
Hors ligne