Création d'un contrôle RichTextBox évolué pour du texte Rtf (C#)

Création d'un contrôle utilisateur prenant en charge les fonctionnalités de mise en forme d'un texte enregistré au format Rtf. Ce contrôle personalisé est une version évoluée du contrôle RichTextBox.

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Bien que nous allions aborder le sujet, il ne s'agit pas ici d'apprendre à créer un contrôle utilisateur mais bien d'apprendre à manipuler du texte Rtf.

Si vous n'avez jamais créé de contrôle utilisateur, je vous engage à lire les articles sur le sujet. Dans cet exercice, j'ai choisi d'utiliser SharpDevelop. Si vous avez déjà créé des contrôles utilisateurs ou si vous avez lu les articles concernant le sujet, il vous sera facile de transposer la procédure à visual studio ou C# builder.

Dotnet met à notre disposition un contrôle graphique permettant d'enregistrer du texte au format Rtf. Il s'agit de la classe RichTextBox. Par l'intermédiaire de cette classe, il met également à notre disposition les méthodes permettant la mise en forme du texte.

Toutefois, ces méthodes ne sont pas directement accessibles à l'utilisateur de l'application mais doivent être gérées par le programme.

Une solution est de prévoir dans le menu les fonctions spécifiques. Cette partie du menu étant activée ou désactivée en fonction du contrôle actif. Une autre solution consiste à associer un menu contextuel à votre contrôle Rtf qui prendra en charge les différentes méthodes dont vous avez besoin. Il est possible et même conseillé de mettre les deux solutions en oeuvre simultanément.

Nous allons ici mettre en oeuvre une toute autre technique, pas forcément meilleure mais plus originale. Nous allons créer notre propre contrôle Rtf qui inclura une barre d'outils pour la manipulation du texte.

Notre contrôle prendra en charge la mise en gras, le soulignement, la mise en italique, le barré, ainsi que la modification de la police ce qui inclus le type (Arial, Courrier,...), la taille et la couleur. Nous ajouterons l'alignement à gauche, à droite ou centré. Nous prévoirons également l'indentation gauche, droite et les listes à puces.

II. Création du contrôle utilisateur.

Dans SharpDevelop (la version utilisée est la 1.0.1), choisissez : Fichier>Nouveau>Fichier et dans la catégorie C# choisissez Contrôle utilisateur. Cliquez sur Créer. Le code de base est généré.

 
Sélectionnez
public class UserControl1 : System.Windows.Forms.UserControl
{
	public UserControl1()
	{
		//
		// The InitializeComponent() call is required for Windows Forms designer support.
		//
		InitializeComponent();
		
		//
		// TODO: Add constructor code after the InitializeComponent() call.
		//
	}
	
	#region Windows Forms Designer generated code
	private void InitializeComponent()
	{
		// 
		// UserControl1
		// 
		this.Name = "UserControl1" ; 
		this.Size = new System.Drawing.Size(292, 266);
	}
	#endregion
}

Nous pouvons maintenant nommer la classe. Remplacez UserControl1 par AdvancedRichTextBox. Enregistrez le fichier ainsi créé et nommez le AdvancedRichTextBox.

Une petite subtilité de SharpDevelop, si au lieu de créer votre fichier via le menu, vous avez choisi le menu contextuel, vous devez introduire le nom du fichier directement dans la fenêtre de choix du type de code à générer.

Passez en mode Design. Ensuite, depuis la barre des outils (Windows Forms), faites glisser l'icone ToolBar sur la fenêtre générée. Fixez les propriétés ButtonSize à 16/16, cursor à Hand et name à tlbCtrlRtf.

Les valeurs choisies pour les propriétés peuvent évidement être modifiées selon vos goûts. Mais attention, la taille des boutons dépend évidemment de la taille des images que vous allez inclure.

Nous pouvons maintenant faire glisser l'objet RichTextBox. Nous le nommerons txtCtrlRtf. Agrandissez le contrôle pour qu'il occupe le reste de l'espace disponible. N'oubliez pas de supprimer le contenu de la propriété Text. Vous devriez avoir ceci:

Image non disponible

Nous allons avoir besoin d'une ImageList. Faite glissez l'icône sur la fenêtre. Elle se place en bas à gauche. Je l'ai appelée ImgLstCtrlRtf.

Accédez à la collection par la propriété Images. Ajoutez les images que nous allons utiliser. Vous pouvez les trouver en téléchargement au bout de cet article.

Image non disponible

Via la propriété Buttons de notre ToolBar, ajoutez un bouton pour chaque fonction souhaitée.

Image non disponible

Votre contrôle ressemble maintenant à ceci:

Image non disponible

On ajoute quelques informations devant la classe pour le RAD.

 
Sélectionnez
[ToolboxBitmap(typeof(AdvancedRichTextBox),""),Description("Interface utilisateur évolué pour un RichTextBox")]
public class AdvancedRichTextBox : System.Windows.Forms.UserControl
{
...
}

Il nous reste à rendre accessible les propriétés de la classe.

Rendre public les propriétés
Sélectionnez
[Description("RichTextBox associée au contrôle"),Category("Composants")]
public RichTextBox RichTextBox  {
	get {
		return txtCtrlRtf ;		
	}
}

[Description("ToolBar associée au contrôle"),Category("Composants")]
public ToolBar ToolBar  {
	get {
		return tlbCtrlRtf ;		
	}
}

[Description] permet d'ajouter des informations pour le RAD.

Pour qu'il soit possible d'adapter la taille du composant, nous devons encore ajouter une méthode qui sera associée à l'événement Paint de notre contrôle utilisateur.

Code permettant le redimensionnement du composant
Sélectionnez

void CtrlRtfPaint(object sender, System.Windows.Forms.PaintEventArgs e)	{
	this.txtCtrlRtf.Size = new Size(this.Width, this.Height-24);			
}

L'objet RichTextox est redimensionné en fonction de la taille du composant. La toolbar ne demande pas d'adaptation.

Nous allons maintenant pouvoir passer aux choses sérieuses.

III. Associer les fonctions à la ToolBar.

A. L'appel d'une fonctionnalité

Pour gérer l'appel des fonctionnalités depuis la toolbar, nous devons associer l'événement ButtonClick à la méthode suivante:

Gestion du clique de la souris sur un bouton de la toolbar
Sélectionnez
void ToolBarButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e){
		// on détermine la position du bouton activé.
		int indexButton = this.tlbCtrlRtf.Buttons.IndexOf(e.Button);
		switch(indexButton){
			case 0:
				break; 
			case 1:
		 		break; 
			case 2:
		 		break; 
			case 3:
		 		break;
			case 4:
		 		break;
			case 6:
		 		break;
			case 7:
		 		break;
			case 8:
		 		break;
			case 10:
		 		break;
			case 11:
		 		break;
			case 12:
		 		break;
		}
}

C'est un switch qui permet d'orienter le programme vers la bonne action. Remarquez qu'il n'y a pas de traitement pour les valeur 5 et 9. Dans l'exemple elles correspondent à des espacements dans la toolbar.

B. La mise en gras

Le bouton pour la mise en gras est le premier. Nous allons donc changer le code pour la valeur 0 dans notre switch.

Mise en gras du texte
Sélectionnez
case 0:
	this.txtCtrlRtf.SelectionFont = new Font(this.txtCtrlRtf.SelectionFont
                       ,this.txtCtrlRtf.SelectionFont.Style + FontStyle.Bold);
	break;

Nous avons pu mettre le texte en gras mais notre code ne peut être conservé ainsi car le même bouton sera utilisé pour effectuer l'opération inverse. Nous verrons dans le chapitre suivant comment réaliser cela.

C. La mise en italique, le soulignement et le surlignement

Pour permettre d'appliquer correctement le style souhaité en fonction du style déjà défini, nous devons connaître l'état actuel. J'ai choisi d'appliquer les styles en une seule opération.

Application du nouveau style au font
Sélectionnez
void ToolBarButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e){
	// on détermine la position du bouton activé.
	int indexButton = this.tlbCtrlRtf.Buttons.IndexOf(e.Button);
	// on récupère les style utilisé dans le texte sélectionné.
	bool bold = this.txtCtrlRtf.SelectionFont.Bold;
	bool italic = this.txtCtrlRtf.SelectionFont.Italic;
	bool underline = this.txtCtrlRtf.SelectionFont.Underline;
	bool strikeout = this.txtCtrlRtf.SelectionFont.Strikeout;
	int style = 0;
	
	if (indexButton < 4){
		// on inverse le style spécifique
		switch(indexButton){
			case 0:
				bold = ! bold;
				break; 
			case 1:
				italic = ! italic;
		 		break; 
			case 2:
				underline = ! underline;
		 		break; 
			case 3:
				strikeout = ! strikeout;
		 		break;
		}
		// on crée un nouveau FontStyle avec les styles activés
		if (bold)
			style += (int)FontStyle.Bold;
		if (italic)
			style += (int)FontStyle.Italic;
		if (underline)
			style += (int)FontStyle.Underline;
		if (strikeout)
			style += (int)FontStyle.Strikeout;
		// on applique le nouveau FontStyle.
		this.txtCtrlRtf.SelectionFont = new Font(this.txtCtrlRtf.SelectionFont
		                                         ,(FontStyle)style);
	}else{
		...
	}
}

Remarquez que les propriétés Bold,Underline,etc de SelectionFont sont en lecture uniquement et ne peuvent être assignées. Ce qui nous oblige à assigner un nouveau font. Pour ne pas perdre les autres caractéristiques du font, nous utilisons un constructeur qui reçoit le font actuel et le nouveau FontStyle.

Il nous reste encore un problème à solutionner. Notre procédure permet d'activer un style pour le texte qui suit le point d'insertion ou le texte sélectionné mais le bouton devrait afficher l'état du style en fonction de la position du curseur. Pour y arriver, nous allons utiliser l'événement SelectionChanged de notre RichTextBox et y associer la méthode suivante.

Modification automatique de l'état des bouttons en fonction de l'état du style correspondant.
Sélectionnez
void TxtCtrlRtfSelectionChanged(object sender, System.EventArgs e) {
	this.tlbButtonBold.Pushed = this.txtCtrlRtf.SelectionFont.Bold;
	this.tlbButtonItalic.Pushed = this.txtCtrlRtf.SelectionFont.Italic;
	this.tlbButtonUnderline.Pushed = this.txtCtrlRtf.SelectionFont.Underline;
	this.tlbButtonStrikeout.Pushed = this.txtCtrlRtf.SelectionFont.Strikeout;
}

L'état du bouton s'adapte maintenant en fonction du déplacement du curseur.

D. Changer de police ou de couleur.

Notre code ressemble maintenant à ceci :

 
Sélectionnez
void ToolBarButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e){
	// on détermine la position du bouton activé.
	int indexButton = this.tlbCtrlRtf.Buttons.IndexOf(e.Button);
	// on récupère les styles utilisés dans le texte sélectionné.
	bool bold = this.txtCtrlRtf.SelectionFont.Bold;
	bool italic = this.txtCtrlRtf.SelectionFont.Italic;
	bool underline = this.txtCtrlRtf.SelectionFont.Underline;
	bool strikeout = this.txtCtrlRtf.SelectionFont.Strikeout;
	int style = 0;
	
	if (indexButton < 4){
		...
	}else{
		switch(indexButton){
			case 4:
		 		break;
			case 6:
		 		break;
			case 7:
		 		break;
			case 8:
		 		break;
			case 10:
		 		break;
			case 11:
		 		break;
			case 12:
		 		break;
		}
	}
}

Pour changer de font ou de couleur, le plus simple est de faire appel à la fenêtre de dialogue prédéfinie, FontDialog.

 
Sélectionnez
case 4:
	FontDialog fontDlg = new FontDialog();
	// on initialise le font en cours comme valeur par défaut de la fenêtre
	fontDlg.Font = this.txtCtrlRtf.SelectionFont;
	// on demande la possibolité de changer les couleurs.
	fontDlg.ShowColor = true;
	if (fontDlg.ShowDialog() == DialogResult.OK){
		// on applique les changements.
		this.txtCtrlRtf.SelectionFont = fontDlg.Font;
		this.txtCtrlRtf.SelectionColor = fontDlg.Color;
	}
	fontDlg.Dispose();
	break;

Remarquez qu'ici nous pouvons assigner directement le font sans aucun souci car dans la fenêtre FontDialog, tout est pris en charge y compris le gras et les autres styles.

E. Modifier l'indentation.

Il n'y a pas grand chose à dire ici, il ne s'agit que d'utiliser la bonne propriété. Remarquez toutefois que l'on test si l'alignement est bien à gauche car on ne peut indenter un texte centré ou aligné à droite.

 
Sélectionnez
case 6:
	if (this.txtCtrlRtf.SelectionIndent >= 36
		&& this.txtCtrlRtf.SelectionAlignment == HorizontalAlignment.Left){
		this.txtCtrlRtf.SelectionIndent -= 36;
	}
	break;
case 7:
	if (this.txtCtrlRtf.SelectionAlignment == HorizontalAlignment.Left){
		this.txtCtrlRtf.SelectionIndent += 36;
	}
	break;

F. Liste à puces

Encore plus simple. On inverse simplement la propriété.

 
Sélectionnez
case 8:
	this.txtCtrlRtf.SelectionBullet = !this.txtCtrlRtf.SelectionBullet ;
	break;

G. Modification de l'alignement

Ici encore pas grand chose à dire.

 
Sélectionnez
case 10:
	this.txtCtrlRtf.SelectionAlignment = HorizontalAlignment.Left;
	break;
case 11:
	this.txtCtrlRtf.SelectionAlignment = HorizontalAlignment.Center;
	break;
case 12:
	this.txtCtrlRtf.SelectionAlignment = HorizontalAlignment.Right;
	break;

Pour pimenter un peu, nous allons griser les boutons d'indentation et les rendre inactifs quand l'alignement n'est pas à droite.

 
Sélectionnez
case 10:
	this.txtCtrlRtf.SelectionAlignment = HorizontalAlignment.Left;
	this.tlbButtonIndentLeft.ImageIndex = 9;
	this.tlbButtonIndentRight.ImageIndex = 11;
	this.tlbButtonCenter.Pushed = false;
	this.tlbButtonRight.Pushed = false;
	break;
case 11:
	this.txtCtrlRtf.SelectionAlignment = HorizontalAlignment.Center;
	this.tlbButtonIndentLeft.ImageIndex = 10;
	this.tlbButtonIndentRight.ImageIndex = 12;
	this.tlbButtonLeft.Pushed = false;
	this.tlbButtonRight.Pushed = false;
	break;
case 12:
	this.txtCtrlRtf.SelectionAlignment = HorizontalAlignment.Right;
	this.tlbButtonIndentLeft.ImageIndex = 10;
	this.tlbButtonIndentRight.ImageIndex = 12;
	this.tlbButtonLeft.Pushed = false;
	this.tlbButtonCenter.Pushed = false;
	break;

Pour griser le bouton nous utilisons en fait une autre image.

Il ne sous reste plus qu'à actualiser l'état des boutons relatifs à l'alignement en fonction du texte. Il nous suffit pour cela d'ajouter 3 lignes à notre précédente méthode.

 
Sélectionnez
void TxtCtrlRtfSelectionChanged(object sender, System.EventArgs e) {
	this.tlbButtonBold.Pushed = this.txtCtrlRtf.SelectionFont.Bold;
	this.tlbButtonItalic.Pushed = this.txtCtrlRtf.SelectionFont.Italic;
	this.tlbButtonUnderline.Pushed = this.txtCtrlRtf.SelectionFont.Underline;
	this.tlbButtonStrikeout.Pushed = this.txtCtrlRtf.SelectionFont.Strikeout;
	this.tlbButtonBullet.Pushed = this.txtCtrlRtf.SelectionBullet;
	this.tlbButtonLeft.Pushed = (this.txtCtrlRtf.SelectionAlignment == HorizontalAlignment.Left);
	this.tlbButtonCenter.Pushed = (this.txtCtrlRtf.SelectionAlignment == HorizontalAlignment.Center);
	this.tlbButtonRight.Pushed = (this.txtCtrlRtf.SelectionAlignment == HorizontalAlignment.Right);
}

IV. Conclusion

La manipulation du Rtf au travers d'une RichTextBox ne contient en définitive pas de piège particulier et il suffit de peu de connaissances pour la mettre en oeuvre. Dans le code source complet de l'exercice, vous trouverez également l'ajout d'un menu contextuel permettant le copier, coller et le défaire, refaire. Cette partie n'est pas expliquée ici simplement parce qu'il n'y a vraiment rien à dire.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Télécharger :
Code source complet
Voir aussi :
Création d'un contrôle WinForm pour .Net
Créer d'un composant .Net et l'intégrer dans l'EDI de C# Builder
Création d'un contrôle Winform avec Delphi 8 .NET
Générer un document Microsoft Word (C#)

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © . Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.