none
VB 2010 – Surcharge de la méthode Show d’un ToolTip RRS feed

  • Question

  • Bonjour à tous,

    Je souhaite personnaliser l’affichage d’un contrôle ToolTip en ajoutant à la liste de surcharge de la méthode Show une nouvelle surcharge aux surcharges déjà existante.

    Overloads Sub Show(ByVal window As IWin32Window)

             …

    End Sub

    La méthode Show provoque l’affichage du ToolTip, mais sans implémentation de code à l’intérieur de la procédure celui-ci ne pourra pas s’afficher. Aussi ma question est la suivante : Quels codes faut-il mettre à l’intérieur de la procédure pour que celui-ci affiche mon ToolTip ?

    Liste des surcharges de la méthode Show du contrôle ToolTip

     

    Merci pour votre aide.

    Cordialement

    SL

    mardi 25 novembre 2014 15:23

Réponses

  • Les méthodes Show appellent une méthodes private (donc non surchargeable) qui est la suivante :

           private void ShowTooltip(string text, IWin32Window win, int duration)
            {
                if (win == null)
                {
                    throw new ArgumentNullException("win");
                }
                Control control = win as Control;
                if (control != null)
                {
                    NativeMethods.RECT rECT = new NativeMethods.RECT();
                    UnsafeNativeMethods.GetWindowRect(new HandleRef(control, control.Handle), ref rECT);
                    Cursor currentInternal = Cursor.CurrentInternal;
                    Point position = Cursor.Position;
                    Point point = position;
                    Screen screen = Screen.FromPoint(position);
                    if (position.X < rECT.left || position.X > rECT.right || position.Y < rECT.top || position.Y > rECT.bottom)
                    {
                        NativeMethods.RECT rECT1 = new NativeMethods.RECT()
                        {
                            left = (rECT.left < screen.WorkingArea.Left ? screen.WorkingArea.Left : rECT.left),
                            top = (rECT.top < screen.WorkingArea.Top ? screen.WorkingArea.Top : rECT.top),
                            right = (rECT.right > screen.WorkingArea.Right ? screen.WorkingArea.Right : rECT.right),
                            bottom = (rECT.bottom > screen.WorkingArea.Bottom ? screen.WorkingArea.Bottom : rECT.bottom)
                        };
                        point.X = rECT1.left + (rECT1.right - rECT1.left) / 2;
                        point.Y = rECT1.top + (rECT1.bottom - rECT1.top) / 2;
                        control.PointToClientInternal(point);
                        this.SetTrackPosition(point.X, point.Y);
                        this.SetTool(win, text, ToolTip.TipInfo.Type.SemiAbsolute, point);
                        if (duration > 0)
                        {
                            this.StartTimer(this.window, duration);
                            return;
                        }
                    }
                    else
                    {
                        ToolTip.TipInfo item = (ToolTip.TipInfo)this.tools[control];
                        if (item != null)
                        {
                            ToolTip.TipInfo tipType = item;
                            tipType.TipType = tipType.TipType | ToolTip.TipInfo.Type.SemiAbsolute;
                            item.Caption = text;
                        }
                        else
                        {
                            item = new ToolTip.TipInfo(text, ToolTip.TipInfo.Type.SemiAbsolute);
                        }
                        item.Position = point;
                        if (duration > 0)
                        {
                            if (this.originalPopupDelay == 0)
                            {
                                this.originalPopupDelay = this.AutoPopDelay;
                            }
                            this.AutoPopDelay = duration;
                        }
                        this.SetToolTipInternal(control, item);
                    }
                }
            }

    Et la méthode SetToolTipInternal appelle une API Win32 (SendMessage). C'est donc un "tooltip" de Windows qui apparait, pas un tooltip managé donc non personnalisable.

    Vu tout ce que vous demandez, pourquoi ne pas vous pencher plutôt sur WPF ?



    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    mardi 25 novembre 2014 17:08

Toutes les réponses

  • Les méthodes Show appellent une méthodes private (donc non surchargeable) qui est la suivante :

           private void ShowTooltip(string text, IWin32Window win, int duration)
            {
                if (win == null)
                {
                    throw new ArgumentNullException("win");
                }
                Control control = win as Control;
                if (control != null)
                {
                    NativeMethods.RECT rECT = new NativeMethods.RECT();
                    UnsafeNativeMethods.GetWindowRect(new HandleRef(control, control.Handle), ref rECT);
                    Cursor currentInternal = Cursor.CurrentInternal;
                    Point position = Cursor.Position;
                    Point point = position;
                    Screen screen = Screen.FromPoint(position);
                    if (position.X < rECT.left || position.X > rECT.right || position.Y < rECT.top || position.Y > rECT.bottom)
                    {
                        NativeMethods.RECT rECT1 = new NativeMethods.RECT()
                        {
                            left = (rECT.left < screen.WorkingArea.Left ? screen.WorkingArea.Left : rECT.left),
                            top = (rECT.top < screen.WorkingArea.Top ? screen.WorkingArea.Top : rECT.top),
                            right = (rECT.right > screen.WorkingArea.Right ? screen.WorkingArea.Right : rECT.right),
                            bottom = (rECT.bottom > screen.WorkingArea.Bottom ? screen.WorkingArea.Bottom : rECT.bottom)
                        };
                        point.X = rECT1.left + (rECT1.right - rECT1.left) / 2;
                        point.Y = rECT1.top + (rECT1.bottom - rECT1.top) / 2;
                        control.PointToClientInternal(point);
                        this.SetTrackPosition(point.X, point.Y);
                        this.SetTool(win, text, ToolTip.TipInfo.Type.SemiAbsolute, point);
                        if (duration > 0)
                        {
                            this.StartTimer(this.window, duration);
                            return;
                        }
                    }
                    else
                    {
                        ToolTip.TipInfo item = (ToolTip.TipInfo)this.tools[control];
                        if (item != null)
                        {
                            ToolTip.TipInfo tipType = item;
                            tipType.TipType = tipType.TipType | ToolTip.TipInfo.Type.SemiAbsolute;
                            item.Caption = text;
                        }
                        else
                        {
                            item = new ToolTip.TipInfo(text, ToolTip.TipInfo.Type.SemiAbsolute);
                        }
                        item.Position = point;
                        if (duration > 0)
                        {
                            if (this.originalPopupDelay == 0)
                            {
                                this.originalPopupDelay = this.AutoPopDelay;
                            }
                            this.AutoPopDelay = duration;
                        }
                        this.SetToolTipInternal(control, item);
                    }
                }
            }

    Et la méthode SetToolTipInternal appelle une API Win32 (SendMessage). C'est donc un "tooltip" de Windows qui apparait, pas un tooltip managé donc non personnalisable.

    Vu tout ce que vous demandez, pourquoi ne pas vous pencher plutôt sur WPF ?



    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    mardi 25 novembre 2014 17:08
  • Bonjour Richard,

    Merci pour ces explications ainsi que le code VB6 pour la surcharge de la méthode Show. C’est très intéressant le code avec des API 32. Je n’ai pas connu la programmation sous VB6 mais j’ai souvent vu avec VBA des personnes qui utilisent des fonctions API 32 pour donner plus de souplesse à leur programme. Ca ne semble pas très compliqué, la seule difficulté est qu’il est très difficile voir impossible de trouver une définition correcte de toutes ces fonctions et procédures et bien sur très risqué de les utiliser sans connaissance.

    Il est dommage qu’il n’est pas été prévu davantage de surcharge pour cette méthode car lorsque l’on travail avec un ToolTip en personnalisant le rendu graphique (OwnerDraw=True), il est alors possible d’intégrer à ce dernier tout le texte souhaité et l’argument « text » de la méthode devient gênant car il celui-ci induit deux effets négatifs sur l’affichage de ce dernier.

    Le premier effet est qu’il est impossible de passer une chaîne de texte vide (sans caractère) pour se passer de cet argument faute de quoi le ToolTip ne s’affiche pas même si vous fournissez le code pour dessiner l’info-bulle !

    Le second effet est induit par le premier, il est impossible de ne pas entrer de caractère dans l’argument « text » de la méthode aussi pour obliger l’affichage il faudra passer au moins un caractère. Lorsque l’on travaille avec la propriété OwnerDraw à True, la forme et le contenu y compris le texte sont gérés par le développeur et auquel cas rien d’autre ne doit apparaître au niveau de l’affichage du ToolTip personnalisé. Ici ce n’est pas le cas, du fait du caractère unique entré une petite zone de texte avec le caractère transmis, sur couleur de fond par défaut d’un ToolTip, apparaît en haut et à gauche !

    Si vous voulez un exemple concret, voyez mon thread récent (Problème avec le déclenchement d’un événement). J’ai corrigé mon code et celui-ci fonctionne très bien, récupérez le code et intégré le dans un projet Windows Form, lancez le et déplacez le formulaire. Le ToolTip devrait suivre le mouvement du formulaire. Observez la zone de texte sur fond rouge qui se déplace avec le ToolTip personnalisé…

    J’envisage dans quelques semaines de passer à WPF car il permet grâce à son langage XAML d’enrichir considérablement les interfaces graphiques de façon plus simple qu’en utilisant VB. Mais VB me paraît plus simple d’utilisation car justement il n’a pas XAML ! Je fais de la programmation depuis peut de temps et je dois encore approfondir plusieurs concepts importants avant de passer sur un outil de programmation plus sophistiqué.

    En ce moment je travaille sur la conception d’événements personnalisés et justement le contrôle ToolTip ne fournit que deux événements. J’ai commencé la réalisation d’un projet visant à lui intégrer un ou plusieurs autres événements mais je rencontre un problème lié au concept d’héritage et au polymorphisme. La documentation en ligne MSDN fournit beaucoup d’information à ce propos mais celle-ci reste très abstraite pour moi aussi je suis à la recherche d’un document avec des exemples afin de mieux les appréhender.

    La problématique que je rencontre est la suivante. J’ai créé un ToolTip lequel s’affiche en dehors de la zone graphique du formulaire auquel il est rattaché. Une fois affichée une procédure que j’ai conçue me permet de changer la forme du curseur lors du survol de celui-ci par la souris mais une procédure inhérente au formulaire fait que lorsque l’on déplace la souris en dehors du formulaire le curseur de la souris passe automatiquement à sa forme par défaut. Comment empêcher cette action de se produire ?

    Merci pour votre aide

    Cordialement

    SL

    mercredi 26 novembre 2014 09:26
  • En dehors du formulaire = n'appartient plus à votre appli => normal que Windows reprenne la main (sinon ce serait le borde... ;-))

    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    mercredi 26 novembre 2014 09:30
  • NB : Depuis 14 ans que j'utilise le Framework .NET, je n'ai jamais eu besoin d'une quelconque API Win32 (alors que c'était le cas sous VB6).

    Donc approfondissez d'abord votre connaissance du Framework avant de faire du Win32.

    Et encore une fois, je pense que vous avez tout intérêt à vous pencher sur WPF que sur les Windows Forms : les possibilités graphiques sont décuplées. (et Windows Forms n'évolue plus depuis pas mal d'année => abandonné par MS)


    Richard Clark
    Consultant - Formateur .NET
    http://www.c2i.fr
    Depuis 1996: le 1er site .NET francophone

    mercredi 26 novembre 2014 09:32
  • Bonsoir Richard,

    Merci pour vos conseils.

    Je vais me documenter davantage sur les possibilités du Framework. Quand à WPF, je pense que c'est une aventure qui débutera bientôt.

    Cordialement

    SL

    vendredi 28 novembre 2014 21:16