Création d'un contrôle RichTextBox évolué pour du texte Rtf (C#)
Date de publication : 06/12/2004
Par
Jean-Alain Baeyens (autres articles)
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.
I. Introduction
II. Création du contrôle utilisateur.
III. Associer les fonctions à la ToolBar.
A. L'appel d'une fonctionnalité
B. La mise en gras
C. La mise en italique, le soulignement et le surlignement
D. Changer de police ou de couleur.
E. Modifier l'indentation.
F. Liste à puces
G. Modification de l'alignement
IV. Conclusion
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é.
public class UserControl1 : System.Windows.Forms.UserControl
{
public UserControl1()
{
InitializeComponent();
}
#region Windows Forms Designer generated code
private void InitializeComponent()
{
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:
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.
Via la propriété Buttons de notre ToolBar, ajoutez un bouton
pour chaque fonction souhaitée.
Votre contrôle ressemble maintenant à ceci:
On ajoute quelques informations devant la classe pour le RAD.
[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 |
[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 |
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 |
void ToolBarButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e){
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 |
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 |
void ToolBarButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e){
int indexButton = this.tlbCtrlRtf.Buttons.IndexOf(e.Button);
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){
switch(indexButton){
case 0:
bold = ! bold;
break;
case 1:
italic = ! italic;
break;
case 2:
underline = ! underline;
break;
case 3:
strikeout = ! strikeout;
break;
}
if (bold)
style += (int)FontStyle.Bold;
if (italic)
style += (int)FontStyle.Italic;
if (underline)
style += (int)FontStyle.Underline;
if (strikeout)
style += (int)FontStyle.Strikeout;
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. |
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 :
void ToolBarButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e){
int indexButton = this.tlbCtrlRtf.Buttons.IndexOf(e.Button);
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.
case 4:
FontDialog fontDlg = new FontDialog();
fontDlg.Font = this.txtCtrlRtf.SelectionFont;
fontDlg.ShowColor = true;
if (fontDlg.ShowDialog() == DialogResult.OK){
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.
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é.
case 8:
this.txtCtrlRtf.SelectionBullet = !this.txtCtrlRtf.SelectionBullet ;
break; |
G. Modification de l'alignement
Ici encore pas grand chose à dire.
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.
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.
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.


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 oeuvre intellectuelle protégée par les droits d'auteurs. 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'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.