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

Composants VCL Delphi Discussion :

Rafraichir un StringGrid à partir d'un thread


Sujet :

Composants VCL Delphi

  1. #1
    Membre éclairé
    Avatar de iubito
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2003
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2003
    Messages : 389
    Points : 655
    Points
    655
    Par défaut Rafraichir un StringGrid à partir d'un thread
    Salut,

    j'ai un thread qui tourne en boucle pour scruter un répertoire où il a des fichiers à traiter.

    Le programme principal crée un fichier à traiter, puis insère une ligne dans un StringGrid juste pour information.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ID | nom du fichier | état
     1 | fichier1.pdf   | En attente
    La boucle de mon thread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    - repère la ligne du StringGrid, on l'appellera index
    - maForm.monGrid.cells[index, 2] = 'Traitement en cours...'
    - fait le traitement
    - maForm.monGrid.cells[index, 2] = 'OK'
    - sleep 1 seconde
    - supprime la ligne n° index
    Problème : mon StringGrid n'est jamais rafraichi !!! Il reste immobile, seule le programme principal y ajoute des lignes, tout ce que fait le thread c'est du vent.

    j'ai beau ajouter des maForm.monGrid.refresh
    ou des Application.ProcessMessages
    rien n'y fait

    Alors j'ai fait un essai avec un label dont je modifie la propriété Caption dans ma boucle, et là ça marche !!!
    Le code n'a rien de bien tordu, les exemples que je vois sur internet, avec une ProgressBar ne sont pas plus compliqués que ça.

    Que se passe-t'il alors sur ce StringGrid pour qu'il ne veuille pas se mettre à jour ?
    Comment y remédier ?

    Merci d'avance

  2. #2
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut
    Salut

    Utilises-tu Synchronize lors des ajouts et rafraichissements depuis le Thread?

  3. #3
    Membre éclairé
    Avatar de iubito
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2003
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2003
    Messages : 389
    Points : 655
    Points
    655
    Par défaut
    J'ai pas réussi à comprendre comment l'utiliser.

    précision : je suis en delphi 7

    est-ce que je dois mettre tout le contenu de mon Execute dans une autre fonction et que le code d'Execute devienne juste Synchronise(l'autre fonction) ?

    le checksynchronize j'ai pas compris

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 462
    Points
    25 462
    Par défaut
    Biensur, le code executé en parallèle doit être dans le Execute, tout le code qui manipule la TStringGrid doit être dans une méthode séparé sans paramètre qui est envoyé via Synchronize, tu peux utiliser un ensemble de variable membre de l'objet thread pour échanger des paramètres entre le Execute et la Méthode qui gère la TStringGrid ... maintenant, vu que tu fais un Sync, j'ignore l'intérêt du thread ... l'autre solution peut être d'utiliser une TThreadList contenant les informations à mettre à jour, et via un PostThreadMessage, le Thread VCL va lire la liste ...

    tout ce qui est exécuté dans le Create est en fait executé dans le thread principal, et non pas dans le nouveau Thread ...

    ensuite manipuler des composants VCL du thread principal depuis un autre thread c'est s'exposé aux EOSError 1400 : Handle de Fenêtre Invalide ... du fait qu'un handle en cours d'utilisation par le Thread a été realloué par la VCL (RecreateWnd par exemple) et donc à changer ...

    l'Appel à Application.ProcessMessages n'est pas non plus une bonne idée, puisqu'il va traiter les messages (cela peut être utile voir PumpMessage fourni ci dessous) mais il va les dispatcher à la MainForm et ActiveForm, des variables qui ne sont pas protégés pour les accès multi-thread ... cela peut provoquer des comportements imprévisibles ... même si cela reste rarissime

    Ensuite CheckSynchronize n'est pas utile, c'est appelé automatiquement durant le Idle de l'application, c'est lui qui va consulter la liste de pointeur de méthode empilé par les appels de Synchronize dans les différents Thread ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    procedure PumpMessages;
    var
       Msg: TMsg;
    begin
         while PeekMessage(Msg, 0, 0, 0, pm_Remove) do begin
               TranslateMessage(Msg);
               DispatchMessage(Msg);
         end;
    end;

  5. #5
    Rédacteur
    Avatar de Pedro
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    5 411
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 5 411
    Points : 8 078
    Points
    8 078
    Par défaut
    Citation Envoyé par iubito Voir le message
    J'ai pas réussi à comprendre comment l'utiliser.

    précision : je suis en delphi 7
    En fait, comme le dit ShaiLeTroll, dès que tu fais appel à un objet de ta VCL depuis un thread autre que le principal, il faut utiliser Synchronize.
    Il faut l'utiliser de cette façon:
    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
     
    procedure AfficheValeur;//Pas de paramètre!
    begin
      maForm.MaGrille.Cells[X,Y] := 'Youpi';
      maForm.MaGrille.Update;//Peut-être pas nécessaire
    end;
     
    ...
     
    procedure TMonThread.Execute;
    begin
    ...
    Synchronize(AfficheValeur);
    ...
    end;
    A vérifier mais dans l'ensemble, c'est comme ça que ça marche.
    Note: il est possible aussi de passer une fonction à paramètre dans Synchronize mais c'est un peu plus complexe... Et surtout je ne me souviens plus comment on fait

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 462
    Points
    25 462
    Par défaut
    Pour reprendre l'exemple, pour répondre à la problématique des paramètres (faut soit même faire sa TProcList et gérer la paramètres sous forme de list de pointeur ou tableau, ... prise de tête)

    Petite correction AfficheValeur est une méthode de TMonThread !!! Attention à cela



    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    type 
      TMonThread = class(TThread)
      private
        FParam1: string;
        FParam2: TPoint;
        ...
      protected 
        AfficheValuer;
      public
        procedure Execute; override;
      end;
      ...
     
    procedure TMonThread.AfficheValeur; //Pas de paramètre!
    begin
      maForm.MaGrille.Cells[FParam2.X,FParam2.Y] := FParam1;
    end;
     
    ...
     
    procedure TMonThread.Execute;
    begin
    ...
      FParam1 := 'Youpi'
      FParam2.X := 100;
      FParam2.Y := 50;
      Synchronize(AfficheValeur);
    ...
    end;

  7. #7
    Membre éclairé
    Avatar de iubito
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2003
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2003
    Messages : 389
    Points : 655
    Points
    655
    Par défaut
    Merci pour vos réponses, j'ai bien fait comme ça mais ça ne marche pas

    Voici mon code un peu plus simplifié (pour lecture)
    Code delphi : 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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
      EnvoiPDFThread = class(TThread)
      private
        etat: string;
        index: integer;
        procedure RemoveLine(StrGrid: TStringGrid; Row: Integer);
        procedure effaceLigne;
        procedure majEtat;
        { Déclarations privées }
      protected
        procedure Execute; override;
        procedure envoie1PDF(sendID: integer);
      public
        constructor Create;
      end;
     
    constructor EnvoiPDFThread.Create;
    begin
      inherited Create(true); //créé suspendu
      etat := 'En attente';
      //Détruire à la sortie
      FreeOnTerminate := True;
    end;
     
    procedure EnvoiPDFThread.Execute;
    begin
      while true do
      begin
        //boucle sur les fichiers PDF
        //quand trouve un fichier, l'envoyer !
        envoie1PDF(identifiant_du_fichier);
     
        if y''a plus de PDF then
        begin //cache le StringGrid sur le formulaire
          main.FicMain.panelKiContientLeGrid.visible := false; //<--- ça marche !
          suspend;
        end;
      end;
    end;
     
    procedure EnvoiPDFThread.envoie1PDF(sendID: integer);
    begin
        //recherche sa ligne dans le StringGrid
        //on obtient alors index = 0 <- première ligne, 1 <- 2e ligne...
        index := 0;
     
        etat := 'Traitement en cours...';
        Synchronize(majEtat);
        //...
        etat := 'Envoi...';
        Synchronize(majEtat);
        //...
        etat := 'OK';
        Synchronize(majEtat);
        sleep(500); //Juste le temps de voir que c''est OK
        Synchronize(effaceLigne); //efface la ligne du string grid
    end;
     
    procedure EnvoiPDFThread.majEtat;
    (* met à jour l'état de la ligne en cours *)
    begin
      main.FicMain.envois.cells[index, 2] := etat;
      main.FicMain.envois.Update;
    end;

    Pour être complet, le petit bout de code qui (re-)démarre le thread
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    //à l'initialisation de l'appli, création du thread
      threadEnvoiPDF := EnvoiPDFThread.Create();
     
    //quand on click sur le bouton Envoyer,
    //sauvegarde l'image à l'écran dans un PDF et envoie
      main.FicMain.panelKiContientLeGrid.Visible := true;
      //...ajoute une ligne avec les informations
      //...crée le fichier PDF dans le répertoire
      if (threadEnvoiPDF.Suspended) then
        threadEnvoiPDF.Resume;
    Keskikloche ?

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 665
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 665
    Points : 25 462
    Points
    25 462
    Par défaut
    juste une remarque de convention

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TEnvoiPDFThread = class(TThread)
    C'est mieux, de mettre le T de type pour une classe, record, ... tous les types complexes ...

    Que fait ton appli pendant le Thread ?

    Remplace la StringGrid par des Add dans un TMemo pour tester ... je n'ai jamais essayé la StringGrid par Thread mais Memo, ProgressBar/StatusBar ...

  9. #9
    Membre éclairé
    Avatar de iubito
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2003
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2003
    Messages : 389
    Points : 655
    Points
    655
    Par défaut
    Pendant ce temps mon application continue de réagir aux demandes de l'utilisateur : scanner, trier des images, sélectionner des options dans des listbox, et appuyer sur le bouton "Envoi" qui met dans la file d'attente que le thread gère.

    J'ai essayé avec un label, ça fonctionne, donc une thread est bien capable de mettre à jour quelque chose à l'écran.
    J'ai pas essayé avec un memo, mais je parie que le mémo va marcher et que le problème vient du stringgrid

  10. #10
    Membre éclairé
    Avatar de iubito
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2003
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2003
    Messages : 389
    Points : 655
    Points
    655
    Par défaut
    Bon bein aujourd'hui... pas mieux

  11. #11
    Membre éclairé
    Avatar de iubito
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2003
    Messages
    389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2003
    Messages : 389
    Points : 655
    Points
    655
    Par défaut
    Finalement j'ai trouvé un autre composant, le TListView, plus joli, et surtout qui marche !!!

Discussions similaires

  1. [GTKmm] rafraichir de fenetre a partir d'un thread
    Par bugmenot dans le forum GTK+
    Réponses: 3
    Dernier message: 14/05/2007, 22h28
  2. Accéder à une interface swing à partir d'un thread
    Par bart64 dans le forum Concurrence et multi-thread
    Réponses: 5
    Dernier message: 15/10/2006, 15h54
  3. [vc++ 2005] acceder a un textbox a partir d un thread
    Par jerome86600 dans le forum VC++ .NET
    Réponses: 9
    Dernier message: 12/07/2006, 13h10
  4. PB : Automation d'Outlook à partir d'un Thread.
    Par loupdeau dans le forum MFC
    Réponses: 3
    Dernier message: 11/05/2005, 17h29

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