API SendMessage sous VB2005

Résolu
JessicaR44 Messages postés 116 Date d'inscription mardi 8 août 2006 Statut Membre Dernière intervention 29 septembre 2013 - 19 janv. 2007 à 22:18
JessicaR44 Messages postés 116 Date d'inscription mardi 8 août 2006 Statut Membre Dernière intervention 29 septembre 2013 - 21 janv. 2007 à 18:36
Bonsoir à tous,
Voilà, premiers pas en VB2005, et déjà dans la m...élasse! (VB2005 Express)
Sous VB6, j'utilisais l'API SendMessage pour faire une recherche dans une Combobox:



Private Declare Function SendMessage Lib "User32" Alias "SendMessageA" _
    (ByVal hWnd As Long, ByVal wMsg As Long, _
    ByVal wParam As Long, lParam As Any) As Long
Private Sub Combo1_KeyPress(KeyAscii As Integer)
  Dim CB As Long
  Dim FindString As String
  Const CB_ERR = (-1)
  Const CB_FINDSTRING = &H14C
  If KeyAscii < 32 Or KeyAscii > 127 Then Exit Sub



  FindString = Left$(Combo1.Text, Combo1.SelStart) & Chr$(KeyAscii)



  CB = SendMessage(Combo1.hWnd, CB_FINDSTRING, -1, ByVal FindString)



  If CB <> CB_ERR Then
    Combo1.ListIndex = CB
    Combo1.SelStart = Len(FindString)
    Combo1.SelLength = Len(Combo1.Text) - Combo1.SelStart
  End If
  KeyAscii = 0
End Sub




Avec l'outil "upgrade vb6 code", j'ai obtenu la sub suivante:



Private Declare Function SendMessage Lib "User32" Alias "SendMessageA" (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByRef lParam As String) As Integer
(j'ai changé le "lParam as Any" en "lParam as string")



Private Sub Combo1_KeyPress(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.KeyPressEventArgs) Handles Combo1.KeyPress
  Dim KeyAscii As Short = Asc(eventArgs.KeyChar)
  Dim CB As Integer
  Dim FindString As String
  Const CB_ERR As Short = (-1)
  Const CB_FINDSTRING As Short = &H14C
  If KeyAscii < 32 Or KeyAscii > 127 Then GoTo EventExitSub
  
  FindString = VB.Left(Combo1.Text, Combo1.SelectionStart) & Chr(KeyAscii)
  CB = SendMessage(Combo1.Handle.ToInt32, CB_FINDSTRING, -1, FindString)
  If CB <> CB_ERR Then
    Combo1.SelectedIndex = CB
    Combo1.SelectionStart = Len(FindString)
    Combo1.SelectionLength = Len(Combo1.Text) - Combo1.SelectionStart
  End If
  KeyAscii = 0
EventExitSub:
  eventArgs.KeyChar = Chr(KeyAscii)
  If KeyAscii = 0 Then
    eventArgs.Handled = True
  End If
End Sub


Ce code ne fonctionnant pas, j'ai essayé de le réécrire toute seule, comme une grande, ce qui m'a donné ceci: (pas bcp de différences avec le précédent)



Private Sub Combo1_KeyPress(ByVal eventSender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Combo1.KeyPress
  Dim CB As integer
  Dim FindString As String
  Const CB_ERR As Short = (-1)
  Const CB_FINDSTRING As Short = &H14C
  If Microsoft.VisualBasic.AscW(e.KeyChar) < 32 Or Microsoft.VisualBasic.AscW(e.KeyChar) > 127 Then Exit Sub



  FindString = VB.Left(Combo1.Text, Combo1.SelectionStart) & icrosoft.VisualBasic.AscW(e.KeyChar)
  CB = SendMessage(Combo1.Handle.ToInt32, CB_FINDSTRING, -1, FindString)
  If CB <> CB_ERR Then
    Combo1.SelectedIndex = CB
    Combo1.SelectionStart = Len(FindString)
    Combo1.SelectionLength = Len(Combo1.Text) - Combo1.SelectionStart
  End If
  e.Handled = True
End Sub


Sous VB6, dès que je tapais par ex. "t", le premier élément de la liste commencant par un "t" était sélectionné; si je tapais ensuite "u", le premier élément commencant par "tu" était sélectionné, et ainsi de suite. Ici, rien n'est sélectionné.
Quelqu'un aurait-il la gentillesse de bien vouloir me dire ou je me suis trompée
Merci 
Jessica

9 réponses

Julien237 Messages postés 883 Date d'inscription vendredi 3 novembre 2000 Statut Membre Dernière intervention 3 mars 2009 7
20 janv. 2007 à 00:18
Mmh c'est vrai, voyons cela...

Premier problème (dans l'ordre dont tu m'en parles) :
En fait le Combo a déjà un système qui fait quelque chose de semblable, mais juste avec une lettre, donc même sans code, lorsqu'on appuie sur une touche, il sélectionne l'objet commencant par cette lettre (une seule lettre, pas ce qui nous convient) pour désactiver cette fonctionnalité qui perturbe notre recherche, il faut simplement indiquer dans les évènements de touches, que l'info est traitée et que le controle ne doit plus s'en charger (cfr e.Handled = True dans les code plus bas)

Second problème :
Oui pour vérifier que ce que l'utilisateur a rentré est une lettre, on peut utiliser e.KeyCode.ToString.Lenght = 1, si c'est faux, c'est que c'est autre chose, que tu peux traiter comme tu le veux dans le Select Case plus bas (voir code).

Troisième problème :
Pour ouvrir la liste, tu fais simplement Combo1.DroppedDown = True, j'ai pas vraiment compris quand tu voulais qu'il s'ouvre, moi je trouve que ça donne bien de l'ouvrir quand on tappe dedans, arrange comme tu veux...

  Private Sub Combo1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Combo1.KeyDown
    Dim i As Integer
    If Not Combo1.DroppedDown Then Combo1.DroppedDown = True
    If e.KeyCode.ToString.Length = 1 Then
      Combo1.Tag = Combo1.Tag & e.KeyCode.ToString   'J'utilise Tag pour stocker l'info de recherche
      i = Combo1.FindString(Combo1.Tag)
      If i = -1 Then   'S'il a rien trouvé, on remet les infos de recherches à 0
        Combo1.Tag = ""
      Else
        Combo1.SelectedIndex = i
      End If
    Else
      Select Case e.KeyCode
        Case Keys.Up
          Combo1.SelectedIndex = Math.Max(0, Combo1.SelectedIndex - 1)
        Case Keys.Down
          Combo1.SelectedIndex = Math.Min(Combo1.Items.Count - 1, Combo1.SelectedIndex + 1)
          'Ici définit ce que tu veux pour chaque touche...
      End Select
    End If
    e.Handled = True
  End Sub

  Private Sub Combo1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Combo1.KeyPress
    e.Handled = True
  End Sub

  Private Sub Combo1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Combo1.KeyUp
    e.Handled = True
  End Sub

  Private Sub Combo1_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Combo1.Validated
    Combo1.Tag = ""
  End Sub

  Private Sub Form1_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
    Dim i, j As Object
    Dim a As String
    Randomize()
    For i = 0 To 10000
      a = ""
      For j = 0 To 8
        a = a & Chr(Int(Rnd(1) * 26 + 65))
      Next
      Combo1.Items.Add(a)
    Next
    Combo1.Items.Add("RECHERCHE")
  End Sub, ----
(Coloration syntaxique automatique par Kenji)

<hr size="2" width="100%" />Julien.
3
JessicaR44 Messages postés 116 Date d'inscription mardi 8 août 2006 Statut Membre Dernière intervention 29 septembre 2013
21 janv. 2007 à 18:36
Bonsoir Julien,
Tu as raison, je suis restée sous VB, tant pis pour l'API; c'est vrai que l'appel de l'API est 2 fois plus rapide, mais c'est vrai aussi que pour voir la différence, il  faut faire plusieurs centaines d'appels successifs !!
J'ai un peu modifié la source que tu m'as gentiment donnée. J'ai fait passer la gestion des touches dans le KeyPress, et je n'ai pas utilisé le Tag: je l'utilise déjà pour autre chose. Ta source est devenue ceci :

Private Sub Combo1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Combo1.KeyPress
    Dim iPos As Integer, sString As String
    If VB.AscW(e.KeyChar) < 32 Or VB.AscW(e.KeyChar) > 127 Then Exit Sub
    If Not Combo1.DroppedDown Then Combo1.DroppedDown = True
    sString = VB.Left(Combo1.Text, Combo1.SelectionStart) & e.KeyChar
    iPos = Combo1.FindString(sString)
    If iPos <> -1 Then
      Combo1.SelectedIndex = iPos
      Combo1.SelectionStart = Len(sString)
      Combo1.SelectionLength = Len(Combo1.Text) - Combo1.SelectionStart
    End If
    e.Handled = True
  End Sub

Quoi qu'il en soit, je te remercie vivement.
Passe une bonne soirée
Jessica    
3
Julien237 Messages postés 883 Date d'inscription vendredi 3 novembre 2000 Statut Membre Dernière intervention 3 mars 2009 7
19 janv. 2007 à 22:47
Une femme qui code ! (Oui lol j'ai du vérifier le pseudo quand j'ai lu "toute seule")
Claaasse, (prologin, concours d'algo l'an passé : sur 100 participants, que des hommes, quelle déception  ).
Sur ce, .Net te simplifie grandement la vie, plus besoin de message, cette fonctionnalité est accessible directement depuis une méthode de ComboBox :

  Private Sub ComboBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ComboBox1.KeyDown
    ComboBox1.Tag &= e.KeyCode.ToString  'J'utilise Tag pour stocker l'info de recherche
    Dim i As Integer = ComboBox1.FindString(ComboBox1.Tag)
    If i = -1 Then  'S'il a rien trouvé, on remet les infos de recherches à 0
      ComboBox1.Tag = ""
    Else
      ComboBox1.SelectedIndex = i
    End If
  End Sub

  Private Sub ComboBox1_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.Validated
    ComboBox1.Tag = ""
  End Sub, ----
(Coloration syntaxique automatique par Kenji)

<hr size="2" width="100%" />Julien.
0
JessicaR44 Messages postés 116 Date d'inscription mardi 8 août 2006 Statut Membre Dernière intervention 29 septembre 2013
19 janv. 2007 à 23:38
Bonsoir Julien,
Heureuse de constater que tu n'es pas macho (ou si peu), et que tu n'as visiblement rien contre le fait qu'une femme puisse coder - lol
Ceci étant dit, je crois que quelque chose ne va pas dans le code que tu m'as fourni:

Private Sub Combo1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Combo1.KeyDown
  Combo1.Tag &= e.KeyCode.ToString  'J'utilise Tag pour stocker l'info de recherche
  Dim i As Integer = Combo1.FindString(Combo1.Tag)
  If i = -1 Then  'S'il a rien trouvé, on remet les infos de recherches à 0
    Combo1.Tag = ""
  Else
    Combo1.SelectedIndex = i
  End If
End Sub



Private Sub Combo1_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Combo1.Validated
  Combo1.Tag = ""
  End Sub




Private Sub Form1_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
  Dim i, j As Object
  Dim a As String
  For i = 0 To 10000
    a = ""
    For j = 0 To 8
      a = a & Chr(Int(Rnd(1) * 26 + 65))
    Next
    Combo1.Items.Add(a)
  Next
  Combo1.Items.Add("RECHERCHE")
End Sub




- En plus l'item qu'il a trouvé, il affiche la dernière lettre frappée en 1ère position
- Problème si j'utilise la flèche "haut": il passe directement dans les "U..."
- Lors de la 1ére frappe, si le texte est blanc, mon appel à l'API ouvrait la dropdown list (CONST CB_SHOWDROPDOWN=&H14F
Je t'ai donné tout mon code pour que tu puisses le vérifier par toi-même (je sais que pour un mec, c'est difficile de croire ce qu'une nana raconte !!!  )
Merci quand même de m'avoir répondu 
Amitiés
Jessica
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
JessicaR44 Messages postés 116 Date d'inscription mardi 8 août 2006 Statut Membre Dernière intervention 29 septembre 2013
20 janv. 2007 à 00:50
Re,
C'est déjà bcp mieux, mais c'est pas encore aussi bien que ce que je faisais avec mon SendMessage, dans lequel je gérais les SelStart et SelLenght. (Hé oui, difficile à satisfaire, une femme !!). Si tu as encore VB6, essaie le 1er code que j'ai mis dans mon 1er post: tu verras
Je vais essayer d'effectuer certaines modifs ce week-end. Je te tiens au courant.
En tout cas, un tout grand merci pour ta gentillesse
Amitiés
Jessica
0
JessicaR44 Messages postés 116 Date d'inscription mardi 8 août 2006 Statut Membre Dernière intervention 29 septembre 2013
20 janv. 2007 à 00:56
Re,
Je viens de me relire: je suis désolée pour le "c'est déjà beaucoup mieux" : j'y connais rien (en tout cas en VB2005), et c'est comme si je jugeais ton travail. J'espère que tu ne l'as pas mal pris.
Bonne nuit
Jessica


 
0
Julien237 Messages postés 883 Date d'inscription vendredi 3 novembre 2000 Statut Membre Dernière intervention 3 mars 2009 7
20 janv. 2007 à 07:19
Non non, pas de problèmes :p
Pour les SelStart et SelLenght, ça c'est à toi de faire comme tu veux, elles ont juste changé de nom et s'appellent maintenant SelectionStart et SelectionLenght, je pars maintenant pour jouer à un mariage, et je ne saurais plus t'aider avant demain soir.
Bonne chance !
<hr size="2" width="100%" />Julien.
0
JessicaR44 Messages postés 116 Date d'inscription mardi 8 août 2006 Statut Membre Dernière intervention 29 septembre 2013
20 janv. 2007 à 21:19
Bonsoir à tous,
Bonsoir Julien,
OK, j'ai trouvé ce qui avait foiré avec l'utilisation de l'API SendMessage avec VB2005. Je me suis focalisée sur la sub KeyPress, alors que l'erreur était autre part, à savoir, dans la déclaration de la fonction :
Il s'agissait d'un code VB6, qui a été converti par VB2005
Sous VB6, il y avait
Private Declare Function SendMessage Lib "User32" Alias "SendMessageA" _
    (ByVal hWnd As Long, ByVal wMsg As Long, _
    ByVal wParam As Long, lParam As Any) As Long
VB2005 en a fait
Private Declare Function SendMessage Lib "User32" Alias "SendMessageA" _
    (ByVal hWnd As Integer, ByVal wMsg As Integer, _
     ByVal wParam As Integer, ByRef lParam As String) As Integer

Ici, j'ai changé le "lParam as Any" en "lParam as string" (comme me le conseillait VB), mais je n'ai pas fait attention au "Byref" qu'il avait ajouté!
Tout est rentré dans l'ordre lorsque j'ai déclaré "ByVal lParam As String".
J'ai fait quelques essais, et la recherche via l'appel de l'API est +/- 2 fois plus rapide.
Ma question maintenant est donc de savoir si techniquement, il est préférable d'utiliser la méthode de combobox de VB2005 ou l'appel de l'API ? Perso, je préférerais l'Api, mais bon ... j'attends vos suggestions
Merci d'avance
Jessica




 
0
Julien237 Messages postés 883 Date d'inscription vendredi 3 novembre 2000 Statut Membre Dernière intervention 3 mars 2009 7
21 janv. 2007 à 17:50
Perso je dirais la méthode de la combobox tout simplement parce que ça m'étonnerais que le traitement du message soit autre qu'un simple appel à cette fonction... Fais simplement ce que tu préfère... Je crois pas qu'un autre te répondras parce que personne d'autre que moi n'a suivi la discussion. (On répond souvent aux messages qui ont été écris les 3-4 dernières heures et à ceux qu'on a commencé et dont on reçoit les mails, donc je pense pas qu'un autre passera par ici )

<hr size="2" width="100%" />Julien.
0
Rejoignez-nous