Vb6: Api GetTextExtentExPointI

Résolu
kibap Messages postés 4 Date d'inscription lundi 16 avril 2007 Statut Membre Dernière intervention 2 juillet 2007 - 28 juin 2007 à 15:35
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 - 2 juil. 2007 à 12:55
Je voudrai utiliser cet Api mais je me heurte à un plantage.

Voici ma déclaration en vb:
Public Declare Function GetTextExtentExPointI Lib "gdi32.dll" (ByVal hdc As Long, ByVal pgiIn As String, ByVal cgi As Long, ByVal nMaxExtent As Long, ByRef lpnFit As Long, ByRef alpDx As Long, ByRef lpSize As SIZE) As Long

Type SIZE
   X as long
   Y as long
End Type

Voici comment je l'utilise dans mon form:

dim MyString as string
dim lngFit as long
dim lngDx as long
dim lngSize as Size
dim lngRet as long

MyString="abcdefghijklmn"

 lngRet = GetTextExtentExPointI(Me.hdc, MyString, Len(MyString), Label1.Width, lngFit, lngDx, lngSize)

Avec Label1 sur ma form.

Dans les specifications de l'Api, le parametre alpDx est définit comme un pointeur vers un array d'integer. J'ai essayé de le remplacer par un tableau de nombre, mais rien n'y fait.

Quelqu'un aurait-il une idée?

Merci,

11 réponses

jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
28 juin 2007 à 17:31
Quel est ton OS et sous quel langage développes-tu ?

Le seul appel de cette fonction fait chez moi (WIN 2000 et VB5) planter VB !
3
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
28 juin 2007 à 19:00
le second param est l'adresse d'un tableau de DWORDs (INT32).
le suivant c'est le nombre de INT32 partant de cette adresse.

Dim lTab(6) As Long ' 7 elems dispos

et tu passeras: lTab(0), 7

ciao...
BruNews, MVP VC++
3
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
29 juin 2007 à 08:44
Salut,

Que veux tu faire exactement ? Tu as regardé du côté de DrawText, qui gère automatiquement le wrap ?

Voilà un code qui fait un wrap au niveau caractère.

Je me suis pas servi du tableau (Je lui passe NULL)... A ce que je comprend, il stocke la position des caractères qui tiennent sur la ligne, donc j'ai pas compris ce que j'allais pouvoir en faire.

J'ai fait une première implémentation (Redraw1), mais elle me plaisait pas car elle faisait trops de recopie de chaîne.
Donc j'en ai fait une deuxième avec des pointeurs (Redraw2), sensée être nettement plus rapide (Aucune recopie de chaîne).
Attention, y a de l'unicode -> les * 2 un peu partout.

==============================================================
Option Explicit

Private Type SIZEL
    cx As Long
    cy As Long
End Type

Private Type TEXTMETRIC
        tmHeight As Long
        tmAscent As Long
        tmDescent As Long
        tmInternalLeading As Long
        tmExternalLeading As Long
        tmAveCharWidth As Long
        tmMaxCharWidth As Long
        tmWeight As Long
        tmOverhang As Long
        tmDigitizedAspectX As Long
        tmDigitizedAspectY As Long
        tmFirstChar As Byte
        tmLastChar As Byte
        tmDefaultChar As Byte
        tmBreakChar As Byte
        tmItalic As Byte
        tmUnderlined As Byte
        tmStruckOut As Byte
        tmPitchAndFamily As Byte
        tmCharSet As Byte
End Type

Const sText As String = "Borland Delphi est un environnement de programmation visuelle orienté objet permettant de développer des applications 32 bits en vue de leur déploiement sous Windows et sous Linux. Avec Delphi, vous pouvez créer de puissantes applications avec un minimum de programmation."

' Pour Redraw1
Private Declare Function GetTextExtentExPoint1 Lib "gdi32" Alias "GetTextExtentExPointA" (ByVal hdc As Long, ByVal lpszStr As String, ByVal cchString As Long, ByVal nMaxExtent As Long, ByRef lpnFit As Long, alpDx As Any, ByRef lpSize As SIZEL) As Long

' Pour Redraw2
Private Declare Function GetTextExtentExPoint2 Lib "gdi32" Alias "GetTextExtentExPointW" (ByVal hdc As Long, ByVal lpszStr As Long, ByVal cchString As Long, ByVal nMaxExtent As Long, ByRef lpnFit As Long, alpDx As Any, ByRef lpSize As SIZEL) As Long
Private Declare Function TextOut Lib "gdi32" Alias "TextOutW" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal lpString As Long, ByVal nCount As Long) As Long
Private Declare Function GetTextMetrics Lib "gdi32" Alias "GetTextMetricsA" (ByVal hdc As Long, lpMetrics As TEXTMETRIC) As Long

Private Sub Form_Paint()
  Redraw1
End Sub

Private Sub Form_Resize()
  Redraw2
End Sub

Private Sub Redraw1()
  Dim nFit As Long               ' Nombre de caractères placés dans la ligne
  Dim uSize As SIZEL             ' Taille prise par le texte
  Dim sLine As String            ' Une ligne à afficher
  Dim sToDraw As String          ' Chaîne restant à dessiner

  ' On efface le contenu de la form
  Me.Cls

  ' Il reste tout le texte à dessiner
  sToDraw = sText

  ' Tant qu'il reste du texte à dessiner
  While sToDraw <> ""
    ' On calcule le nombre de caractères affichables dans la ligne
    Me.ScaleMode = vbPixels
    GetTextExtentExPoint1 Me.hdc, sToDraw, Len(sToDraw), Me.ScaleWidth, nFit, ByVal 0&, uSize

    ' On récupère les caractères affichables dans la ligne
    sLine = Left$(sToDraw, nFit)

    ' On prépare les caractères suivant pour la ligne suivante
    sToDraw = Mid$(sToDraw, nFit + 1, Len(sToDraw) - nFit)

    ' On dessine la ligne
    Print sLine
  Wend
End Sub

Private Sub Redraw2()
  Dim nFit As Long                ' Nombre de caractères placés dans la ligne
  Dim uSize As SIZEL              ' Taille prise par le texte
  Dim uTextMetrics As TEXTMETRIC  ' Pour récupérer la hauteur d'une ligne
  Dim nY As Long                  ' Ordonnée de dessin du texte
  Dim nBegin As Long              ' Début du texte à dessiner
  Dim nAdrText As Long            ' Adresse de la chaîne

  ' On efface le contenu de la form
  Me.Cls

  ' Récupération de la hauteur d'une ligne (Devrait être dans Form_Load)
  GetTextMetrics Me.hdc, uTextMetrics

  ' Il reste tout le texte à dessiner
  nAdrText = StrPtr(sText)
  nBegin = nAdrText
  nY = 0

  ' Tant qu'il reste du texte à dessiner
  While nBegin < nAdrText + Len(sText) * 2
    ' On calcule le nombre de caractères affichables dans la ligne
    Me.ScaleMode = vbPixels
    GetTextExtentExPoint2 Me.hdc, nBegin, (nAdrText + Len(sText) * 2 - nBegin) / 2, Me.ScaleWidth, nFit, ByVal 0&, uSize

    ' On dessine la ligne
    TextOut Me.hdc, 0, nY, nBegin, nFit

    ' On se place sur la suite du texte
    nBegin = nBegin + nFit * 2

    ' Passage à la ligne
    nY = nY + uTextMetrics.tmHeight
  Wend
End Sub
3
kibap Messages postés 4 Date d'inscription lundi 16 avril 2007 Statut Membre Dernière intervention 2 juillet 2007
29 juin 2007 à 19:02
Merci pour vos réponses.
1. jmfmarques: Je suis sur xp. et c'est du vb.


2. BruNews: Merci pour le tableau. L'appel de la fonction ne plante plus.


3. rt15: Merci, Ton code dans Redraw1 est le même que le mien. sauf que tu écrit sur le formulaire, alors que j'écris dans un Label. A la place de me.scalewidth, j'ai Label1.width.

Mon objectif est juste d'écrire un texte dans un Label avec la possibilité de couper ce dernier (le texte) en mettant des pontillés si celui-ci dépasse la taille de mon label. (Montrer à l'utilisateur que le texte est plus grand que celui affiché).
Donc j'ai besoin de connaitre, suivant ma chaine, le nombre de caractère max que le label peut contenir.
Pour l'instant le nombre de caractère retourné(lngFit) n'est pas bon. J'ai l'impression que je dois convertir la taille du Label1 (label1.width) que je passe à la fonction.
Vos iddées sont les bienvenues.
Merci,

 


 
3

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

Posez votre question
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
29 juin 2007 à 19:21
Pas possible d'ajouter le style SS_ENDELLIPSIS au label ?
Si oui, Windows fera le calcul et l'affichage tout seul, nettement préférable.

ciao...
BruNews, MVP VC++
3
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
2 juil. 2007 à 10:05
Salut,

lngFit pas bonne -> GetTextExtentExPoint2 veut la largeur de l'espace disponible en unité logique. (On peut spécifier la taille d'une unité logique via SetMapMode). A ce que j'ai cru comprendre, VB6 est configuré en MM_TEXT (Une unité = un pixel) par défaut (Mais ça me paraît bizarre...). Mais il propose en plus de changer le système de coordonné pour chaque contrôle, à l'aide de la propriété ScaleMode. Cette propriété change les valeurs de ScaleWidth et ScaleHeight du contrôle courant, et peut modifier les propriété Width et Height des contrôles contenus dans ce contrôle. Par défaut, ScaleMode est à twips.

Donc dans ton cas, il devrais suffire de faire :

Label1.ScaleMode = vbPixels
GetTextExtentExPoint2  (...) , Label1.ScaleWidth,  (...)

ajouter le style SS_ENDELLIPSIS -> Pour ça, il faut pouvoir récupérer un handle sur le label : Il faut qu'il est une propriété hwnd (Encore qu'on peut peut être le récupérer avec les routines d'énumération de fenêtre genre une succession de GetWindow). Une fois qu'on a le handle, il devrait suffire de faire un GetWindowLong en passant le handle du label et GWL_STYLE en index. Genre :

dim nStyle As Long
nStyle = GetWindowLong(Label1.hwnd, GWL_STYLE)

Puis on ajoute le style :

nStyle = nStyle or SS_ENDELLIPSIS

(Y a aussi SS_WORDELLIPSIS qui peut peut être plus te convenir)

Et on remet le style en place :
SetWindowLong Label1.hwnd, GWL_STYLE, nStyle


                
3
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
2 juil. 2007 à 10:22
C'est vrai qu'il n'y a pas de "propriété" hwnd sur un label VB....
Le plus bizzare c'est qu'on puisse supporter toutes ces limitations.

ciao...
BruNews, MVP VC++
3
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
2 juil. 2007 à 12:55
Pas sûr qu'il marche ton SendMessage. D'une part TB_SETSTYLE à l'air d'être fait pour les toolbar, d'autre part, tu zapes les styles que ton contrôle avait : tu remplace au lieu d'ajouter.

Pour le handle, comme je le disais, tu peux le retrouver avec GetWindow, mais c'est très chiant. Les fenêtre forment une arborescence, il te suffit de la parcourir jusqu'à tomber sur ton contrôle. Par exemple, s'il est dans la form, tu commence avec un :

hHandle = GetWindow(Form1.hwnd, GW_CHILD)

puis tu enchaîne avec des :


hHandle = GetWindow(hHandle , GW_HWNDNEXT)

jusqu'à tomber sur ton contrôle... spy++ fournit avec VS permet de connaître la structure de l'arborescence des fenêtres. Mais d'après l'aide, peut être qu'en placant ton contrôle au premier plan (Devant tous les autres), tu tomberas directement dessus avec le premier GW_CHILD.

Tu peux peut être aussi regarder FindWindow.

C'est vrai que ça les auraient pas tuer de mettre la propriété...
3
jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
28 juin 2007 à 16:50
Curieux, ton triuc ....

je ne connais pas ta fonction, mais je connais celle-ci :

Private Declare Function GetTextExtentPoint32 Lib "gdi32" Alias "GetTextExtentPoint32A" (ByVal hdc As Long, ByVal lpsz As String, ByVal cbString As Long, lpSize As POINTAPI) As Long
qui  n'a que 4 paramètres qui sont les suivants :

· hdc
Identifies the device context.




· lpString
Points to the string of text. The string does not need to be zero-terminated, since cbString specifies the length of the string.




· cbString
Specifies the number of characters in the string.




· lpSize
Points to a SIZE structure in which the dimensions of the string are to be returned.
0
kibap Messages postés 4 Date d'inscription lundi 16 avril 2007 Statut Membre Dernière intervention 2 juillet 2007
2 juil. 2007 à 12:35
Sais-tu comment avoir le handle d'un label en vb?
Je pense suivant ton conseil essayer ceci:
Sendmessage(Mon Label Handle, TB_SETSTYLE, 0,SS_ENDELLIPSIS)

Merci.
0
kibap Messages postés 4 Date d'inscription lundi 16 avril 2007 Statut Membre Dernière intervention 2 juillet 2007
2 juil. 2007 à 12:41
Oups...message en trops. Pas vu les votres avant. pas tenir compte.
0
Rejoignez-nous