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 :

Comment garder une interface active durant un long traitement (ou, de l'usage de ProcessMessages) ?


Sujet :

Lazarus Pascal

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut Comment garder une interface active durant un long traitement (ou, de l'usage de ProcessMessages) ?
    Bonjour,

    Je me casse les dents sur un problème ardu depuis une semaine sans avoir une bonne solution, et surtout sans comprendre le pourquoi du comment et le fonctionnement de ProcessMessages.

    Mon problème :
    J'affiche une trajectoire qui évolue constamment et que je calcule en même temps. Cela provoquait un scintillement très désagréable que j'ai résolu en utilisant un TCustomControl pour le doublebuffered (curieusement absent de TCustomGraphic ...) et en découpant mon image en petits bouts (grille d'images).

    Le problème maintenant est que seules les images modifiées généralement sont remises à jour.


    Précisions :
    - le seul cas où cela n'a pas lieu est lorsque je crée les images en même temps que le formulaire, mais pour diverses raisons je souhaite les créer à l'appel de la routine qui affiche la trajectoire

    - j'utilise application.ProcessMessages après la modification des images, ce qui semble bien les mettre à jour

    - ProcessMessages n'a aucun effet en l'utilisant après la création de la grille d'images dans la routine. En fait, elles apparaissent en flash, disparaissent, et éventuellement réappariassent une fois la routien finie !

    - suite à la lecture de http://users.telenet.be/sonal.nv/ics...ocessMessage03 il apparait qu'il ne faut pas utiliser ProcessMessages mais plutôt la méthode Update des contrôles. Après essai, cela fonctionne en effet : toutes les images s'affichent immédiatement. Il reste juste un léger problème ; le bouton permettant d'arrêter la routine n'est plus accessible puisqu'apparemment l'application ne traite plus automatiquement les messages ...

    - en rajoutant de temps en temps un seul ProcessMessages, l'accès au bouton revient, ce qui a pour effet immédiat ... d'effacer toutes les images qui ne sont pas modifiées !!!

    - puisqu'il semble y avoir un soucis entre le flux normal du programme, les évênements, les messages et leur traitement, j'ai essayé de lancer la longue routine via un chronomètre lui-même activer par le bouton, en espérant pouvoir ainsi libérer le bouton.. Résultat : à nouveau une fois lancée la routine ne peut plus être stoppée, le bouton étant inaccessible, et si on rend la main par un ProcessMessages, les images disaparaissent.


    Mes questions :
    - lorsqu'on crée un contrôle dans une routine, comment être sûr qu'il sera bien intégré au formulaire, donc mis à jour quand il faut ?

    - à quoi sert réellement ProcessMessages vu que dans le lien il semble bien qu'on n'ait pas le droit de l'utiliser

    - comment "bien concevoir" un programme dans le sens des interruptions et autres évênements "automatiquement" gérés par l'application ?

    - existe-t-il un manuel détaillés des objets en particulier des contrôles, pour freepascal ?

    - existe-t-il une alternative à ProcessMessages pour lire et traiter les évênements claviers et souris ?

    - comment éviter le problème du scintillement d'images remise à jour fréquemment sans avoir à les découper en morceaux, cela de façon fiable, simple, etc. ?



    Ah, j'oubliais. Selon que j'utilise ProcessMessages, TFrom.Update, ou d'autres méthodes pour garder toutes l'image sans que le clic ne soit pris en compte, il m'arrive même de ne pouvoir stopper le programme qu'en le tuant brutalement (Ctrl-F2 étant inopérationnel ...) !




    PS : il arrive que tous les boutons du formulaire passent manifestement en état "disabled" (écriture grisée) sans que cela ne soit programmé, auquel cas l'arrêt de la routine est très simple : cliquer sur un autre programme ; pourquoi donc sortiir la souris de dessus le bouton fait comme si j'avais cliqué dessus (sachant que ce bouton active et désactive alternativement un booléen pour arréter la routine) ?


    Voilà, j'attends votre aide pour résoudre tous ces mystères de freepascal.

  2. #2
    Membre expérimenté
    Avatar de Gouyon
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    1 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 1 095
    Points : 1 531
    Points
    1 531
    Billets dans le blog
    5
    Par défaut
    J'affiche une trajectoire qui évolue constamment et que je calcule en même temps. Cela provoquait un scintillement très désagréable que j'ai résolu en utilisant un TCustomControl pour le doublebuffered (curieusement absent de TCustomGraphic ...) et en découpant mon image en petits bouts (grille d'images).

    Le problème maintenant est que seules les images modifiées généralement sont remises à jour.
    Personnellement j'utiliserais plutôt les threads. Un thread qui fait les calculs l'autre qui affiche les résultats.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Certes, certes.

    Mais ne compliquons pas tout en même temps ! Enfin, si c'est possible ...

  4. #4
    Rédacteur
    Avatar de darrylsite
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 299
    Points : 2 501
    Points
    2 501
    Par défaut
    Citation Envoyé par pem1996 Voir le message
    Certes, certes.

    Mais ne compliquons pas tout en même temps ! Enfin, si c'est possible ...
    J'ai pas pu lire tout ton post, mais si j'ai bien compris le bouton ne réagit plus quand tu lances des traitements.

    Comme les traitements sont exécutés dans le flux normale du programme, les évènements ne sont plus gérés. La solution serait de lancer les taches en parallèle. Comme l'a dit Gouyon, c'est ce que font les Thread.

  5. #5
    Membre expérimenté
    Avatar de Gouyon
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    1 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 1 095
    Points : 1 531
    Points
    1 531
    Billets dans le blog
    5
    Par défaut
    Justement les threads simplifieront ton problème et ne sont pas extrêmement compliqués à metrre en oeuvre (voir FAQ).

    lorsqu'on crée un contrôle dans une routine, comment être sûr qu'il sera bien intégré au formulaire, donc mis à jour quand il faut ?
    Je ne comprend pas bien de quoi tu parles. As tu un exemple de code?
    - à quoi sert réellement ProcessMessages vu que dans le lien il semble bien qu'on n'ait pas le droit de l'utiliser
    C'est lié au système d'exploitation Windows. En gros un programme scrute en boucle une liste de message. Cette liste est mise à jour lorsqu'un évènement survient (par exemple un appuis sur un bouton de souris). Dans certain cas le traitement d'un de ces message peut être long voir bloquant. ProcessMessage permet de forcer le traitement des messages qui attendent dans la liste.
    On a parfaitement le droit de l'utiliser mais ça ne sert à rien si il n'y a pas de message en attente
    - comment "bien concevoir" un programme dans le sens des interruptions et autres évênements "automatiquement" gérés par l'application ?
    Vaste sujet. Ceci dit c'est un peu plus facile avec les outils de maintenant et je ne vois pas ou est la difficulté.
    - existe-t-il un manuel détaillés des objets en particulier des contrôles, pour freepascal ?
    L'aide en ligne de Lazarus entre autre sinon j'utilise beaucoup la FAQ et les forum Delphi
    - existe-t-il une alternative à ProcessMessages pour lire et traiter les évênements claviers et souris ?
    Inutile d'utiliser ProcessMessages il suffit d'écrire un méthode qui traite l'évènement. Voir l'onglet évènement dans l'inspecteur d'objet des contrôles.
    - comment éviter le problème du scintillement d'images remise à jour fréquemment sans avoir à les découper en morceaux, cela de façon fiable, simple, etc. ?
    Mettre le propriété doublebuffered à true; Ceci dit il y a toujours un petit effet de scintillement mais bien moindre.

  6. #6
    Rédacteur
    Avatar de darrylsite
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 299
    Points : 2 501
    Points
    2 501
    Par défaut
    Citation Envoyé par Gouyon Voir le message
    Mettre le propriété doublebuffered à true; Ceci dit il y a toujours un petit effet de scintillement mais bien moindre.
    Une solution serait peut etre d'utilisé des bibliothèques graphiques comme OpenGL/SDL lorsqu'on veut faire des traitements graphique assez lourds.

  7. #7
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    bonjour,

    ta question n'est pas très claire...enfin son contexte en tout cas ne l'est pas.

    que sont tes images ? quel composant ou quelle méthode utilises-tu pour les dessiner ?

    il faut garder à l'esprit qu'une application Windows est (sauf à utiliser des Thread) résolument monotâche.

    le coeur de l'application est une boucle qui attend un message (Application.ProcessMessages) pour déclencher le traitement lié (Button1Click). Cet appel interrompt la boucle de lecture des messages, donc aucun autre évènement n'est traité en attendant la fin de la procédure invoquée.

    Dans ta question tu parles d'une modification de trajectoire qui évolue constamment...est-ce donc que ton programme boucle sur une procédure de mise à jour ? auquel cas le ProcessMessages n'a pas lieu sauf si tu l'invoques explicitement.

    Est-ce un message (un Timer par exemple) qui provoque la mise à jour de l'affichage ? on l'absence de message (Application.OnIlde) ?

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Bonjour à tous et merci pour vos réponses.

    @Darrylsite, non c'est un effet secondaire.
    Je modifie dans une boucle une image (je veux voir le résultat s'afficher au fur et à mesure et pas à la fin). Plusieurs problèmes se posent alors :
    - si je prends une image "normale" (Timage), il y a un désagréable scintillement
    - celui-ci a aussi lieu avec une classe construite sur TCustomControl mais moins souvent
    - comme l'image n'est entièrement modifiée, faute de mieux je l'ai découpée en plusieurs que j'affiche en grille. Un nouveau problème apparaît : après un affichage initial qui semble assez correct, au premier usage de processmessages les portions d'images non modifiées disparaissent de l'écran.
    - plus aucune interaction n'est possible si je n'inclue pas un processmesages afin de permettre par exemple aux boutons de pouvoir répondre à un clic, moyen utilisé pour arrêter le calcul en cours

    À propos de la disparition des blocs d'images. Si mes images sont créées dans form1.create, alors elles restent en générales visibles avec ou sans processmessages (=PM). Si elles sont créés dans la même routine qui fait ensuite la boucle :
    - je suis parvenu après maints efforts à les rendre visibles grâce à la méthode update
    - elles restent visibles si aucun PM n'est utilisé
    - elles disparaissent définitivement au premier PM rencontré
    Je viens de réussir à les rendre visibles en les réaffichant après un PM ; au premier coup il y a un long scintillement puis plus rien comme si elles n'étaient plus mise à jour ! Ça rend l'intérêt du découpage pour accélérer l'affichage inutile (ou comment tuer une mouche avec un canon) mais au moins je n'ai plus de scintillement.


    @Gouyon, moi non plus, vu le comportement aléatoire de la bête.
    Si j'ajoute à un formulaire un contrôle depuis l'éditeur, je sais qu'il fonctionne correctement ensuite, par exemple charger une fichier dans une Timage l'affiche bien.
    Si je créé depuis le code le contrôle et tente de l'utiliser, généralement ça ne fonctionne pas (ex, l'image dans lequel j'ai chargé un fichier apparait puis disparait).
    Comme dans le second cas il faut au moins avoir une ligne
    ctl:=Ttype_control.create;
    et que dans le premier cela n'apparaît pas dans le code directement accessible (unitX.pas), je me demandait s'il n'y avait pas une instruction de ce genre que j'aurai oubliée et expliquerait le comportement aberant.

    J'ai l'impression quelque part que l'application ou le formulaire n'est pas au courant qu'il y a de nouveaux contrôles à au moins laisser visibles tels quels.


    "Rendre le bouton à son état normal non enfoncé" est bien un message ? Plutôt que traiter les messages, y a-t-il un moyen de faire lire les évênements à l'application ? Je vuex dire que si la boucle bloque le programme, aucun clic frénétique ne sera entendu ; y a-t-il une instruction pour dire à l'application d'écouter sans forcément traiter s'il n'y a rien ?


    Je connais les références LCL, RTL, FCL, dont curieusement TImage est absente. Idem pour le manuel de la programmation pascal qui ressemble a celui des années 80 avec deux cours chapitres sur les objets (4 pages de moins de deux paragraphes succins chacunes) et les classes (guère mieux) et ne dit rien de l'utilisation des contrôles pour une interface graphique. J'ai fouillé dans le wiki pour d'autres choses comme les images jpeg avec succès, mais rien de concluant pour mon problème.

    Je cherche plutôt un manuel de la programmation objet / formulaires sous pascal, ou d'un cours, mais je n'ai pas trouvé jusqu'ici.

    il suffit d'écrire un méthode qui traite l'évènement.
    C'est bien ce que j'ai fait. Mais la boucle empêche d'y entrer.

    Mettre le propriété doublebuffered à true; Ceci dit il y a toujours un petit effet de scintillement mais bien moindre.
    Ça a bien atténué, mais comme la remise à jour doit être fréquente, cela n'était pas suffisant, d'où le découpage.

    @darrylsite
    "lourd"


    Comment dire. Quand je programmais en turbo pascal sur un 486 j'ai fait bien plus lourd que ça avec un résultat largement plus convenable.

    Mon problème "lourd" est de calculer un malheureux point puis de l'afficher sans que l'image ne saute. Le doublebuffer, descendant sans doute des doubles pages d'écran, semblait être la solution, mais pas idéale dans les faits.

    Mon problème est alourdi par un autre aspect : coller un "sprite" à l'emplacement du point. Je ne trouve pas ça de la haute voltige graphique.


    @Paul TOTH, merci, je comprends mieux.
    J'ai bien une boucle. Je peux l'interrompre momentannément pour permettre le traitement des évênements (donc le clic qui me permettra d'arréter la boucle).

    Mon pb et mon interrogation majeure est que dans cette boucle et dès que PM est utilisé, des images disparaissent et ne réapparaissent que si je les réaffiche !




    Je suis en train de refaire une série de tests pour essayer de trouver quelques exemples courts et clairs du comportement.


    Rq : quelqu'un a laissé entendre que processmessages était propre à windows. Je suis sous linux, mais aimerais metre ce programme à dispo sous window ; y a-t-il une contournante pour "compiler everywhere" ?

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Petit exemple de code en partie tiré de http://wiki.freepascal.org/Developin...e_clignotement

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
      private
        { private declarations }
      public
        { public declarations }
        image:TCustomControl;
        Image1: TImage;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
         png : TPortableNetworkGraphic;
     
      begin
    { ceci tiré du lien n'affiche rien }
        png := TPortableNetworkGraphic.Create;
        Image:= TCustomControl.Create(Self); 
        Image.Top := 0;
        Image.Left := 100;
        Image.Width := 40;
        Image.Height := 40;
        Image.Parent := Self;
        Image.DoubleBuffered := True;
        Image.Visible:=true;
        png.LoadFromFile('./image.png');
        Image.Canvas.Draw(0,0,png);
        png.Free;
        Image.Update;                   { malgré cet ajout }
     
    { ceci est inspiré du lien et du fait qu'une TImage déposée sur la fiche fonctionne }
        Image1:= TImage.Create(Self);  
        Image1.Parent := Self;
        Image1.AutoSize:=true;
        Image1.Visible:=true;
        Image1.Picture.PNG.LoadFromFile('./image.png');
    end;
    Comme le commentaire l'indique, l'exemple tiré du wiki et qui a bien fonctionné par ailleurs dans le programme précédent n'affiche rien.

    Inversement, Image1 qui est bien créée par le code et pas par Lazarus, s'affiche.

    Pourquoi cette différence ?

  10. #10
    Membre expérimenté
    Avatar de Gouyon
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    1 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 1 095
    Points : 1 531
    Points
    1 531
    Billets dans le blog
    5
    Par défaut
    Si j'ai bien compris tu veux afficher un film (Une image qui évolue dans le temps).
    Dans ce cas il suffit d'un seul composant TImage ou plus simple un TBitmap et travailler avec ce dernier.
    La fréquence de changement entre les deux images dépendra de la vitesse de ton calcul.
    Dans l'exemple du code que tu donne je ne vois pas l'intérêt de créer dynamiquement les images. Ce qui t'intéresse c'est le contenus.

    Dans un premier temps ça peut se faire en une tache unique. Mais pour ne pas bloquer l'interface il vaut mieux utiliser les threads (surtout si tu as une machine avec un processeur multi-cœur)

    Ajoute dans ton exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Image.Color:=clRed;
    et je pense que tu verras un beau carré rouge apparaître sur ta Form.

  11. #11
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    Bon alors, je pense que tu n'as pas une vision claire de Windows...ou XWindow, car c'est en réalité assez voisin.

    j'ai d'ailleurs lancé il y a quelques années les premiers éléments d'une VCL Windows/Linux qui devait permettre de compiler une application Delphi avec Kylix sans aucun changement dans le code.

    mais je m'écarte du sujet

    donc sous Windows on n'a généralement pas accès à la mémoire vidéo (DirectX le permet) et de toute façon notre application est rarement seule à l'écran.

    mais tu peux très bien utiliser un Bitmap pour travailler dessus en mémoire comme tu le faisais sous DOS à l'écran..quand la fenêtre doit être réaffichée (car déplacée par exemple) Windows envoie le message WM_PAINT qui se traduit par le OnPaint de la fiche, c'est à ce moment là que le Bitmap sera dessiné à l'écran. Tu peux limiter la mise à jour à une portion de l'écran avec un TPaintBox. Quand c'est toi qui désire actualiser l'affichage tu es supposé indiquer à Windows par un appel Invalidate que l'image DOIT être redessinée..et Windows lancera un WM_PAINT quand ce sera nécessaire.

    tant que le bitmap écrase l'ancien affichage sans effacer l'écran avant, tu n'auras pas de clignotement.

    Utiliser un TCustomControl permet d'éviter l'évènement WM_ERASEBKGND de la fiche qui, dans la VCL, efface la fiche en la remplissant avec sa "Color".

    ceci dit tout cela ne répond pas au pb principal, ton application ne doit pas rester plantée sur un traitement car elle DOIT répondre aux messages de Windows sous peine de ne pas se réafficher correctement quand on la déplace.

    faire appel à PM dans ta boucle débloque la situation mais ça t'oblige de toute façon à gérer les clics et autres actions qui pourraient relancer ta boucle. il faut don griser les boutons ou tester l'état de ton traitemnt, si en cours -> Exit

    mais je préfère l'approche moins brutale d'un traitement invoqué périodiquement par un timer ou par OnIdle

  12. #12
    Membre expérimenté
    Avatar de Gouyon
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    1 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 1 095
    Points : 1 531
    Points
    1 531
    Billets dans le blog
    5

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    @Gouyon
    C'est en quelque sorte un film en effet. Le calcul est immédiat mais j'ai besoin que l'affichage soit le plus rapide possible car la séquence calcul/affichage doit se faire en nombre important et très fréquemment.

    Le Timage ne convient pas pour cela à cause du scintillement ; c'est ce que j'avais initialement pris.
    C'est pour éviter ce souci que j'en suis venu à la création de l'image à la volée.

    Parfois cette création marche (ce fût le cas dès l'essai du code trouvé dans la réf, sinon je serais allé voir ailleurs), parfois ça ne passe pas pour une raison obscure (voir plus bas en fin de réponse de Paul).

    J'ai bien un beau carré rouge en effet ... mais toujours pas l'image chargée (il n'y a pas d'erreur) que j'arrive par ailleurs à voir dans d'autres cas !?


    @Paul
    Merci de ces éclaircissements. Je me doute bien que tout cela fonctionne de façon bien différente, je suis juste surpris de ne pouvoir avoir simplement une sorte de machine virtuelle avec :
    - un "écran" tout simple (qui correspondrait à la zone limitée par la fenêtre par ex.) qui indépendamment du proc lit la mémoire et l'affiche
    - des tampons de claviers et souris qui peuvent être interrogés au milieu d'une boucle, ou un mécanisme type l'interruption matérielle/logicielle d'antant (qui là étaient de vrais évênements ...).
    Mais bon, je diverge aussi.

    Je vais voir ce que je peux faire avec TPaintBox.

    Pour invalidate, j'invalide ! Pas plus que update d'ailleurs, finalement.
    Encore une fois seules les images modifiées lors du traçage de l'orbite restent visibles.


    tant que le bitmap écrase l'ancien affichage sans effacer l'écran avant, tu n'auras pas de clignotement.
    Je veux bien, mais je n'ai pas saisi comment ; parce que TCustomControl ne contient pas de bitmap.


    Je gère les clics sur l'interface, justement pour pouvoir interrompre le traitement en cours, et c'est là que PM intervenanait.


    Pour la question du Timer, voici l'exemple que j'annonçais à Gouyon.

    Fort des indications que vous m'avez indiquées (laisser le temps à l'appli de réagir de son côté), j'ai opté pour un timer.

    Première réaction : super génial, enfin ça marche !

    Deuxième réaction : pourquoi lorsque j'augmente l'intervalle de 1 ms à 100 ms tout fout de nouveau le camp !?

    Apparemment, ne pas laisser suffisamment de temps à l'appli permet de ne pas effacer les images tandis que lui laisser le temps lui permet à nouveau de se comporter de façon aberrante.

    Je fais des copies d'écran et les envoie.



    Cependant la solution timer est un pis-aller ici ; dans certains cas, peut-être nombreux, c'est une bonne solution mais quand on veut que l'application passe le plus clair de son temps à calculer plutôt qu'attendre qu'il soit l'heure de calculer, c'est une très mauvaise solution ! Enfin, ici je m'en contenterai.

  14. #14
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Voici les deux portions d'écrans correspondant à l'intervalle très bref et le plus long, dans l'ordre.

    Le carré gris dans la banane noire est la marque d'une image collée qui n'était apparue à la copie sur aucune des deux copies.

    Vous pouvez juger de l'étendue du problème.
    Images attachées Images attachées   

  15. #15
    Membre expérimenté
    Avatar de Gouyon
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    1 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 1 095
    Points : 1 531
    Points
    1 531
    Billets dans le blog
    5
    Par défaut
    C'est en quelque sorte un film en effet. Le calcul est immédiat mais j'ai besoin que l'affichage soit le plus rapide possible car la séquence calcul/affichage doit se faire en nombre important et très fréquemment.
    Quel fréquence de rafraichissement souhaite tu?
    Comment construis tu ton image

  16. #16
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    Citation Envoyé par pem1996 Voir le message
    Voici les deux portions d'écrans correspondant à l'intervalle très bref et le plus long, dans l'ordre.

    Le carré gris dans la banane noire est la marque d'une image collée qui n'était apparue à la copie sur aucune des deux copies.

    Vous pouvez juger de l'étendue du problème.
    cela ressemble fort à un problème de persistance...

    voici un exemple de ce phénomène

    associe cette méthode au OnClick d'une fenêtre vierge
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    procedure TForm1.FormClick(Sender: TObject);
    begin
      Canvas.TextOut(10,10,'Hello, bouge la fenêtre maintenant... !');
    end;
    tu peux déplacer la fenêtre, le texte reste affiché...mais si elle sort de l'écran ou si tu viens placer une autre fenêtre devant, le texte disparait !

    tout simplement car, comme je l'expliquais avant Windows sollicite parfois la fenêtre pour qu'elle se redessine, son contenu ayant été perdu quand elle est sortie de l'écran ou qu'une autre fenêtre la recouverte.

    si tu places un TImage et que dans le code précédent tu utilises Image1.Canvas à la place du Canvas, le texte est dessiné dans un bitmap automatiquement créé par TImage (d'ailleurs le fond de l'image devient blanc) et le texte devient persistant car TImage réaffiche son bitmap quand Windows le réclame.

    Ajoutons un Timer sur la fiche réglé à 100ms
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Image1.Canvas.TextOut(10,30, IntToStr(GetTickCount));
    end;
    je pensais pouvoir reproduire le clignotement par ce code, mais ça ne clignote pas non plus

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Image1.Canvas.FillRect(Image1.ClientRect, clWhite);
      Image1.Canvas.TextOut(10,10,'Hello, bouge la fenêtre maintenant... !');
      Image1.Canvas.TextOut(10,30, IntToStr(GetTickCount));
    end;
    alors comment tu fais ?

  17. #17
    Membre expérimenté
    Avatar de Gouyon
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    1 095
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 1 095
    Points : 1 531
    Points
    1 531
    Billets dans le blog
    5
    Par défaut Code avec threads
    Pour te montrer que les threads ne sont pas si compliquées qu ça voici un petit exemple que tu pourrais utiliser pour résoudre ton problème.
    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
    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
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
     
    unit MulThMain;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
      ExtCtrls, StdCtrls, BGRABitmap, BGRABitmapTypes;
     
    type
      t_Tablo = array [0..319, 0..239] of integer;
      {Thread de calcul}
      TCalcul = class(TThread)
      private
        PointX, PointY: integer;
      protected
        procedure Execute; override;
      public
        constructor Create(CreateSuspended: boolean);
      end;
     
      {Thread d'affichage}
      TAffiche = class(TThread)
      private
        IndexAff: integer;
      protected
        procedure Execute; override;
      public
        constructor Create(CreateSuspended: boolean);
      end;
     
      { TForm1 }
     
      TForm1 = class(TForm)
        BtnStart: TButton;
        BtnStop:  TButton;
        Image1:   TImage;
        procedure BtnStartClick(Sender: TObject);
        procedure BtnStopClick(Sender: TObject);
        procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
        procedure FormCreate(Sender: TObject);
      private
        { private declarations }
        ThCalc: TCalcul;
        ThAff:  TAffiche;
      public
        { public declarations }
        DataReady: PRTLEvent;
        Tablo:     array [0..15] of t_Tablo;
        IndexImg:  integer;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    constructor TCalcul.Create(CreateSuspended: boolean);
    begin
      FreeOnTerminate := True;
      inherited Create(CreateSuspended);
    end;
     
    procedure TCalcul.Execute;
    const
      CoinX: array[1..3] of integer = (319, 0, 319);
      CoinY: array[1..3] of integer = (0, 239, 239);
    var
      i, nx, ny,m: integer;
      dx2, dy2:  integer;
      Max, V:    integer;
    begin
      PointX := 160;
      PointY := 120;
      Form1.IndexImg := 0;
      while not Terminated do
      begin
        PointX := PointX + 10;
        if PointX > 320 then
        begin
          PointX := 10;
          PointY := PointY + 10;
          if PointY > 230 then
            PointY := 10;
        end;
        for nx := 0 to 319 do
        begin
          for ny := 0 to 239 do
          begin
            Form1.Tablo[Form1.IndexImg][nx, ny] := 255-ny;
          end;
        end;
        for nx := PointX-5 to PointX+5 do
        begin
          for ny := PointY-5 to PointY+5 do
          begin
            Form1.Tablo[Form1.IndexImg][nx, ny] := 0;
          end;
        end;
     
        Inc(Form1.IndexImg);
        if Form1.IndexImg > 15 then
          Form1.IndexImg := 0;
        RTLEventSetEvent(Form1.DataReady);
      end;
    end;
     
    constructor TAffiche.Create(CreateSuspended: boolean);
    begin
      FreeOnTerminate := True;
      inherited Create(CreateSuspended);
    end;
     
    procedure TAffiche.Execute;
    var
      x, y, n: integer;
      Bmp:     TBGRABitmap;
      PSource: PBGRAPixel;
     
    begin
      while not Terminated do
      begin
        RTLEventWaitFor(Form1.DataReady);
        Bmp      := TBGRABitmap.Create(320, 240);
        IndexAff := Form1.IndexImg - 1;
        if IndexAff < 0 then
          IndexAff := 15;
        PSource := Bmp.Data;
        x := 0;
        y := 0;
        for n := 0 to Bmp.NbPixels - 1 do
        begin
          PSource^.red   := Form1.Tablo[IndexAff][x, y];
          PSource^.green := Form1.Tablo[IndexAff][x, y];
          PSource^.blue  := Form1.Tablo[IndexAff][x, y];
          Inc(PSource); // aller au pixel suivant
          Inc(x);
          if x >= 320 then
          begin
            x := 0;
            Inc(y);
          end;
        end;
        Bmp.InvalidateBitmap; // note qu'on a changé par accès direct
        Bmp.Draw(Form1.Image1.Canvas, 0, 0, True);  // affiche l'image calculée en mode opaque
        Bmp.Free;
        Sleep(16);
        Synchronize(@Form1.Image1.Refresh);
      end;
    end;
     
    { TForm1 }
     
    procedure TForm1.BtnStartClick(Sender: TObject);
    begin
      thCalc := TCalcul.Create(False);
      ThAff  := TAffiche.Create(False);
      BtnStart.Enabled := False;
      BtnStop.Enabled:=true;
    end;
     
    procedure TForm1.BtnStopClick(Sender: TObject);
    begin
      thCalc.Terminate;
      ThAff.Terminate;
      BtnStart.Enabled := True;
      BtnStop.Enabled:=false;
    end;
     
    procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    begin
      thCalc.Terminate;
      ThAff.Terminate;
     
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      DataReady      := RTLEventCreate;
      DoubleBuffered := True;
    end;
     
    initialization
      {$I MulThMain.lrs}
     
    end.
    Ça ne scintille pas mais il faut ajuster le taux de rafraichissement afin d'éliminer le phénomène de persistance.

  18. #18
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 34
    Points : 17
    Points
    17
    Par défaut
    Je veux un élément :
    - permettant de dessiner dessus (TCustomControl ou TGraphicControl)
    - tel que ce qui y est dessiné apparaisse, que ce soit un point ou une image complète (TImage mais pas TCustomControl)
    - qui puisse être placé au dessus de tous les autres éléments de la fiche (TCustomControl mais pasTImage)
    - qui gère la transparence (TCustomImage donc TImage, mais pas TCustomControl)

    mais existe-t-il ?

    Je n'en ai pas l'impression puisque ces caractéristiques appartiennent à deux branches différentes (TCustomControl et TGraphicControl).

  19. #19
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    Citation Envoyé par pem1996 Voir le message
    Je veux un élément :
    - permettant de dessiner dessus (TCustomControl ou TGraphicControl)
    - tel que ce qui y est dessiné apparaisse, que ce soit un point ou une image complète (TImage mais pas TCustomControl)
    - qui puisse être placé au dessus de tous les autres éléments de la fiche (TCustomControl mais pasTImage)
    - qui gère la transparence (TCustomImage donc TImage, mais pas TCustomControl)

    mais existe-t-il ?

    Je n'en ai pas l'impression puisque ces caractéristiques appartiennent à deux branches différentes (TCustomControl et TGraphicControl).
    AAAH ! tu joues avec la transparence !!! ça explique certaines choses

    pour qu'un composant soit transparent, il faut qu'avant d'être affiché, le composant situé sous lui s'affiche en premier...et là on obtient en effet des effets désagréables. D'ailleurs tes images ne disparaissent-elles pas car elles sont transparentes ?

    il y a d'autres façon de gérer l'affichage que par transparence...mais là il faudrait en savoir un peu plus, pourquoi utilises tu la transparences ?

Discussions similaires

  1. Comment faire une interface de ce type....
    Par SpiderAlpha dans le forum C++Builder
    Réponses: 6
    Dernier message: 30/04/2007, 13h50
  2. Comment réutiliser une interface d'un scannner ?
    Par baume dans le forum API, COM et SDKs
    Réponses: 1
    Dernier message: 18/06/2005, 00h08
  3. comment construire une interface comme une pomme...
    Par redanium dans le forum C++Builder
    Réponses: 3
    Dernier message: 29/10/2004, 15h35
  4. comment fonctionne une interface graphique???
    Par elekis dans le forum Langages de programmation
    Réponses: 2
    Dernier message: 27/10/2004, 23h10
  5. Comment créé une "interface" pour mes programmes??
    Par alcazar dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 09/02/2004, 13h02

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