IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

Différence de format de String entre une StringGrid.Cells[aCol,aRow]et un array_of_String[aRow] [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Invité
    Invité(e)
    Par défaut Différence de format de String entre une StringGrid.Cells[aCol,aRow]et un array_of_String[aRow]
    Bonjour,

    Je transforme une image en String (normalement AnsiString) mais une déclaration String suffit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function TmySQLtoSGtoSQL.SQLBlobToStr(aQuery : TZQuery; aField : TField) : String;
    {public}
    {String or AnsiString ?}
    var
      aStream : TMemoryStream;
    begin
     Result := '';
     with aQuery do
      if not(aField.isNull) then begin
       try
        aStream := TMemoryStream.Create;
        TBlobField(aField).SaveToStream(aStream);
        Result := MemStreamToString(aStream);
       finally
        aStream.Free;
       end;
      end;
    end;
    Puis réciproquement la String en Image
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    function TmySQLtoSGtoSQL.StrBlobToImage(aStr : String; aImage: TImage): Boolean;
    var
       aStream : TMemoryStream;
    begin
     Result := False;
     if aStr <> '' then
      try
       aStream := TMemoryStream.Create;
       try
        if StringToMemStream(aStr, aStream) then begin
         aStream.Position := 0;
         aImage.Picture.LoadFromStream(aStream);
         Result := True;
        end;
       except
        Result := False;
       end;
      finally
       aStream.Free;
      end;
    end;
    Un test "ordinaire" fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    {sTmp : String;}
    with mySQLtoSGtoSQL1 do begin
      //Envoi du Field SQL ds une chaine
         sTmp := SQLBlobToStr(ZQueryLOCK,Fields[ca_caLOGO]);
       //Envoi d'une chaine dans l'image;
          if sTmp <> '' then StrBlobToImage(sTmp, Image1);
     end;
    Maintenant, si je place mes sTmp dans des cellules d'une TStringGrid cela ne fonctionne plus. Pour que cela fonctionne, il faut que j'associe mes sTmp dans un aArray (array of string). Je suis en {$mode objfpc}{$H+}
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    with mySQLtoSGtoSQL1 do begin
       StrBlobToImage(aArray[iRow], Image1); {OK}
       StrBlobToImage(Cells[sg_caLOGO, iRow], Image2); {No !!!!!!!!!}
    end;
    Les TStringGrids.Cells[aCol, aRow] ne sont pas des String de même nature que les aArray[aRow] ?
    Un Showmessage( IntToStr(length(aArray[iRow]))+'-'+IntToStr(length(Cells[sg_caLOGO, iRow]))); renvoie 1010-8 donc le remplissage de Cells avec la même méthode que l'array[aRow] ne fonctionne pas. J'en déduis -peut-être bêtement- que la nature des String n'est pas identique. Est-ce un raisonnement erroné ? Je précise que dans le TStringGrid, j'utilise des TColumns dont j'ai modifié la MaxSize... au cas où... mais sans succès.

    Une bonne âme peut m'expliquer ?


    Cordialement. Gilles
    Dernière modification par Invité ; 05/11/2011 à 12h16. Motif: Précisions

  2. #2
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 786
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 786
    Points : 5 918
    Points
    5 918
    Par défaut
    Bonjour,
    En remontant le code source de la Classe TStringGrid, je constate pour la propriété Cellls est définie dans TCustomStringGrid et que le code de l'accesseur est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function TCustomStringGrid.Getcells(aCol, aRow: Integer): string;
    var
       C: PCellProps;
    begin
      Result:='';
      C:=FGrid.Celda[aCol,aRow];
      if C<>nil then Result:=C^ .Text;
    end;
    et le type PCellProps
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      PCellProps= ^TCellProps;
      TCellProps=record
        Attr: pointer;
        Data: TObject;
        Text: pchar;
      end;
    Un String d'un côté et un PChar de l'autre, l'explication viendrait-elle de là ?
    --
    Philippe.

  3. #3
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 879
    Points : 11 377
    Points
    11 377
    Billets dans le blog
    6
    Par défaut
    as-tu un #0 en 9° position de ton image ?

    si ça vient bien de là, pour contourner le problème, il te faudra peut-être caster en PByte à condition de stocker la taille en tête des données, sans #0 ! ou coder en Base64 ou autre, pour éviter les #0...

    si tu stockes le type de la donnée ailleurs, pourquoi ne pas loger directement un TmemoryStream en Object de la cellule, voire dans sa chaîne, et te passer de la conversion en string ?

  4. #4
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 879
    Points : 11 377
    Points
    11 377
    Billets dans le blog
    6
    Par défaut
    autre possibilité, du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if Pos('This is a zero', sTmp)=0
    then sTmp := StringReplace(sTmp, #0, 'This is a zero', [rfReplaceAll]);
    et inversement en sortie...

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    merci à tous deux pour vos réponses.
    Je ne vais pas dire "j'aurais dû y penser". J'ai donc fait une petite révision. J'ai tenté vos 2 approches et dans les 2 cas, je n'ai pas réussi.

    Je vais rester avec mon Array qui est devenu une Record finalement pour gérer aussi bien ce problème d'images que le problème de la pseudo-multiselection dans ma StringGrid, le traitement en cas de suppression, mouvement (ou tri) ou insertion de lignes étant commun.

    Merci beaucoup.
    Cordialement. Gilles
    Dernière modification par Invité ; 07/11/2011 à 12h07.

  6. #6
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 879
    Points : 11 377
    Points
    11 377
    Billets dans le blog
    6
    Par défaut
    Cet exemple fonctionne chez moi pour stocker et restituer une chaîne contenant 1 ou plusieurs #0 dans une cellule de StringGrid. Mais ça ne répond pê pas à toutes tes problématiques :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
      with TStringGrid.Create(nil) do
      try
        RowCount:=3;
        ColCount:=5;
        S:='Seul'#0' ou pas ?';
        ShowMessage(IntToStr(Length(S)));
        Cells[2, 1]:=S;
        ShowMessage(IntToStr(Length(Cells[2, 1])));
        if Pos('This is a zero', S)=0
        then S := StringReplace (S, #0, 'This is a zero', [rfReplaceAll]);
        Cells[2, 1]:=S;
        ShowMessage(IntToStr(Length(Cells[2, 1])));
        if Pos('This is a zero', S)>0
        then S := StringReplace (S, 'This is a zero', #0, [rfReplaceAll]);
        ShowMessage(IntToStr(Length(S)));
      finally
        Free

  7. #7
    Invité
    Invité(e)
    Par défaut
    Bonjour Toulourou,

    Désolé de ne pas avoir été plus précis. Pour les pointeurs, je n'ai pas réussi. Je suis un peu embarrassé entre les explications qui me semblent fondées de Ph. B. et la technique des pointeurs que je n'arrive pas à appliquer aux Cells. C'est en contradiction avec l'hypothèse de départ... ou je m'y prends probablement mal : j'ai noté sur mon cahier. Je reverrai cela plus tard... sinon je vais perdre le fil de ma boucle de développement actuel.

    Pour votre code, techniquement il fonctionne... MAIS, les StringReplace sont d'une grande lenteur. Et tout mon projet repose sur la fluidité.

    Comme j'ai un petit creux de mon emploi du temps, compte tenu du temps que vous voulez bien m'accorder, je vous décris un peu le "cadre" de mes problèmes : j'essaye de développer en Lazarus, un logiciel de gestion de mon Etablissement Scolaire, logiciel dont la base est distante (hébergée). C'est une réécriture. J'ai développé ce projet, il y a quelques années en Windev 7.5, langage que j'ai abandonné depuis. Cette version tourne toujours d'ailleurs dans l'établissement. La seule insatisfaction exprimée est les temps d'attente... qui ne sont pas vraiment longs mais qui pénalisent la fluidité. Je me suis dit qu'avec un langage compilé, on devait pouvoir résoudre ce problème. C'est un projet commencé en Lazarus 0.9.26 avec ses horribles StringGrids dont la gestion des colonnes invisibles était impossible à l'époque. Ce projet n'a rien de stratégique pour mon établissement car l'autre version continue à fonctionner. Il me permet "simplement" de me faire plaisir avec un langage que j'affectionne, le Pascal, et surtout dans deux environnements que j'apprécie autant l'un que l'autre, Windows et Linux.

    La fluidité est donc le principal challenge avec la version que j'essaye de développer en Lazarus. Cette réduction des temps d'attente est le facteur prioritaire après la solidité : "donner la fluidité que l'on aurait si on utilisait une base locale". Donc par exemple, l'accès aux tables de la base se fait en 2 temps : un accès "direct" disons des 100 premiers enregistrements (LIMIT 100). A ce moment, l'utilisateur peut tout faire (insertion, correction, suppression) sauf trier. Accès direct complété en parallèle par un accès threadé (LIMIT OFFSET en mySQL ou OFFSET en postgreSQL) qui une fois terminé, active la possibilité des tris sur les colonnes. Là, Lazarus est irréprochable... à condition de ne pas faire cela avec les DataSet-->dbGrid usuels. De par leur construction, cette "chaîne" n'est pas threadable... J'ai donc fait ceci avec un simple couple DataSet<-->TmyStringGrid. La prochaine étape serait de lier la StringGrid directement à un Dataset quelconque d'où une question récente sur la question des DataSets génériques. On obtiendait ainsi une "dbStringGrid" threadable, multiselect, triable... Mais chaque chose en son temps. Pour l'instant, l'accès threadé me donne satisfaction.

    Là, j'en suis au "Strombisnoscope" des élèves. Les photos sont stockées dans des Blobs de la base... Je sais que certains vont pousser des cris (stocker des images dans une BDD ), comme d'ailleurs pour le couple DataSet <-->TmyStringGrid et le fait de charger toute la table (re )... Mais comme c'est aussi dynamique qu'une simple vue, je ne vois pas pourquoi je m'en priverais. Pour les images, reste le ftp. Or ce que j'ai réussi à faire avec l'association base+ftp (même threadée) est vraiment lent par rapport au seul accès threadé à la base contenant les images : en effet, pour la première solution (BDD+ftp), il faut bien à un moment, dans la Form, synchroniser la base avec le ftp... En plus je ne suis pas satisfait des composants Indy qui plantent aléatoirement lorsque le nombre d'accès est important... (Ils chauffent ? ). Synapse convient mieux. Mais la combinaison est surclassée par le seul accès à la BDD si je place mes images en elle.

    Bref, pour en revenir à notre problème, le remplacement ne permet pas avec votre méthode la fluidité de la roulette de la souris si par exemple je veux afficher l'image dans un Timage extérieur à la StringGrid. Or, comme je l'ai expliqué, j'y tiens. Alors évidemment, si seulement le 9ème caractère est concerné, on peut limiter le StringReplace au 9ème... mais qu'est-ce qui me garantit qu'il est le seul... On refait une boucle 'tant que' pour éliminer séquentiellement dans chaque Cells les #0 ? C'est envisageable...

    Donc, encore une fois, merci pour votre aide.
    Bonne journée. Gilles
    Dernière modification par Invité ; 08/11/2011 à 10h18.

  8. #8
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 879
    Points : 11 377
    Points
    11 377
    Billets dans le blog
    6
    Par défaut
    Je comprends bien le besoin de vitesse.
    Pour le StringReplace, je ne sais pas combien de temps ça prend, mais le rfReplaceAll permet de remplacer toutes les occurrences en une seule passe.
    Mais pour gagner du temps, pourquoi ne pas garder les TMemoryStreams ? C'est pê d'ailleurs votre dernière approche. Ou directement des TImage, ce qui ne doit pas être très pénalisant si les images restent petites et qu'il n'y en a que quelques centaines, style vignettes de photos.
    [EDIT] il y a même les TListImage, faits pour ça, non ?

  9. #9
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Je n'affiche pas les images dans la StringGrid mais un simple indicateur : image ou pas (petite image affichée par le OndrawCell). Je voulais simplement initialement stocker le blob dans une Cell. Par contre, la "fiche" des élèves (un TPanel) est placée sous la StringGrid, et lorsqu'une ligne est sélectionnée (voire j'espère bientôt survolée), la fiche est mise à jour (y compris l'image qui est incluse dans ce Panel).

    Mais le Record est une solution qui répond à tous mes critères sauf la simplicité de programmation. C'est pourquoi, la Cells me convenait mieux au départ. Cependant, je vais affiner cette approche avec StringReplace et essayer de comprendre quel rapport il y a exactement entre les Cells et les PChar. Pour le TlistImage, non. Je veux qu'à terme, ma StringGrid soit autonome. Je dois resserrer (factoriser et agréger) mes codes sinon la couche "métier" est envahie par des rustines de corrections ou d'améliorations des composants. Le record semble indispensable pour d'autres fonctions. Il faut que je regarde l'approche avec un "TanObject" suggéré par Mick605 sur ce forum pour un autre sujet. Incorporé dans la TmyStringGrid un TListImage me semble trop "gourmand".


    Cordialement. Gilles
    Dernière modification par Invité ; 08/11/2011 à 10h29.

  10. #10
    Invité
    Invité(e)
    Par défaut
    Bon,

    intrigué quand même, j'ai poursuivi un peu mon effort. En combinant, vos 2 remarques, j'en arrive à cela :

    Cells n'est pas un Pchar : StrPas(Cells[sg_caLOGO, iRow]) renvoie l'erreur Error: Incompatible type for arg no. 1: Got "AnsiString", expected "PChar". (cf StrPas). Donc c'est bien une String.

    Par contre le remplissage de la Cells se ferait en utilisant les pChar ?... Il aurait en tous cas recours à une chaîne C (ASCIIZ) (qui se termine par #0 cf cet article partie B. Les chaînes C).

    Donc quand la Cells se remplit au premier caractère #0 rencontré, le processus de remplissage l'identifie comme une fin de chaîne. Chez moi en 9ème position, d'où le length(Cells[]) = 8;

    La procédure de Toulourou (trop lente) permet au moment du remplissage de la Cells de la remplir "complètement" en remplaçant le(s) #0, point(s) d'arrêt, par des caractères anodins.

    Enfin, c'est ce que je comprends.

    Bref, il faudrait une méthode pour remplacer les #0 plus rapidement que StringReplace qui est réputée pour sa lenteur. Il existe bien des procédures beaucoup plus rapides d'échange de chars (et pas de string) mais quel char de remplacement utiliser, char dont on sera sûr qu'il n'existera pas dans la chaîne initiale ?

    Cordialement.
    Gilles.
    Dernière modification par Invité ; 08/11/2011 à 15h42.

  11. #11
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 879
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 879
    Points : 11 377
    Points
    11 377
    Billets dans le blog
    6
    Par défaut
    quel est le format des images stockées dans la base ?

    je ne vois pas d'alternative rapide au StringReplace...

    ma seule idée (célérité à tester) est de transformer le flux image en Base64, comme dans un mail

  12. #12
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    A priori, avis d'un autre lazarusien sur un forum anglosaxon, le chargement d'une chaîne avec caractère NULL n'est pas envisageable directement
    Ultimately the drawing of the text is done by (a call to) the widgetset, and they all use C-style strings, so they will treat #0 as end of string.
    Mais pourquoi utiliser des chaines C pour remplir une String dans une String ?

    Bon, je passe par un Record que j'ai intégré à mon composant. Je n'ai pas réussi à utiliser le TObject associé à chaque cellule. Je me suis d'ailleurs demandé pourquoi on n'associait pas (ou on n'avait pas laissé la possibilité d'associer) un TObject à la ligne qui dans mon cas serait plus adapté.

    Cordialement. Gilles
    Dernière modification par Invité ; 10/11/2011 à 13h54.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Calcul pourcentage de différence entre string d'une liste
    Par crunchy63 dans le forum Général Python
    Réponses: 3
    Dernier message: 01/02/2013, 14h41
  2. Réponses: 6
    Dernier message: 14/07/2007, 11h36
  3. [JBoss]Différence entre une DataSource et une XADataSource ?
    Par lalakers dans le forum Wildfly/JBoss
    Réponses: 2
    Dernier message: 03/10/2005, 11h18
  4. Réponses: 2
    Dernier message: 25/05/2005, 21h34
  5. [Debutant]Formater un string pour une url
    Par maxxou dans le forum Entrée/Sortie
    Réponses: 3
    Dernier message: 22/03/2004, 16h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo