IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

TextBox/RichTextBox avec couleurs


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Inscrit en
    Novembre 2010
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 3
    Par défaut TextBox/RichTextBox avec couleurs
    Bonjour,

    je cherche a créer un petit editeur de texte et j'aimerais que certains mots-clés soient en couleur. Je me suis évidemment tourné du côté du contrôle RichtTextBox qui le permet, j'ai rapidement obtenu un résultat, les mots-clés enregistrés sont bien en couleur. Pour appliquer ces couleurs, je suis obligé de revérifier tout le texte, donc quand j'applique les couleurs au texte, je bloque le rafraîchissement du contrôle tant que ce n'est pas terminé. Le problème est que sur les longs texte, je me retrouve confronté à un problème de lenteur. Même si je mets un timer pour la vérification des couleurs au lieu de le faire à chaque fois que le texte change, ce n'est pas agréable a l'utilisation, on voit le texte s'afficher quelques secondes après l'avoir écrit.
    J'ai essayé de sauvegarder un tableau avec le SelectionStart et le SelectionLength à côté pour savoir tous les endroits ou j'avais déjà appliqué la couleur et ainsi ne pas avoir à réappliquer les couleurs sur le texte déjà écrit, mais j'ai quelques problèmes. Il faut déjà que je décale ces valeurs si le texte ajouté est écrit avant, si le texte rajouté est issu d'un copier/coller je ne sais pas de combien je dois décaler... C'est aussi problématique lorsque c'est du texte effacé. Bref, c'est vraiment pas pratique, et tout ça à cause de la façon dont le RichtTextBox fonctionne, je trouve déjà un peu stupide de devoir sélectionner le texte pour le modifier....
    J'ai tenté quelques trucs avec un WebBrowser que j'utiliserais comme éditeur de texte, cela fonctionne plutôt bien, je n'ai plus les problèmes de lenteurs, par contre je perds toutes les fonctions et évènement de la TextBox/RichTextBox et cela est bloquant pour ce que je veux faire de ce programme. J'aimerais par exemple ajouter une fonctione d'Auto-Completion, avec la TextBox ou RichTextBox, j'ai pu trouvé sur internet une classe qui permet de le rajouter et cela fonctionne, mais par contre pas avec le WebBrowser, ce qui est normal.

    J'en viens a vous demander conseil pour résoudre mon problème, pensez-vous qu'il est judicieux de continuer à améliorer le RichTextBox ? J'ai l'impression qu'il n'y a pas vraiment moyen d'améliorer ces problèmes de lenteurs mais je me trompe peut-être. Auriez-vous un lien ou je pourrais télécharger un contrôle qui permet de répondre à mes besoins ? J'en ai déjà cherché sur internet, j'en ai trouvé plusieurs mais c'était toutes des évolution du RichtTextBox et il y avait toujours ce problème de lenteur. Ou alors auriez-vous d'autres suggestions ?

    Merci d'avance pour votre aide.

    Cordialement

  2. #2
    Membre Expert Avatar de mactwist69
    Homme Profil pro
    Développement VB.NET
    Inscrit en
    Janvier 2007
    Messages
    1 707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développement VB.NET
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 707
    Par défaut
    Bonjour,

    Je pense qu'il faille garder le richtextbox si il contient tout ce dont tu as besoin.
    Maintenant, on peut essayer de voir si il existe des astuces pour amélioré la rapidité.
    Par exemple je pense qu'essayer de sauvegarder les noms déjà coloré, ou essayer de gérer les copier coller, te ralentiront plus qu'autre chose.

    Je pense qu'il faut essayer (si possible) de trouver le bon événement et un très bon algo optimisé au max...

    Quel événement utilises tu pour déclencher la coloration de ton text ? TextChanged j'imagine ?
    Peut être as tu un petit bout de code ?

  3. #3
    Futur Membre du Club
    Inscrit en
    Novembre 2010
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 3
    Par défaut
    Pour l'evenement, j'avais commencé avec le TextChanged, mais maintenant j'utilise un timer pour éviter de calculer trop de fois. Toutefois, avec les modifications que j'ai fait, je pourrais réutiliser le TextChanged (les threads s'arrêtent s'il faut recalculer). J'ai amélioré un peu entre temps le code pour modifier les couleurs, je sauvegardais l'emplacement de mon curseur dans la RichTextBox pour le remettre au meme endroit à la fin de mes modifications, mais j'ai remarqué qu'il n'étais pas remis à l'emplacement original à la fin de mes traitements mais à chaque coloration de mots, et c'était surtout ça qui faisait prendre du temps à la fonction...
    Je récupère l'emplacement des mots à colorer dans un thread séparé, pour le moment cette partie prend du temps car j'ai fait un truc assez simple. Cette partie est à optimiser, ce que je ferai par la suite avec des Regexp sûrement, mais ca n'impactait pas mon problème de lenteur de mise à jour de la RichTextBox.
    A priori, le problème évoqué est plus ou moins réglé, il me reste toujours quelques soucis lié au fait que je dois sélectionner le texte pour modifier sa couleur... Si l'utilisateur change l'emplacement de la scrollbar avant que le traitement des threads soit terminé, la scrollbar revient a l'emplacement ou le texte était originellement et non à l'état de la scrollbar ou elle était réellement. Je ne pense pas qu'on puisse y faire grand chose, et ca sera moins problématique une fois que j'aurai optimisé le point précédent.

    Pour ce qui est de la fonction qui nous intéresse, je la met ci-dessous, je ne pense pas qu'il y ait encore quelque chose à optimiser mais si c'est le cas je suis toujours preneur. Ce code se lance donc seulement si le texte a été modifié :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     
     
       Private WithEvents RTActuel As RichTextBox
        Private listModifs As New List(Of modifCouleur)
     
        Structure modifCouleur
            Dim position As Long
            Dim longueur As Long
            Dim couleur As Color
        End Structure
     
     Private Sub ModifierCouleur()
     
            '       Debug.Print("MODIF COMMENCE : " & listModifs.Count)
     
            ' Lock the update
            LockWindowUpdate(Me.Handle.ToInt32)
     
     
            Dim posStart As Integer = RTActuel.SelectionStart
            Dim posLength As Integer = RTActuel.SelectionLength
     
            RTActuel.Select(0, RTActuel.TextLength)
            RTActuel.SelectionColor = Color.Black
            RTActuel.Select(posStart, posLength)
     
     
            SyncLock listModifs
                For Each modif As modifCouleur In listModifs
     
                    RTActuel.Select(modif.position, modif.longueur)
                    RTActuel.SelectionColor = modif.couleur
     
                Next
                listModifs.Clear()
            End SyncLock
     
     
            RTActuel.Select(posStart, posLength)
            RTActuel.SelectionColor = Color.Black
     
            ' Unlock the update
     
            LockWindowUpdate(0)
     
            couleurTableOk = False
            couleurWordOk = False
     
            listModifs.Clear()
     
            '       Debug.Print("MODIF FINI")
     
    End Sub
    et pour info voici le code du timer, je ne pense pas qu'il soit utile pour aider à l'optimisation par contre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    Private Sub TimerCouleur_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimerCouleur.Tick
     
     
            If Not RTActuel Is Nothing  Then
                If Math.Abs(RTActuel.TextLength - saveRequête.Length) >= 1 Then
                    texteModifie = True
     
                    If nbThreadActif > 0 Then
                        stopThread = True
                    End If
                End If
     
                saveRequête = RTActuel.Text
     
     
                If nbThreadActif = 0 And autoCompletion.VisibleItems.Count = 0 Then
     
                    If stopThread = False And couleurTableOk And couleurWordOk Then
                        ModifierCouleur()
                    End If
     
                    If  texteModifie = True Then
     
                        listModifs.Clear()
                        stopThread = False
     
     
                            'Dim posStart As Integer = RTActuel.SelectionStart
                            'Dim posLength As Integer = RTActuel.SelectionLength
     
                            'RTActuel.Select(0, RTActuel.TextLength)
                            'RTActuel.SelectionColor = Color.Black
                            'RTActuel.Select(posStart, posLength)
     
                            ThreadCouleur = New Thread(AddressOf SetColorWord)
                            ThreadTables = New Thread(AddressOf SetColorTables)
     
                            Dim argumentsWord(1)
     
                            argumentsWord(0) = RTActuel.Text
                            argumentsWord(1) = listMotsCles
                            nbThreadActif += 1
                            ThreadCouleur.Start(argumentsWord)
     
     
                            Dim argumentsTables(1)
                            argumentsTables(0) = RTActuel.Text
                            argumentsTables(1) = dictListTables(nomConnexionActuel)
     
                            nbThreadActif += 1
                            ThreadTables.Start(argumentsTables)
                            texteModifie = False
     
     
                    End If
                End If
            End If
        End Sub
    je ne modifie pas les couleurs tant que l'autocompletion est affichée (sinon ca l'enlève, ce qui est un peu gênant). Le reste n'est peut-être pas très clair sans le reste du code, mais ya plusieurs tests qui se font dans l'ordre :
    - Si le texte a été modifié, la boolean texteModifie passe a True, je stop les thread s'il y en a.
    - S'il y a encore des threads actifs ou si l'auto-completion est affiché, je n'exécute rien.
    - Il y a 2 threads qui modifient les boolean couleurTableOk et couleurWordOk à True lorsqu'ils sont terminés, ca veut dire que tous les mots a colorié sont répertiorés et dans ce cas je peux lancer la fonction qu'on a vu avant. Par contre si on avait arrêté les threads, la fonction n'est pas executée.
    - Si le texte a été modifié alors je relance les threads

  4. #4
    Membre chevronné Avatar de Jabbal'H
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2004
    Messages
    403
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2004
    Messages : 403
    Par défaut
    Il y a quelques temps j'utilisais un RichTextBox également, et bien que bien moins custom que toi, j'avais un problème de lenteur

    J'avais trouvé çà à mettre dans ton App.config sur un évènement de chargement par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Timeline.DesiredFrameRateProperty.OverrideMetadata(
                        typeof(Timeline),
                        new FrameworkPropertyMetadata { DefaultValue = 20 });
    Si tu n'a pas de vidéos ou ce genre de chose, à priori cela ne devrait pas ce voir sur ton appli, mais sur le RichTextBox si ! Du moins sur le mien j'ai vu la différence.

  5. #5
    Membre Expert Avatar de mactwist69
    Homme Profil pro
    Développement VB.NET
    Inscrit en
    Janvier 2007
    Messages
    1 707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développement VB.NET
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 707
    Par défaut
    Salut,

    J'essai de réfléchir plus en terme de logique.

    Et par exemple, je ne sais pas si c'est une bonne idée cette liste de mot qui enregistre tout les mots déjà colorier.
    Parce que au final, colorier un bout de texte, je ne sais pas si ça prends du temps, mais dans ton code, tu vas tester si il existe, tu mémorise ceux qu'il y a a faire... tout ça avec un thread qui travail a côté.

    J'imagine que tu y à déjà penser (tu me diras pourquoi ça n'irait pas), mais essayer de travailler "en temps réel", je m'explique.

    - Au premier chargement du texte, tu parcours ton texte et tu colorie tout (idéalement, avant affichage de la form pour aller plus vite).
    - Ensuite tu te concentre uniquement sur les entrées de texte, en partant du principe que tout ce qui est existant est juste (donc pas besoin de boucler à l'infini). Comment faire cela ?

    J'ai regarder vite fait les événements. Et par exemple il y a le KeyPress où un l'argument sender contient le lettre ou carrément le texte coller.
    2 cas donc, quand il se déclenche:
    - un copier coller (du coup tu peux analyser directement tout le texte coller) et cibler ton travail (en live?)
    - si ton utilisateur est en train de taper un mot... tu pourrais genre capter la position du curseur, revenir en arrière jusqu'au début du mot (seulement la première fois, puis mémoriser le mot en cours), l'analyser à chaque lettre, et le colorier à la volé si il y a besoin en appelant une fonction et en lui donnant les coordonnées.

    C'est une idée comme ça...

  6. #6
    Futur Membre du Club
    Inscrit en
    Novembre 2010
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 3
    Par défaut
    Citation Envoyé par mactwist69 Voir le message
    Salut,

    J'essai de réfléchir plus en terme de logique.

    Et par exemple, je ne sais pas si c'est une bonne idée cette liste de mot qui enregistre tout les mots déjà colorier.
    Parce que au final, colorier un bout de texte, je ne sais pas si ça prends du temps, mais dans ton code, tu vas tester si il existe, tu mémorise ceux qu'il y a a faire... tout ça avec un thread qui travail a côté.
    J'ai abandonné l'idée de la liste qui enregistre les mots déjà coloriés. Le temps dépend de la longueur du texte évidemment, et j'ai potentiellement plusieurs centaines de lignes à traiter, donc le moindre dixième de secondes gagné, c'est déjà bien. Pour le moment, la fonction de coloriage de mon post précédent des mots s'éxecute dans un temps acceptable, si je peux gagner encore du temps je serai content mais je peux me satisfaire du résultat pour l'instant.

    Citation Envoyé par mactwist69 Voir le message
    J'imagine que tu y à déjà penser (tu me diras pourquoi ça n'irait pas), mais essayer de travailler "en temps réel", je m'explique.

    - Au premier chargement du texte, tu parcours ton texte et tu colorie tout (idéalement, avant affichage de la form pour aller plus vite).
    - Ensuite tu te concentre uniquement sur les entrées de texte, en partant du principe que tout ce qui est existant est juste (donc pas besoin de boucler à l'infini). Comment faire cela ?

    J'ai regarder vite fait les événements. Et par exemple il y a le KeyPress où un l'argument sender contient le lettre ou carrément le texte coller.
    2 cas donc, quand il se déclenche:
    - un copier coller (du coup tu peux analyser directement tout le texte coller) et cibler ton travail (en live?)
    - si ton utilisateur est en train de taper un mot... tu pourrais genre capter la position du curseur, revenir en arrière jusqu'au début du mot (seulement la première fois, puis mémoriser le mot en cours), l'analyser à chaque lettre, et le colorier à la volé si il y a besoin en appelant une fonction et en lui donnant les coordonnées.

    C'est une idée comme ça...
    Effectivement, j'y ai pensé, mais j'ai été confronté a quelques problèmes, notamment au niveau des copier/coller. L'évènement KeyPress enregistre un argument KeyChar, dans le cas ou c'est un copié/coller, le texte copier n'est pas inscrit dans l'argument. Le sender quant a lui renvoi la RichTextBox donc tout le texte complet. Je pourrais peut-être réussir a isoler le texte copier/coller en comparant le texte avant et après, mais au final je pense pas que ca me serve a grand chose. Du moment où c'est un copier/coller, a mon avis il vaut mieux recontrôler toutes les lignes qui se trouvent après.
    Pour le 2eme point, oui c'est une idée, je pense l'adapter en calculant pas seulement pour le mot en cours, mais refaire les calculs pour toute la ligne. Je dois prendre en compte certains caractères dans le texte pour savoir si je dois mettre en couleur, pas juste le mot en lui-même, du coup je suis obligé de récupérer tout le texte avant et après le mot, mais je vais me restreindre à la ligne en cours, ca devrait être suffisant.

    Je vais modifier mes threads (que je vais regrouper en un seul finalement) afin de traiter seulement les lignes ou du texte a été modifié (ou les lignes qui suivent celles ou le texte a été modifié s'il s'agit d'un copié/coller). Et je pense qu'après je serais bon. Comme expliqué dans mon post précédent, le problème initial est je crois résolu, les lignes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    RTActuel.Select(posStart, posLength)
            RTActuel.SelectionColor = Color.Black
    étaient inclus dans la boucle, ce qui multipliait par 2 le temps de traitement. Si vous avez encore des idées d'amélioration, je continue à vérifier ce thread mais pour moi il est peut être indiqué comme Résolu (1ère fois que je poste ici, j'imagine que c'est fait par un modérateur ? Je ne vois pas l'option). Merci pour vos idées et conseils, cela m'est très utile.

    Citation Envoyé par Jabbal'H Voir le message
    Il y a quelques temps j'utilisais un RichTextBox également, et bien que bien moins custom que toi, j'avais un problème de lenteur

    J'avais trouvé çà à mettre dans ton App.config sur un évènement de chargement par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Timeline.DesiredFrameRateProperty.OverrideMetadata(
                        typeof(Timeline),
                        new FrameworkPropertyMetadata { DefaultValue = 20 });
    Si tu n'a pas de vidéos ou ce genre de chose, à priori cela ne devrait pas ce voir sur ton appli, mais sur le RichTextBox si ! Du moins sur le mien j'ai vu la différence.
    Je n'ai encore jamais modifié le app.config et je ne sais pas comment rajouté ce petit bout de code pour savoir si ça modifie quelque chose ou pas dans mon programme. J'ai un peu cherché sur internet comment implémenter ça mais j'ai du mal à comprendre comment ça fonctionne. Je garde ça de côté. Je verrai plus tard si je peux faire quelque chose, à moins que t'aies un petit moment à me consacrer pour m'expliquer.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Couleur BackGround RichTextBox avec SendMessage
    Par sergelagier dans le forum Windows Forms
    Réponses: 0
    Dernier message: 03/07/2013, 23h01
  2. Définir un textBox password avec le style XP
    Par NicolasJolet dans le forum Windows
    Réponses: 3
    Dernier message: 19/03/2006, 14h43
  3. PopupMenu : afficher un dessin avec couleur personnalisée
    Par MiJack dans le forum Composants VCL
    Réponses: 3
    Dernier message: 07/02/2006, 13h54
  4. alligner des textbox (input) avec une liste
    Par sundjata dans le forum Balisage (X)HTML et validation W3C
    Réponses: 4
    Dernier message: 20/01/2006, 16h16
  5. [VB.NET] Brush avec couleur définie en RGB
    Par jennings dans le forum Windows Forms
    Réponses: 7
    Dernier message: 31/12/2004, 09h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo