SUPINFO International University

SUPINFO Institute of Information Technology
Laboratoire Microsoft




Tous les Articles du Laboratoire Microsoft

Programmation sur Tablet PC : IHM de la barre de recherche IE (partie 1)
Accueil > Articles > Matériels
Auteurs 
Julien BAKMEZDJIAN



 Tous les articles de cet auteur

0,4/5

Mauvais


30915
130/58

 

Introduction

 

            Dans l’article précédent, nous avons vu comment créer et intégrer à Internet Explorer (IE) une barre d’outils générique en .Net. Cette barre doit, rappelons le, permettre de naviguer sur le web au moyen du stylet d’un TabletPC. Nous devons donc maintenant implémenter les parties IHM et traitements d’arrière plan de cette barre.

            Cet article sera le premier volet de la partie IHM. Il y sera question de la création de trois contrôles utilisateurs, et du réglage de certaines de leurs propriétés. Le deuxième article de cette partie se concentrera sur le contrôle principal de cette barre, à savoir la zone de saisie des urls. Dans aucun de ces articles ne sera rappelée la démarche détaillée de création de contrôles. Cette démarche a, en effet, déjà fait l’objet d’un article.

            Pour l’heure, nous allons présenter deux contrôles très proches : les FlatIEButton et les CheckBoxEx. Puis nous détaillerons le contrôle permettant d’afficher l’historique sous la zone de saisie des urls (ListBoxEx).

           

 

Se fondre dans Internet Explorer

 

            Le premier objectif de notre barre d’outils en matière d’IHM était de se fondre le plus possible dans IE. Pour cela, il fallait réaliser des contrôles dont le comportement se rapprochait au maximum de celui des contrôles standard d’IE. Cela impliquait, par exemple, de créer des contrôles sans bord, s’éclaircissant lorsque la souris les survole. Il fallait également tenir compte des contraintes spéciales à la programmation pour TabletPC exposées dans le premier article, à savoir agrandir les zones actives des contrôles (très important pour les RadioButton et les CheckBox), fournir des zones de saisie de l’encre assez grandes…

            C’est donc dans cette optique que nous avons créé deux nouveaux contrôles : les FlatIEButton et les CheckBoxEx.

 

FlatIEButton

 

            Les FlatIEButton, dans la version finale de notre barre d’outils, correspondent aux boutons de validation (boutons « .com », « .fr »…) :

 


 

            Ils ont le même comportement que les boutons standard (ils en héritent), à quelques exceptions près. Premièrement, ils ne possèdent pas de bords, ne laissant donc apparaître que leur texte et leur image. Ensuite, ils prennent une forme 3D et s’éclaircissent lorsque la souris les survole.


Cette propriété d’éclaircissement se doit d’ailleurs d’être débrayable. Enfin, ils ne doivent pas afficher les cadres habituels indiquant qu’un contrôle a le focus.

 

            Pour éviter qu’un cadre ne s’affiche, il suffit de s’abonner à l’événement Paint du bouton. Celui-ci est appelé immédiatement après que le bouton se soit redessiné. Il s’agit ici d’effacer le cadre extérieur en dessinant par-dessus un rectangle de la couleur de fond du bouton :

 

      this.Paint += new PaintEventHandler(FlatIEButton_OnPaint);

 

dans le constructeur, puis :

 

      private void FlatIEButton_OnPaint(object sender, PaintEventArgs e)

      {

            // Si la souris n'est pas au dessus

            if(!MouseOver)

            {

                  // On redessine le contrôle sans bords

                  ControlPaint.DrawBorder(

                        e.Graphics,

                        this.DisplayRectangle,

                        this.BackColor,   2, ButtonBorderStyle.Solid,

                        this.BackColor, 2, ButtonBorderStyle.Solid,

                        this.BackColor,   2, ButtonBorderStyle.Solid,

                        this.BackColor,   2, ButtonBorderStyle.Solid);

            }

      }

 

            Ensuite, pour donner au bouton un aspect 3D au survol de la souris, il faut modifier la propriété FlatStyle :

 

      // On donne l'aspect 3D lorsque la souris le survole

      FlatStyle = System.Windows.Forms.FlatStyle.Popup;

 

            Pour éclaircir le bouton, nous avons créé deux Bitmap, l’une pour l’image normale et l’autre pour l’image éclairée. Nous leur avons attaché deux propriétés publiques. Il appartient à l’utilisateur du contrôle de créer et d’attacher deux Bitmap de son choix. Nous avons enfin créé une propriété HighlightButton qui valide ou invalide l’éclaircissement. On permute les Bitmap et on change la couleur de fond dans une méthode RefreshImage qui est appelée sur les événements MouseEnter et MouseLeave (si HighlightButton est vrai) :

 

      private void RefreshImage()

      {

            // Si la demande d'éclaircissement du contrôle est spécifiée

            if(HighlightButton)

            {

                  // si la souris est sur le contrôle, on "éclaire" l'image

                  if(MouseOver)

                  {

                        // On change la couleur de fond

                        this.BackColor = System.Drawing.Color.FromArgb(247,247,231);

                        // On change l'image du bouton

                        this.Image = Image_Highlighted;

                  }

                  // Si la souris n'est pas sur le contrôle

                  else

                  {

                        // On change la couleur de fond

                        this.BackColor = System.Drawing.SystemColors.Control;

                        // On change l'image du bouton

                        this.Image = Image_Unhighlighted;                                }

            }

      }

 

            Enfin, le contrôle ne doit pas prendre le focus (pour éviter, entre autre chose, l’apparition du « rectangle de focus »). Pour cela, une seule ligne dans le constructeur suffit :

 

      // on interdit la prise de focus

      SetStyle(ControlStyles.Selectable, false);

 

 

Le code complet de ce contrôle est téléchargeable ici.

 

CheckBoxEx

 

            Ce contrôle est utilisé pour les préfixes d’autocomplétion : « http », « www » …

 

 


 

 

            Le code de ce contrôle est quasiment identique à celui de FlatIEButton, mis à part que nous héritons de CheckBox au lieu de Button. De plus, il faut donner l’apparence « Bouton » à la CheckBox pour agrandir sa zone active. Ceci se fait dans le constructeur en une ligne :

 

      // On donne à la case à cocher l'apparence d'un bouton

      this.Appearance = Appearance.Button;

 

            Enfin, quatre Bitmap sont maintenant nécessaires (coché/décoché et éclairé/non éclairé). Cette fois-ci, elles sont initialisées afin qu’une case à cocher soit affichée par défaut.

 

Le code complet de la CheckBoxEx est disponible ici.

 

Exemple d’utilisation du FlatIEButton et du CheckBoxEx

 

            Nous allons ici vous donner un exemple de création et d’initialisation d’un FlatIEButton. Ceci s’appliquerait également à une CheckBoxEx.

           

            Après avoir créé un FlatIEButton, il faut créer les deux Bitmap à afficher :

 

      private System.Drawing.Bitmap okBitmap;

      private System.Drawing.Bitmap ok_highlightedBitmap;

 

            Il faut ensuite charger les Bitmap, leur affecter une couleur transparente (si souhaité) puis les associer au bouton, dans le constructeur du Container par exemple :

 

      // Chargement des images à mettre dans les Bitmaps

      okBitmap = new                                                                                       System.Drawing.Bitmap(assembly.GetManifestResourceStream("InkToolBar.  Images.ok.bmp"));

     

      ok_highlightedBitmap = new System.Drawing.Bitmap(assembly.GetManifestResourceStream("InkToolBar.      Images.ok_highlighted.bmp"));

...

      // La couleur blanche est maintenant la couleur transparente

      okBitmap.MakeTransparent(Color.White);

      ok_highlightedBitmap.MakeTransparent(Color.White);

...

      // Lien entre l'image et son Bitmap

      this.okButton.Image_Unhighlighted = okBitmap;

      this.okButton.Image_Highlighted = ok_highlightedBitmap;

 

            Tous ces contrôles sont dans un assembly qui vous est proposé en fin d’article.         

 

Affichage de l’historique : ListBoxEx

 

Présentation du contrôle ListBoxEx

 

            Nous désirons ici réaliser un menu déroulant affichant l’historique en fonction des premières lettres saisies dans la zone d’adresses, comme dans la barre traditionnelle d’IE. Cette liste devra donc pouvoir sortir de la barre. De plus, elle devra suivre les changements de taille de la zone de saisie qui, comme nous le verrons dans le prochain article, s’élargit lorsque le stylet s’approche :

 


 

Lorsque le stylet est au dessus de la zone de saisie, l’historique s’agrandit également :

 

 

            Enfin, nous souhaitons que les lignes de l’historique soient mises en surbrillance lorsque le pointeur de la souris passe au dessus.

 

            Nous allons donc créer un nouveau contrôle hérité de ListBox : ListBoxEx. Ce contrôle est instancié dans notre barre d’outils sous le nom d’historyListBox. Il ne sera pas inclus dans l’assembly contenant FlatIEButton et CheckBoxEx. En effet, il est totalement adapté à notre barre d’outils et ne pourra a priori jamais servir dans un autre projet. Ce contrôle sera donc inclus dans le projet principal de la barre d’outils qui vous sera livré à la fin de cette série d’articles. Le code est cependant disponible à la fin de cette partie.

           Une précision avant d’aller plus loin : Une fonction incluse dans la dll shdocvw.dll permet d’utiliser le même contrôle d’affichage de l’historique et d’autocomplétion que IE : il s’agit de SHAutocomplete. Cette fonction s’utilise très simplement, puisque après l’avoir déclarée grâce à l’attribut DllImport, il suffit d’appeler cette fonction en lui passant en paramètre le handle du contrôle auquel il faut l’attacher. Tout est ensuite automatique. Malheureusement, il nous était impossible d’utiliser cette fonction puisqu’elle affiche l’historique en fonction de la propriété Text du contrôle auquel elle est attachée. Elle ne peut pas, comme nous le souhaiterions, tenir compte également de l’encre saisie. C’est pourquoi nous avons décidé de retravailler nous même cette partie (ceci sera exposé dans le dernier de cette série).

 

Changer le parent d’un contrôle

 

            Passons maintenant à l’écriture de ce nouveau contrôle. Nous allons tout d’abord voir une fonctionnalité qui est traitée à l’extérieur du contrôle, c’est-à-dire depuis son conteneur : il s’agit de faire dépasser historyListBox de la barre. Il faut signaler qu’un contrôle ne peut normalement pas sortir de son contrôle parent. Cependant, il est possible, grâce à une fonction de l’API Windows, de changer la propriété Parent d’un contrôle. Il suffit lorsque nous voulons faire dépasser la historyListBox, de lui donner la fenêtre de IE comme parent. Il ne faut pas oublier de changer les coordonnées de la historyListBox car sa position est calculée par rapport à son parent. Les deux fonctions de l’API nécessaires sont :

 

// Import d'une méthode de l'API permettant de changer le parent d'un contrôle

[DllImport("user32")]

private static extern bool SetParent(int hWndChild, int hWndNewParent);

 

// Import d'une méthode de l'API permettant de connaître le parent d'un contrôle

[DllImport("user32")]

private static extern int GetParent(int hWnd);

 

Leur utilisation sur notre historyListBox se fait comme suit :

 

// Si le Parent de la ListBox n'est pas IE donc que c'est InkToolBar

if(GetParent(this.historyListBox.Handle.ToInt32()) != Explorer.HWND)

{    

      // On change le Parent de la ListBox en IE

      SetParent(this.historyListBox.Handle.ToInt32(), Explorer.HWND);

      // On change la position relative de la ListBox (-> elle ne bouge pas à l'écran)

      this.historyListBox.Top += this.Top;

      this.historyListBox.Left += this.Left;

      // On affiche la ListBox

      this.historyListBox.Show();

}

 

Détecter la sortie du pointeur de la souris

 

            Notre ListBoxEx doit ensuite suivre les changements de taille de la zone de saisie d’adresses. Cependant, lorsque la zone de saisie se réduit, si le pointeur de la souris est au dessus la ListBoxEx (l’utilisateur s’apprête à sélectionner un élément ou à faire défiler la liste), elle ne doit pas se réduire immédiatement. Il faut donc la réduire seulement lorsque le pointeur quitte la zone de la ListBoxEx.

A priori, cela se fait simplement en surveillant les événements MouseEnter et MouseLeave liés à la ListBox. Cependant, un problème se pose lorsqu’une ScrollBar est présente à droite de la ListBox : les événements de la souris considèrent que la ScrollBar ne fait pas partie de la ListBox ! Une des premières choses à implémenter dans notre ListBoxEx est donc la création d’une propriété booléenne publique qui permette de savoir si le curseur de la souris est au dessus de la zone de la ListBoxEx, ScrollBar incluse… Nous allons pour cela réaliser du polling : nous vérifions toutes les 100 ms la position du curseur de la souris et la comparons à la position de la ListBoxEx, en tenant compte de ses dimensions globales (= avec la ScrollBar). Nous utilisons pour cela un timer ainsi qu’une méthode de l’API Windows. Nous créons également au passage un événement qui est levé lorsque le pointeur quitte notre ListBoxEx :

 

public class ListBoxEx : ListBox

{

      // Flag indiquant si la souris survole actuellement le contrôle  private bool mouseOver = false;

      // Timer permettant de faire du polling pour savoir si la

            souris est au dessus   

      private Timer mouseTimer;

 

      // Création d'un événement déclenché lorsque la souris quitte la zone

      public event EventHandler MouseLeaveListBoxZone;

 

 

...

 

      public ListBoxEx()

      {

            mouseTimer = new Timer(); // Création du timer de polling

 

            // Abonnement à l'événement de déclenchement du timer :

            mouseTimer.Tick += new EventHandler(MouseTimer_OnElapsed);

            mouseTimer.Interval = 100; // Initialisation de la durée              

            mouseTimer.Start(); // Départ du timer

 

            ...

 

}

 

 

 

private void MouseTimer_OnElapsed(object myObject, EventArgs

                        myEventArgs)

{

            // Si ce code s'exécute pendant le Design Time

            if(this.DesignMode)

                  return; // Ne rien faire

 

//Sinon :

 

// On récupère le rectangle correspondant au contrôle (Scroll inclus)

            Rectangle myRect = GetRectangleToScreen(this);

 

// Si le curseur de la souris est dans le rectangle du contrôle

            if(myRect.Contains(Cursor.Position))

                  mouseOver = true; // On positionne le Flag à true

            //Sinon

            else

            {

                  //Si le Flag était positionné à true

                  if(mouseOver)

                        // La souris vient de quitter le contrôle

                        // On envoie l'événement perso

                        MouseLeaveListBoxZone(this, new EventArgs()); 

                        mouseOver = false; // On positionne le Flag à false

            }

 

            mouseTimer.Start(); // On relance le timer

}

 

...

 

}

 

Notre méthode MouseTimer_OnElapsed connaît la position du rectangle de la ListBoxEx grâce à la méthode GetRectangleToScreen que voici :

 

private Rectangle GetRectangleToScreen(System.Windows.Forms.Control ctrl)

{

// Initialisation de rectangle résultat

      Rectangle Rect = new Rectangle(0, 0, 0, 0);

 

// Appel à la méthode de l'API Windows permettant de récupérer le

rectangle d'un contrôle

      GetWindowRect((IntPtr)(ctrl.Handle.ToInt32()), ref Rect);

 

// Retour du rectangle du contrôle

      return new Rectangle(Rect.Left, Rect.Top,

            Rect.Width - Rect.Left, Rect.Height - Rect.Top);

}

 

Cette méthode utilise à son tour une fonction de l’API Windows qui rend le rectangle du contrôle dont le handle est passé en paramètre :

                       

[System.Runtime.InteropServices.DllImport("user32.dll")]

private static extern int GetWindowRect(IntPtr hwnd, ref Rectangle aRect);

 

Le problème ici est que la fonction GetWindowRect renvoie dans son paramètre aRect, quatre entiers qui représentent respectivement les coordonnées du coin supérieur gauche, par rapport à l’écran, du contrôle et les coordonnées du coin inférieur droit. Hors la définition de la classe Rectangle du framework .Net contient seulement les membres Top, Left, Width et Height. Le GetWindowRect de l’API remplit donc les champs Width et Height de aRect avec les coordonnées écran du coin inférieur droit du contrôle ! D’où la nécessité de notre méthode GetRectangleToScreen qui effectue la conversion lors du return...

La position du curseur de la souris est, elle, obtenu plus simplement, avec une propriété statique du framework : Cursor.Position.

 

Ainsi, le conteneur d’une ListBoxEx peut savoir à tout moment si le curseur de la souris se trouve au-dessus du contrôle (propriété MouseOver), et reçoit un événement MouseLeaveListBoxZone lorsque le curseur quitte la zone (ScrollBar incluse).

 

Sélection sur déplacements de la souris

 

La sélection d’un élément de la liste sur le simple déplacement de la souris se fait par l’abonnement à l’événement MouseMove. La méthode associée est :

 

private void ListBoxEx_OnMouseMove(object sender, MouseEventArgs e)

{

      try

      {

      // On sélectionne la ligne au-dessus de laquelle se trouve la souris

            SelectedIndex

                  = (Items.Count * ItemHeight - 2 > e.Y) ?

                        e.Y / ItemHeight + TopIndex : -1;

      }

     

// On empêche toute erreur minime d'indice

      catch(System.ArgumentOutOfRangeException){}

}

 

Cette méthode n’appelle pas de plus longs commentaires...

 

Pour conclure sur cette partie consacrée à notre contrôle ListBoxEx, nous vous proposons le code complet en téléchargement ici.

Conclusion

 

Nous avons créé dans cet article trois contrôles pour notre barre d’outils IE :

ListBoxEx permet d’afficher un historique web. Très adapté à notre cas, il a été inclus dans le projet principal de notre barre d’outils : aucune version compilée ne vous est donc proposée maintenant ; nous vous rappelons que la totalité de la solution source vous sera proposé dans le dernier article de cette série.

Les deux autres contrôles, FlatIEButton et CheckBoxEx sont inclus dans un assembly nommé InkTollBarControls.dll téléchargeable ici. Cet assembly contient en réalité trois contrôles : le troisième, InkInputEx, est utilisé pour la zone de saisie d’adresses web. Beaucoup plus élaboré, il mérite que nous y accordions un article entier, en l’occurrence le prochain.




En Savoir Plus 
Evaluez cet article 


Pour afficher ou poster un commentaire, cliquez sur ce lien : Forum-Microsoft



Retrouvez ci-dessous les autres sections du Laboratoire Microsoft

Définitions

Accès direct aux définitions :
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Effectuez une recherche dans les définitions :