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

Langage Delphi Discussion :

Action unique avec le KeyPreview


Sujet :

Langage Delphi

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Points : 64
    Points
    64
    Par défaut Action unique avec le KeyPreview
    Salut.
    J'ai participé il y a un bout de temps à une discussion portant sur comment Devier l'evenement de la touche Entrer
    La méthode proposée ici et là s'applique sur un TEdit en particulier.
    Seulement, s'il y a plusieurs zones Edit sur la fenêtre, il faudra définir la même action pour tous.
    Bien sûr on peut le faire de façon (plus ou moins) élégante en associant la même méthode aux OnKeyDown ou aux OnKeyPress de tous les TEdit à partir de l'inspecteur d'objet ou dans le code. Cette astuce m'a l'air quelque peu tirée par les cheveux.
    J'ai donc essayé d'exploiter le KeyPreview (qui permet à la fiche d'intercepter les touches clavier avant les autres contrôles). C'est déjà mieux puisque je ne définit que le OnKeyPress ou le OnKeyDown de la fiche pour avoir mon action de validation.
    Seul hic, le son est de retour !
    J'ai bien essayé de faire un dans le OnKeyDown de la fiche après mon action de validation (et son équivalent pour le OnKeyPress), rien n'y fait, les zones Edit reçoivent bien l'action de la touche Entrer et produise donc un son.
    Il faudrait donc trouver comment annuler la propagation de l'action clavier après son interception par la fiche.

    Quelqu'un aurait une méthode "simple" pour faire cela?
    (bien sûr "simple" exclus l'utilisation des Message et autres trucs tordus de Delphi )

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 449
    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 449
    Points : 24 856
    Points
    24 856
    Par défaut
    Voici un extrait de Vcl.Forms.TCustomForm.KeyPreview

    Les touches de navigation (Tab, les touches de déplacement, etc.) ne sont pas affectées par KeyPreview car elles ne génèrent pas d'événements clavier. De même, lorsqu'un bouton détient la focalisation ou lorsque sa propriété Default a la valeur true, la touche Entrée n'est pas affectée par KeyPreview car elle ne génère pas d'événements du clavier.
    Attention, si tu utilises un TBitBtn en Kind OK, il sera Default true, pense que ton code lié au KeyPreview risque de ne pas fonctionner !

    Pourquoi ne pas écrire un code réutilisable

    il y a un tas d'approche possible !

    un BPL, un Package
    avec ton propre TEdit, ou tu inhibes les comportements innapropriés, ainsi pas besoin de mettre un code dans chaque OnKeyPress
    Cela nécessite de savoir développer un nouveau composants et son déploiement dans l'IDE

    Voir un class helper dans lequel tu définis ton OnKeyPress Event Handler, il te faudra tout de même par code affecter ce gestionnaire à chaque OnKeyPress que tu souhaite gérer !


    Tu peux aussi faire une classe TEditNoEnter et TEditDecorator
    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
     
    type
      TEditDecorator = class(TComponent)
      protected
        FEdit: TEdit;
      public
        constructor Create(AEdit: TEdit); overload; virtual;
        constructor Create(AEditDecorator: TEditDecorator); overload; // virtual;
      end; 
     
      TEditNoEnter = class(TEditDecorator)
      private
        FOldKeyPressEventHandler: TKeyPressEvent;
     
        procedure KeyPressEventHandler(Sender: TObject; var Key: Char);
      public
        constructor Create(AEdit: TEdit); override;
      end;

    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
     
    constructor TEditDecorator.Create(AEdit: TEdit);
    begin
      inherited Create(AEdit);
     
      FEdit := AEdit;
    end;
     
    constructor TEditDecorator.Create(AEditDecorator: TEditDecorator);
    begin
      Create(AEditDecorator.FEdit);  
    end;
     
    constructor TEditNoEnter.Create(AEdit: TEdit);
    begin
      inherited Create(AEdit);
     
      FOldKeyPressEventHandler := AEdit.OnKeyPress;
      AEdit.OnKeyPress := KeyPressEventHandler;
    end;
     
    procedure TEditNoEnter.KeyPressEventHandler(Sender: TObject; var Key: Char);
    begin
      if Key = #13 then // ou #10
        Key := #0;
     
      if Assigned(FOldKeyPressEventHandler) then
        FOldKeyPressEventHandler(Sender, Key);
    end;
    Tu peux librement affecter des OnKeyPress à TEdit pour des traitements particulier via l'Inspecteur d'Objet mais PAS pour la gestion du Enter !

    Car c'est le défaut de vouloir généraliser un gestionnaire, cela devient pénible dès que l'on veut injecter du code spécifique

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin 
      TEditNoEnter.Create(Edit1);
      TEditNoEnter.Create(Edit2);
      TEditNoEnter.Create(Edit3);
    end;
    Tu peux même chainer, imaginons une classe TEditNoVoyelle qui refuse les voyelles

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    type
      TEditNoVoyelle = class(TEditDecorator)
      private
        FOldKeyPressEventHandler: TKeyPressEvent;
     
        procedure KeyPressEventHandler(Sender: TObject; var Key: Char);
      public
        constructor Create(AEdit: TEdit); override;
      end;

    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
     
    constructor TEditNoVoyelle.Create(AEdit: TEdit);
    begin
      inherited Create(AEdit);
     
      FOldKeyPressEventHandler := AEdit.OnKeyPress;
      AEdit.OnKeyPress := KeyPressEventHandler;
    end;
     
    procedure TEditNoVoyelle.KeyPressEventHandler(Sender: TObject; var Key: Char);
    begin
      if UpCase(Key) in ['A', 'E', 'I', 'O', 'U', 'Y'] then
        Key := #0;
     
      if Assigned(FOldKeyPressEventHandler) then
        FOldKeyPressEventHandler(Sender, Key);
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin 
      TEditNoEnter.Create(Edit1);
      TEditNoEnter.Create(TEditNoVoyelle.Create(Edit2));
      TEditNoEnter.Create(Edit3);
    end;
    Pour Edit1 et Edit3
    Il va invoquer NoEnter puis DFM

    Pour Edit2
    Il va invoquer NoEnter puis NoVoyelle puis DFM
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Points : 64
    Points
    64
    Par défaut
    Merci ShaiLeTroll.
    C'est vrai que je n'ai pas "bien" lu l'aide du KeyPreview.
    Je comprend plutôt bien la création d'une classe particulière pour définir l'action souhaitée; j'utilise souvent cette pratique. Mais elle ne me convient pas trop pour le cas présent. J'ai vraiment la flemme de le faire.
    Le blème avec la classe personnalisée, c'est qu'on ne peut pas voir le contrôle en mode conception, à moins de créer un objet qui sera mis dans la palette (trop long tout ça et je ne l'ai pas encore réussi).
    C'est pour cela que je parlais d'
    une méthode "simple"

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 449
    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 449
    Points : 24 856
    Points
    24 856
    Par défaut
    un méthode simple bon bon !
    Un technique bien tordue : [D6] Attraper la touche 'Entrée'



    Tu ajoute ceci AVANT la TForm !

    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
    type
      TEdit = class(Vcl.StdCtrls.TEdit)
      private
        FOldKeyPressEventHandler: TKeyPressEvent;
     
        procedure KeyPressEventHandler(Sender: TObject; var Key: Char);
      public
        procedure Loaded(); override;
      end;
     
    procedure TEdit.Loaded();
    begin
      FOldKeyPressEventHandler := OnKeyPress;
      OnKeyPress := KeyPressEventHandler;
    end;
     
    procedure TEdit.KeyPressEventHandler(Sender: TObject; var Key: Char);
    begin
      if Key = #13 then // ou #10
        Key := #0;
     
      if Assigned(FOldKeyPressEventHandler) then
        FOldKeyPressEventHandler(Sender, Key);
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Points : 64
    Points
    64
    Par défaut
    Tout à fait prodigieux !
    J'ai utilisé un TLabeledEdit pour le test. Et c'est passé nickel (après une adaptation pour le TLabeledEdit).
    D'après ce que j'ai pu comprendre, quand dans la classe de ma Form on prend un objet de type TLabeledEdit, il recherche la déclaration la plus proche et tombe donc sur la nouvelle classe que j'ai défini. C'est bien cela?
    Ca fait un nouveau skill, je sens que je vais abuser de cette technique
    Mais dis, c'est quoi la méthode loaded() ?

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 449
    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 449
    Points : 24 856
    Points
    24 856
    Par défaut
    Citation Envoyé par Fandyz Voir le message
    Tout à fait prodigieux
    Et Mystérieux aussi !

    Citation Envoyé par Fandyz Voir le message
    D'après ce que j'ai pu comprendre, quand dans la classe de ma Form on prend un objet de type TLabeledEdit, il recherche la déclaration la plus proche et tombe donc sur la nouvelle classe que j'ai défini. C'est bien cela?
    Je n'ai jamais compris comme le FindClass s'y retrouve, Paul Toth faisait remarquer que l'on peut bidouiller plusieurs variantes dans différents fichiers de TForm et Delphi s'y retrouve quand même !

    Citation Envoyé par Fandyz Voir le message
    Ca fait un nouveau skill, je sens que je vais abuser de cette technique ?
    C'est pour cela que j'ai tardé à la soumettre, c'est aussi une méthode dégueux, moi je l'évite, je pratique que dans mon application de test pour connaître le truc

    Citation Envoyé par Fandyz Voir le message
    Mais dis, c'est quoi la méthode loaded() ?
    TComponent.Loaded c'est quand le DFM est chargé, tu peux utiliser aussi AfterConstruction

    Il n'y a pas de OnCreate dans le TEdit ou TLabeledEdit, contrairement à la TForm (voir OldCreateOrder)
    Dans ce cas surcharger le constructor ne fonctionnerait pas car la modification par code serait effectué avant que l'on charge les property via le DFM, du coup, pas d’affectation de l'event
    Loaded est donc le bon moment pour écraser les valeurs issues de la DFM
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2012
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 91
    Points : 64
    Points
    64
    Par défaut
    C'est pour cela que j'ai tardé à la soumettre, c'est aussi une méthode dégueux, moi je l'évite
    D'ac ShaiLeTroll, je vais l'utiliser le moins possible alors
    Merci pour avoir apporté une réponse à ma préoccupation.

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Chaque événement de la VCL est encapsulé dans une méthode virtual du même nom sans le préfixe "On". Pour OnKeyPress : KeyPress (déclaré dans TWinControl). Il suffit par conséquent de redéfinir cette méthode

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
      TEdit = class(Vcl.StdCtrls.TEdit)
      protected
        procedure KeyPress(var Key :char); override;
      end;
     
    procedure TEdit.KeyPress(var Key: char);
    begin
      if Key = #13
      then Key := #0
      else inherited;
    end;

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 449
    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 449
    Points : 24 856
    Points
    24 856
    Par défaut
    Merci Andnotor pour la version KeyPress override, c'est bien mieux que Loaded !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 09/03/2006, 13h35
  2. [Threads] Actions continues avec des threads
    Par MiJack dans le forum Concurrence et multi-thread
    Réponses: 6
    Dernier message: 10/10/2005, 17h32
  3. action reaction avec champs type="text"
    Par ericmart dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 13/04/2005, 17h00
  4. [Struts][Tiles] Probleme d'action mapping avec un dynaform
    Par bluefox_du_974 dans le forum Struts 1
    Réponses: 3
    Dernier message: 28/03/2005, 22h47

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