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

 Delphi Discussion :

Trouve handle d'un parent à partir du handle fils


Sujet :

Delphi

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 96
    Points : 50
    Points
    50
    Par défaut Trouve handle d'un parent à partir du handle fils
    Salut

    Je sais pas si le titre du message est très clair, je m'explique :
    J'ai un Panel qui contient différents éléments du type : TLable, Timages, etc..

    Je veux déclencher un évènement quand la souris sort du Panel, j'utilise donc le OnMouseLeave du Panel mais il se déclenche aussi quand la souris passe sur un des composants à l'intérieur du Panel.

    Je peux récupérer le handle du composant sur lequel se trouve la souris avec WindowFromPoint(mouse.Cursorpos) mais comment récupérer le Handle du parent correspondant pour savoir si je suis toujours sur le Panel ?

    J'ai fait un truc un peut bâtard, je voudrais savoir si vous avez mieux comme idée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    GetClassName(WindowFromPoint(mouse.Cursorpos),aName, 256);
    If not ((string(aName)='TPanel) or (string(aName)='TImage') or (string(aName)='TLabel'))then ......je suis bien sortie du Panel car le handle récupéré ne correspondant à aucun composant se trouvant sur mon Panel......
    Merci

  2. #2
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Ah, ça c'est pour moi. J'aime bien ce genre de bidouillage.

    Bon, déjà ta solution ne me semble pas valide, puisque si tu rentres sur un autre TPanel ou TImage ou TLabel ou ... etc., la réponse au test sera de nouveau positive ! GetClassName n'est d'aucune utilité dans ce cas précis.

    Je cherche, je teste, et je te donne une soluce.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 96
    Points : 50
    Points
    50
    Par défaut
    Merci, t'as l'ar motivé ça fait plaisir.

    Pour ma soluce, je sais que c'est pas terrible, mais j'ai trouvé que ça, d'ou mon post sur le forum. J'ai un peu de chance car autour de mon Panel, je n'ai pas les types de composants que je teste.

    Merci de chercher, ++

  4. #4
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Ma solution.

    voici une fonction qui teste si la souris se trouve ou pas dans un contrôle donné - indépendamment de ce qu'il contient ou pas - d'une fiche donnée (inspiré d'une de mes vieilles units) :

    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
    function IsMouseInControl(AForm: TForm; AControl: TControl): Boolean;
    var P : TPoint;
        X,Y:Integer;
        Info:TWindowInfo;
    begin
      // On vérifie déjà que la fenêtre de l'application est en avant-plan,
      // sinon la souris n'est pas considérée comme étant "dans" le contrôle.
      if Windows.GetForeGroundWindow <> AForm.Handle then begin Result := false; exit end;
      // On récupère les coordonnées absolues de la souris
      GetCursorPos(P);
      // Les coordonnées de la fenêtre principale, et plus si affinité
      Windows.GetWindowInfo(AForm.Handle,Info);
      // Coordonnées relatives de la souris dans la fenêtre principale
      X := P.X - Info.rcClient.Left;
      Y := P.Y - Info.rcClient.Top;
      // Est-elle dans le contrôle souhaité ?
      if  (X >= AControl.Left) and (X < AControl.Left+AControl.Width)
      and (Y >= AControl.Top)  and (Y < AControl.Top+AControl.Height)
          then Result := true else Result := false;
    end;
    Voilà.

    Ensuite, on peut utiliser cette fonction à n'importe quel moment (on peut la mettre dans un évènement appli OnIdle, ou dans un TTimer si nécessaire)
    pour savoir si la souris est dans le contrôle ou pas. Nul besoin de définir d'évènement particulier.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if IsMouseInControl(MainForm,Panel1) then 
     begin 
      Memo1.Lines.Add('Je suis le maître du panel !');
     end;

  5. #5
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 700
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 700
    Points : 13 146
    Points
    13 146
    Par défaut
    Ou plus simplement (toujours dans OnMouseLeave) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    with TControl(Sender) do
      if not PtInRect(ClientRect, ScreenToClient(Mouse.CursorPos)) then
        ...

  6. #6
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Oui, mais ta solution ne résout pas forcément le problème, qui est que l'évènement OnMouseLeave se déclenche quand la souris, tout en restant sur le Panel, passe sur un composant dudit Panel.

    Maintenant, il y a quand même certainement beaucoup plus simple que ma soluce en utilisant les fonctions de la VCL, mais il était question de Handle dans le titre, donc je suis parti sur cette idée-là ; le but étant de montrer quelles fonctions Windows peuvent être utilisées...

    D'ailleurs, cette fonction peut se transformer facilement pour renvoyer une réponse à partir de deux handles, hors de tout contexte VCL :

    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 IsMouseInComponent2(AWnd, ACtlHdl: THandle): Boolean;
    var P : TPoint;
        X,Y:Integer;
        InfoWnd,InfoCtrl:TWindowInfo;
    begin
      // On vérifie déjà que la fenêtre de l'application est en avant-plan,
      // sinon la souris n'est pas considérée comme étant "dans" le contrôle.
      if Windows.GetForeGroundWindow <> AWnd then begin Result := false; exit end;
      // On récupère les coordonnées absolues de la souris
      GetCursorPos(P);
      // Les coordonnées de la fenêtre principale, et plus si affinité
      Windows.GetWindowInfo(AWnd,InfoWnd);
      // Coordonnées relatives de la souris dans la fenêtre principale
      X := P.X - InfoWnd.rcClient.Left;
      Y := P.Y - InfoWnd.rcClient.Top;
      // Récupère coordonnées du contrôle
      Windows.GetWindowInfo(AWnd,InfoCtrl);
      // Est-elle dans le contrôle souhaité ?
      Result := (X >= InfoCtrl.rcWindow.Left) and (X < InfoCtrl.rcWindow.Right)
                and (Y >= InfoCtrl.rcWindow.Top)  and (Y < InfoCtrl.rcWindow.Bottom)
    end;
    Elle pourrait même s'utiliser entre deux applications, à condition de connaître les deux Handles. Ça peut éventuellement servir.

    Si on veut juste tester plus précisément le passage dans la zone client, il faut remplacer la dernière instruction par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Result := (X >= InfoCtrl.rcClient.Left) and (X < InfoCtrl.rcClient.Right)
              and (Y >= InfoCtrl.rcClient.Top)  and (Y < InfoCtrl.rcClient.Bottom)

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 96
    Points : 50
    Points
    50
    Par défaut
    Super ça marche mais à un détail qui ne vient pas de ta fonction (je pense)

    Quand je survole un composant du Panel et que je sors du Panel sans repasser par le Panel (le composant est vraiment au bord), l’événement OnLeavePanel ne se déclenche pas, je suppose que c'est le OnLeave du composant qui se déclenche.
    Il faut que j'associe les OnLeave de tous les composants du Panel à ta fonction ?

    Merci

  8. #8
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    C'est adressé à AndNotOr ou à moi ?

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 96
    Points : 50
    Points
    50
    Par défaut
    Pardon, à toi avec ta fonction

  10. #10
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Ah, alors en fait voilà comment je vois les choses : justement, pour éviter d'avoir à écrire 36 millions d'évènements OnMouseLeave, la démarche est toute autre : pose un composant TTimer sur ta fiche par exemple (onglet Système), mets sa propriété Interval à 50 (50 ms c'est arbitraire, tu peux mettre moins si tu veux que ce soit plus réactif), et affecte à OnTimer le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     if IsMouseInComponent(Self,Panel1)
      then begin
            // traitement à faire quand la souris est dans le contrôle
           end
      else begin
            // traitement à faire quand la souris est en dehors du contrôle
           end;
    Après, si tu veux précisément qu'un évènement se déclenche une seule fois, quand le curseur quitte le Panel, il suffit d'utiliser un indicateur booléen, pour ne pas que le traitement s'effectue en cascade.

  11. #11
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 700
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 700
    Points : 13 146
    Points
    13 146
    Par défaut
    Citation Envoyé par CapJack Voir le message
    Oui, mais ta solution ne résout pas forcément le problème, qui est que l'évènement OnMouseLeave se déclenche quand la souris, tout en restant sur le Panel, passe sur un composant dudit Panel.
    Et ?..
    Cet événement surviendra toujours et c'est bien à ça que sert le test.

    Sinon, ta fonction n'est pas bonne dans le sens où tu te réfères à la fiche sans être sûr qu'elle est bien le parent direct du contrôle (la fiche elle-même pourrait être dockée). Il faudrait contrôler toute la parentée.
    Mais tous cela reste inutile ! Il suffit de faire une conversion écran des coordonnées du contrôle

  12. #12
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Dans un tel contexte, la solution de AndNotOr marche aussi d'ailleurs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     if PtInRect(Panel1.ClientRect, ScreenToClient(Mouse.CursorPos))
      then begin
            // traitement à faire quand la souris est dans le contrôle
           end
      else begin
            // traitement à faire quand la souris est en dehors du contrôle
           end;
    Mais bon, j'ai expliqué pourquoi j'étais parti sur des handles.

    Le problème, c'est le comportement de OnMouseLeave, en fait, qui fait qu'un ne peut pas l'utiliser.

  13. #13
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Sinon, ta fonction n'est pas bonne dans le sens où tu te réfères à la fiche sans être sûr qu'elle est bien le parent direct du contrôle. Il faudrait contrôler toute la parentée.
    Tout à fait. Mais on part du principe que le programmeur sait ce qu'il fait, quand même.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Mais tous cela reste inutile ! Il suffit de faire une conversion écran des coordonnées du contrôle
    Une fois le problème éclairci, c'est une évidence. Mais ça permettra toujours à quelques-uns de découvrir des fonctions intéressantes de l'API...

    Edit : je reconnais mes torts, effectivement en mettant le code dans OnMouseLeave, fonctions API ou pas, ça marche, et c'est plus simple. Je n'avais pas saisi la logique de la chose. Sauf s'il y a un composant tout au bord du TPanel. Et là, ça coince. Le mieux à faire est d'éviter de mettre des composants au bord.

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    96
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 96
    Points : 50
    Points
    50
    Par défaut
    Ta méthode Andnotor marche bien sans rajouter autre chose.
    Quand on est ou on quitte un des composants du Panel, il reste afficher (c'est mon but et le faire disparaître quand la souris n'est à l'intérieur)

    Merci à vous deux pour le coup de main.

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 04/10/2010, 18h26
  2. Réponses: 1
    Dernier message: 02/11/2009, 18h46
  3. [C#]recuperer numero process ou nom a partir du handle d'une form
    Par aymane_farissi dans le forum Windows Forms
    Réponses: 1
    Dernier message: 17/08/2006, 20h10
  4. Spécifier la fenêtre parent à partir de createProcess()?
    Par Jean-Philippe Shields dans le forum Windows
    Réponses: 7
    Dernier message: 22/02/2006, 14h59
  5. Page dans le cadre parent à partir d'un iframe...
    Par Leobaillard dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 21/02/2006, 14h57

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