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

C++Builder Discussion :

[RichEdit]mot sous le Curseur


Sujet :

C++Builder

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de daheda
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2006
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Ile Maurice

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2006
    Messages : 81
    Par défaut [RichEdit]mot sous le Curseur
    bonjour à tous !
    voilà un code en Builder C++ qui permet de connaitre le mot sous le curseur
    Mais il ya un petit bug :
    Il ya une violation d'adresse quand je ressort de mon RichEdit ou je Rentre depuis le coin haut où le point du curseur vaut 0,0
    voila l'ébauche de la fonction
    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
     
    String GetWordUnderCursor(TRichEdit *RichEdit )
    { int
      DebutMot, FinMot,
      CharIndex, LineIndex, CharOffset;
      TPoint Pt=TPoint();
      String Result = "";
      Pt = Mouse->CursorPos;
      Pt = RichEdit->ScreenToClient(Pt);
      // Récupère le caractère sous le curseur
      // (La fonction retourne -1 si elle échoue)
      CharIndex = SendMessage(RichEdit->Handle, EM_CHARFROMPOS, 0, int(&Pt));
    //   Form1->Label1->Caption=" char index "+ IntToStr(CharIndex);
      //ShowMessage(IntToStr(CharIndex));
      if (CharIndex !=-1 ) {
            Form1->Label1->Caption=" char index "+ IntToStr(CharIndex);
            Form1->Label2->Caption =RichEdit->Text[CharIndex];
        // Si le caractère est valide, on teste les caractères adjacents pour
        // savoir si le mot sous le curseur
     
        if (RichEdit->Text[CharIndex]!=' '|| RichEdit->Text[CharIndex]!='\n'){
          // Récupère l'index de la ligne
          LineIndex = RichEdit->Perform(EM_EXLINEFROMCHAR, 0, LPARAM(CharIndex));
           //Récupère la position du caractère depuis le début de la ligne
          CharOffset = CharIndex - RichEdit->Perform(EM_LINEINDEX, WPARAM(LineIndex), 0);
          Form1->Label3->Caption="Line Index"+IntToStr(LineIndex);
          Form1->Label4->Caption="Char OffSet "+IntToStr(CharOffset);
          // Récupère le mot sous le curseur
          if (((RichEdit->Lines->Strings[LineIndex].Length()) > 0)&&(RichEdit->Lines->Strings[LineIndex].Length()>CharOffset)){
            // La partie gauche du mot
            DebutMot = CharOffset + 1;
            Form1->Label5->Caption=IntToStr(CharOffset);
            while (DebutMot > 0){
              if (RichEdit->Lines->Strings[LineIndex][DebutMot]!=' ' )
                DebutMot = DebutMot - 1 ;
              else
                break;
            }
            // La partie droite
            FinMot = CharOffset + 1;
            while (FinMot < (RichEdit->Lines->Strings[LineIndex].Length()) ){
              {
              if (RichEdit->Lines->Strings[LineIndex][FinMot]!=' ' )
              FinMot = FinMot + 1 ;
              else
                break;
              }
           }
     
            // On copie le mot dans Result
          for (int i=DebutMot;i<=FinMot-1;i++)
            Result+= RichEdit->Lines->Strings[LineIndex].c_str()[i];
          }
        }
     
      }
       return Result;
    }
    la question est donc : c'est qui beuge et y a t il un solution?

    Cordialement

  2. #2
    Membre Expert
    Avatar de Gilles Louïse
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    421
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2002
    Messages : 421
    Par défaut
    L'index des caractères commence à 1, donc si vous cliquez sur le coin vous allez obtenir 0 et vous avez un OutOfRange. Le mieux est de considérer que si vous cliquez 0, vous considérez que c'est 1 et vous supprimez le if (CharIndex !=-1). Vous écrivez donc juste avant ce if :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (!CharIndex) CharIndex=1;
    ce qui signifie que si l'index est nul, vous ne mettez à 1 et vous supprimez le if qui suit.

    Sinon votre procédure à l'air d'être bonne, merci pour ce code qui peut être intéressant à reprendre.

    À bientôt
    Gilles

  3. #3
    Membre confirmé Avatar de daheda
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2006
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Ile Maurice

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Août 2006
    Messages : 81
    Par défaut
    Merci Beaucoup!
    a bietot.
    cordiallement

  4. #4
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    J'ai utilisé l'événement OnMouseMove du RichEdit.
    Voici comment j'ai simplifié :

    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
     
    void __fastcall TForm1::RichEdit1MouseMove(TObject *Sender,
          TShiftState Shift, int X, int Y)
    {
    int DebutMot, FinMot, CharIndex, LineIndex, CharOffset, le;
    char c;
    AnsiString N;
    TPoint Pt = Point(X,Y); // X,Y du TRichEdit donc... !!!
     
    CharIndex = SendMessage(RichEdit1->Handle, EM_CHARFROMPOS, 0, int(&Pt));
    LineIndex = RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, LPARAM(CharIndex));
     
    if((LineIndex >=0) && (LineIndex < RichEdit1->Lines->Count))
        {
        N = RichEdit1->Lines->Strings[LineIndex];
        le = N.Length();
        if (CharIndex ! =-1)
            {
            c = RichEdit1->Text[CharIndex+1];
            if((c !=  ' ') && (c != '\n'))
                {
                CharOffset = CharIndex - RichEdit1->Perform(EM_LINEINDEX, WPARAM(LineIndex), 0);
                if((le > 0) && (le > CharOffset))
                    {
                    DebutMot = CharOffset + 1;
                    FinMot = DebutMot;
     
                    while((DebutMot > 0) && ( N[DebutMot] != ' ')) DebutMot--;
                    while((FinMot <= le) && (N[FinMot] != ' ')) FinMot++;
     
                    //L'écho dans un label
                    Label1->Caption = N.SubString(DebutMot, FinMot - DebutMot);
                    }
                }
            }
        } 
    }
    A plus !

  5. #5
    Membre Expert
    Avatar de Gilles Louïse
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    421
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2002
    Messages : 421
    Par défaut
    Citation Envoyé par henderson Voir le message
    Salut !

    J'ai utilisé l'événement OnMouseMove du RichEdit.
    Voici comment j'ai simplifié :

    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
     
    void __fastcall TForm1::RichEdit1MouseMove(TObject *Sender,
          TShiftState Shift, int X, int Y)
    {
    int DebutMot, FinMot, CharIndex, LineIndex, CharOffset, le;
    char c;
    AnsiString N;
    TPoint Pt = Point(X,Y); // X,Y du TRichEdit donc... !!!
     
    CharIndex = SendMessage(RichEdit1->Handle, EM_CHARFROMPOS, 0, int(&Pt));
    LineIndex = RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, LPARAM(CharIndex));
     
    if((LineIndex >=0) && (LineIndex < RichEdit1->Lines->Count))
        {
        N = RichEdit1->Lines->Strings[LineIndex];
        le = N.Length();
        if (CharIndex ! =-1)
            {
            c = RichEdit1->Text[CharIndex+1];
            if((c !=  ' ') && (c != '\n'))
                {
                CharOffset = CharIndex - RichEdit1->Perform(EM_LINEINDEX, WPARAM(LineIndex), 0);
                if((le > 0) && (le > CharOffset))
                    {
                    DebutMot = CharOffset + 1;
                    FinMot = DebutMot;
     
                    while((DebutMot > 0) && ( N[DebutMot] != ' ')) DebutMot--;
                    while((FinMot <= le) && (N[FinMot] != ' ')) FinMot++;
     
                    //L'écho dans un label
                    Label1->Caption = N.SubString(DebutMot, FinMot - DebutMot);
                    }
                }
            }
        } 
    }
    A plus !
    C'est bien mais le problème, c'est qu'en ajoutant une unité, vous êtes décalé d'une lettre. Quand donc vous pointez la dernière lettre d'un mot, il ne considère pas la modification. De plus, LineIndex ne peut pas être négatif, le premier test est donc inutile, et CharIndex non plus, le test sur CharIndex est inutile. En revanche CharIndex peut être nul, on peut donc soit faire un test sur CharIndex et ne rien faire s'il est nul et considérer CharIndex pour trouver le bon mot (et non comme vous le faites CharIndex+1) :

    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
    void __fastcall TForm1::RichEdit1MouseMove(TObject *Sender,
          TShiftState Shift, int X, int Y)
    {
    int DebutMot, FinMot, CharIndex, LineIndex, CharOffset, le;
    char c;
    AnsiString N;
    TPoint Pt = Point(X,Y); // X,Y du TRichEdit donc... !!!
     
    CharIndex = SendMessage(RichEdit1->Handle, EM_CHARFROMPOS, 0, int(&Pt));
    LineIndex = RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, LPARAM(CharIndex));
     
    if(LineIndex < RichEdit1->Lines->Count)
        {
        N = RichEdit1->Lines->Strings[LineIndex];
        le = N.Length();
        if (CharIndex)
            {
            c = RichEdit1->Text[CharIndex];
            if((c !=  ' ') && (c != '\n'))
                {
                CharOffset = CharIndex - RichEdit1->Perform(EM_LINEINDEX, WPARAM(LineIndex), 0);
                if((le > 0) && (le > CharOffset))
                    {
                    DebutMot = CharOffset + 1;
                    FinMot = DebutMot;
     
                    while((DebutMot > 0) && ( N[DebutMot] != ' ')) DebutMot--;
                    while((FinMot <= le) && (N[FinMot] != ' ')) FinMot++;
     
                    //L'écho dans un label
                    Label1->Caption = N.SubString(DebutMot, FinMot - DebutMot);
                    }
                }
            }
        } 
    }
    soit se débarasser du cas où CharIndex est nul en le mettant à un dans ce cas-là. Dans ce cas le if disparaît.

    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
    void __fastcall TForm1::RichEdit1MouseMove(TObject *Sender,
          TShiftState Shift, int X, int Y)
    {
    int DebutMot, FinMot, CharIndex, LineIndex, CharOffset, le;
    char c;
    AnsiString N;
    TPoint Pt = Point(X,Y); // X,Y du TRichEdit donc... !!!
     
    CharIndex = SendMessage(RichEdit1->Handle, EM_CHARFROMPOS, 0, int(&Pt));
    LineIndex = RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, LPARAM(CharIndex));
     
    if(LineIndex < RichEdit1->Lines->Count)
        {
        N = RichEdit1->Lines->Strings[LineIndex];
        le = N.Length();
        if (!CharIndex) CharIndex=1;
        c = RichEdit1->Text[CharIndex];
        if((c !=  ' ') && (c != '\n'))
          {
          CharOffset = CharIndex - RichEdit1->Perform(EM_LINEINDEX, WPARAM(LineIndex), 0);
          if((le > 0) && (le > CharOffset))
             {
             DebutMot = CharOffset + 1;
             FinMot = DebutMot;
     
             while((DebutMot > 0) && ( N[DebutMot] != ' ')) DebutMot--;
             while((FinMot <= le) && (N[FinMot] != ' ')) FinMot++;
     
             //L'écho dans un label
             Label1->Caption = N.SubString(DebutMot, FinMot - DebutMot);
             }
          }
       }
    }
    Merci pour ce code excellent, ça m'ennuie un peu de jouer les inspecteurs des travaux finis en oubliant de remercier le concepteur d'origine!

    À bientôt
    Gilles

  6. #6
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    Attention quand même !

    Dans le code que je propose, on peut effectivement se passer de tester CharIndex pour la bonne raison que l'on est dans la zone client de l'objet.
    On ne récupère donc jamais -1 et là tu as tout à fait raison Gilles !
    La valeur 0 demeure l'indice du premier caractère vu par le système, donc il faut en tenir compte avec les propriétés du type AnsiString.

    Par contre il faut prendre cette précaution dans le code qui est proposé par l'auteur de la discussion, parce que l'on ne peut pas savoir si X,Y appartienent bien à la zone client de l'objet donc un retour de -1 est possible.
    C'est une précaution à prendre !

    Il est vrai que l'on observe un décalage mais il est tout à fait normal.
    En effet, en arrière plan, le caractère qui est retourné (donc ça concerne sa position) est celui devant lequel le Caret viendrait se positionner si on cliquait à cette position :
    - si l'on est sur la première moitié du caractère, alors le caret se positionne devant ce caractère.
    - si l'on est sur l'autre moitié dans ce cas le caret se positionne devant le caractère suivant.
    C'est la meilleure façon pour gérer la position d'un caret mais dans le cas présent, on le ressent comme un défaut (lorsque l'on est sur la moitié droite) !

    Voici pour info le code définitif :

    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
     
    void __fastcall TForm1::RichEdit1MouseMove(TObject *Sender,
          TShiftState Shift, int X, int Y)
    {
    int DebutMot, FinMot, CharIndex, LineIndex, CharOffset;
    char c;
    AnsiString N = "";
    AnsiString R = "";
    TPoint Pt = Point(X,Y);
    CharIndex = SendMessage(RichEdit1->Handle, EM_CHARFROMPOS, 0, int(&Pt));
    LineIndex = RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, LPARAM(CharIndex));
    if(LineIndex < RichEdit1->Lines->Count)
        {
        N = RichEdit1->Lines->Strings[LineIndex];
        int le = N.Length();
     
        c = RichEdit1->Text[CharIndex+1];
        //Label2->Caption = c; //pour faire écho du défaut lié au Caret
        if((c!= ' ') && (c != '\n'))
            {
            CharOffset = CharIndex - RichEdit1->Perform(EM_LINEINDEX, WPARAM(LineIndex), 0);
            if((le > 0) && (le > CharOffset))
                {
                DebutMot = CharOffset + 1;
                FinMot = DebutMot;
     
                while( (DebutMot > 0 ) && ( N[DebutMot] != ' ') ) DebutMot--;
                while( (FinMot <= le ) && ( N[FinMot] != ' ') ) FinMot++;
     
                R = N.SubString(DebutMot, FinMot - DebutMot);
                }
            }
        }
    //Echo du résulat : soit R est vide soit R contient un mot
    Label1->Caption = R;
    }
    En tout cas... bravo à l'auteur pour avoir posé le problème.

    Je pense que ça mérite d'entrer dans les trucs et astuces et si ce n'est pas déjà fait comment se fait-il que personne n'y a jamais pensé avant ... !

    A plus !

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

Discussions similaires

  1. Aide mot sous le curseur (RichEdit)
    Par MIWAN dans le forum Débuter
    Réponses: 6
    Dernier message: 29/10/2009, 22h22
  2. [DOM] [Drag N Drop] Element HTML sous le curseur
    Par nicolas.pied dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 01/10/2007, 09h25
  3. Comment trouver le texte sous le curseur ?
    Par deetox dans le forum Langage
    Réponses: 2
    Dernier message: 06/08/2005, 13h54
  4. Comment detecter un polygon sous le curseur
    Par FreshVic dans le forum OpenGL
    Réponses: 2
    Dernier message: 04/07/2003, 10h48
  5. RichEdit tjs positionner le curseur en bas du texte
    Par microseb dans le forum C++Builder
    Réponses: 2
    Dernier message: 16/05/2003, 17h48

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