如何突出显示颜色与 RichTextBox 文本中所有其他选择不同的单词或短语? [英] How to highlight a word or phrase with a color different from all the other selections in a RichTextBox text?

查看:74
本文介绍了如何突出显示颜色与 RichTextBox 文本中所有其他选择不同的单词或短语?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

主要目标是让用户在所有其他选定的字词或短语中将选择识别为当前选择.

private void numericUpDown1_ValueChanged(object sender, EventArgs e){如果 (results.Count > 0){richTextBox1.SelectionStart = results[(int)numericUpDown1.Value - 1];richTextBox1.SelectionLength = textBox1.Text.Length;richTextBox1.SelectionColor = Color.Red;richTextBox1.ScrollToCaret();}}

本例中,在截图中,搜索到的词有3个结果:System.所有结果都以黄色着色.

如果我将 NumericUpDown 值更改为 2,它会将结果中的第二个 System 字着色为红色,然后将 NumericUpDown 值更改为 3 时,它会将最后一个 System 结果着色为红色也.

我的问题是 2 和 3 都用红色表示:我只希望当前选定的单词用红色表示,所有其他匹配项都应使用默认颜色.

解决方案

一些有助于构建可以处理文本选择的类对象的建议.

此类应包含在给定文本中搜索关键字所需的大部分(或全部)逻辑,维护找到的匹配项列表、它们的位置和长度,并允许对该列表进行基本的导航匹配,以及其他可以轻松扩展功能的配置.

这里,TextSearcher1 类构造函数需要一个 RichTextBox 控件作为参数之一,加上一个用于正常选择的 Color 和一个用于突出显示当前当匹配列表被导航时匹配.

▶ 搜索功能由

TextSearcher 类:

using System.Collections.Generic;使用 System.Drawing;使用 System.Text.RegularExpressions;使用 System.Windows.Forms;私有类 TextSearcher{私有绑定源 m_bsMatches = null;私有 RichTextBox m_Rtb = null;public TextSearcher(RichTextBox rtb) : this(rtb, Color.Yellow, Color.Red) { }公共文本搜索器(RichTextBox rtb,颜色选择颜色,颜色当前颜色){this.m_Rtb = rtb;选择颜色 = 选择颜色;当前颜色 = 当前颜色;}公共字符串 CurrentKeywords { 获取;私人订制;} = string.Empty;public bool CaseSensitive { get;放;} = 真;public int CurrentIndex =>m_bsMatches.Position;公共匹配 CurrentMatch =>(匹配)m_bsMatches.Current;公共 MatchCollection 匹配 { 获取;私人订制;}公共颜色选择颜色 { 获取;放;}公共颜色 CurrentColor { 获取;放;}public void GotoMatch(int position){选择文本(假);this.m_bsMatches.Position = Math.Max(Math.Min(this.m_bsMatches.Count, position), 0);选择文本(真);}公共无效 NextMatch(){选择文本(假);if (this.m_bsMatches != null && m_bsMatches.Position == this.m_bsMatches.Count - 1) {this.m_bsMatches.MoveFirst();}else { this.m_bsMatches.MoveNext();}选择文本(真);}public void PreviousMatch(){选择文本(假);如果 (this.m_bsMatches != null && this.m_bsMatches.Position > 0) {this.m_bsMatches.MovePrevious();}else { this.m_bsMatches.MoveLast();}选择文本(真);}公共整数搜索(字符串关键字){if (CurrentKeywords.Equals(keywords)) 返回 Matches.Count;this.m_bsMatches?.Dispose();CurrentKeywords = 关键字;var options = RegexOptions.Multiline |(CaseSensitive ? RegexOptions.IgnoreCase : RegexOptions.None);匹配 = Regex.Matches(this.m_Rtb.Text, 关键字, 选项);如果(匹配!= null){this.m_Rtb.SelectAll();this.m_Rtb.SelectionColor = this.m_Rtb.ForeColor;this.m_Rtb.SelectionStart = 0;this.m_bsMatches = new BindingSource(Matches, null);选择关键字();返回匹配数.}返回0;}私有无效 SelectKeywords(){foreach(匹配 m 匹配){选择文本(假);NextMatch();}this.m_bsMatches.MoveFirst();}私有无效 SelectText(布尔当前){this.m_Rtb.Select(CurrentMatch.Index, CurrentMatch.Length);this.m_Rtb.SelectionColor = 当前?当前颜色:选择颜色;}}

1 - 我知道,好名字!我花了一段时间才想出来,所以请不要改变它:)

The main goal is to let an User identify a selection as the current, among all other selected words or phrases.

private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
    if (results.Count > 0)
    {
        richTextBox1.SelectionStart = results[(int)numericUpDown1.Value - 1];
        richTextBox1.SelectionLength = textBox1.Text.Length;
        richTextBox1.SelectionColor = Color.Red;
        richTextBox1.ScrollToCaret();
    }
}

In this case, in the screenshot, there are 3 results of the searched word: System. All the results colored in yellow.

If I change the NumericUpDown value to 2, it will color in red the second System word in the results and then when changing the NumericUpDown value to 3, it will color the last System result in red too.

My problem is that both 2 and 3 will be in colored in red: I want only the current selected word to be colored in red, all the other matches should use the default color.

解决方案

A few suggestions that can help in building a class object that can handle selections of text.

This class should contain most (or all) the logic needed to search for keywords inside a given text, maintain a list of the matches found, their position and length and allows basic navigation of this list of matches, plus other configurations that can extend the functionality without much effort.

Here, the TextSearcher1 class constructor expects a RichTextBox control as one of the arguments, plus a Color used for the normal selection and a Color used to highlight the current match when the list of matches is navigated.

▶ The search functionality is handled by the Regex.Matches() method, which return a MatchCollection of Match objects, quite handy since each Match contains the position (Index property) of the match inside the text and its length (Length property).

▶ The navigation functionality is instead provided by a BindingSource object. Its DataSource property is set to the MatchCollection returned by Regex.Matches() and it's reset each time a new set of keywords is searched.
This class, when initialized, provides the MoveNext(), MovePrevious(), MoveLast() and MoveFirst() methods, plus a Position property, which identifies the Index of current object in the collection - a Match object, here.

▶ The CaseSensite property is used to perform case sensitive or insensitive searches. Added to show that it can be simple to expand the basic functionality with more features that build on the existing (for example, a culture sensitive/insensitive search).

To initialize the TextSearcher class, pass the instance of a RichTextBox control and two Color values to its contructor:

TextSearcher matchFinder = null;

public SomeForm()
{
    InitializeComponent();
    matchFinder = new TextSearcher(richTextBox1, Color.Yellow, Color.Red);
}

In the example, you can see four Controls:

  • The Previous (btnPrevious) and Next (btnNext) Buttons, used to navigate the list of matches.
  • A NumericUpDown (nudGotoMatch), used to jump to a specific matched keywork.
  • A TextBox (txtSearch), used to enter one or more keywords, separated by a pipe (the pipe char is used specify alternate matches in the Regex, it could be replaced with something else in the UI).

Since the TextSearcher class contains all the search and navigation logic, the code needed to activate the functionality of these controls in the front-end is minimal, just the standard UI requirements (such as setting e.SuppressKeyPress = true when the Enter key is pressed in a TextBox control).

private void txtSearch_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter) {
        string keywords = (sender as Control).Text;
        e.SuppressKeyPress = true;

        if (!matchFinder.CurrentKeywords.Equals(keyword)) {
            nudGotoMatch.Maximum = matchFinder.Search(keywords);
        }
    }
}

private void nudGotoMatch_ValueChanged(object sender, EventArgs e)
{
    if (matchFinder.Matches.Count > 0) {
        matchFinder.GotoMatch((int)nudGotoMatch.Value - 1);
    }
}

private void btnPrevious_Click(object sender, EventArgs e)
{
    matchFinder.PreviousMatch();
}

private void btnNext_Click(object sender, EventArgs e)
{
    matchFinder.NextMatch();
}

This is how it works:

The TextSearcher class:

using System.Collections.Generic;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Windows.Forms;

private class TextSearcher
{
    private BindingSource m_bsMatches = null;
    private RichTextBox m_Rtb = null;

    public TextSearcher(RichTextBox rtb) : this(rtb, Color.Yellow, Color.Red) { }
    public TextSearcher(RichTextBox rtb, Color selectionColor, Color currentColor)
    {
        this.m_Rtb = rtb;
        SelectionColor = selectionColor;
        CurrentColor = currentColor;
    }

    public string CurrentKeywords { get; private set; } = string.Empty;
    public bool CaseSensitive { get; set; } = true;
    public int CurrentIndex => m_bsMatches.Position;
    public Match CurrentMatch => (Match)m_bsMatches.Current;
    public MatchCollection Matches { get; private set; }
    public Color SelectionColor { get; set; }
    public Color CurrentColor { get; set; }

    public void GotoMatch(int position)
    {
        SelectText(false);
        this.m_bsMatches.Position = Math.Max(Math.Min(this.m_bsMatches.Count, position), 0);
        SelectText(true);
    }
    public void NextMatch()
    {
        SelectText(false);
        if (this.m_bsMatches != null && m_bsMatches.Position == this.m_bsMatches.Count - 1) {
            this.m_bsMatches.MoveFirst();
        }
        else { this.m_bsMatches.MoveNext(); }
        SelectText(true);
    }

    public void PreviousMatch()
    {
        SelectText(false);
        if (this.m_bsMatches != null && this.m_bsMatches.Position > 0) {
            this.m_bsMatches.MovePrevious();
        }
        else { this.m_bsMatches.MoveLast(); }
        SelectText(true);
    }

    public int Search(string keywords)
    {
        if (CurrentKeywords.Equals(keywords)) return Matches.Count;
        this.m_bsMatches?.Dispose();
        CurrentKeywords = keywords;
        var options = RegexOptions.Multiline |
                     (CaseSensitive ? RegexOptions.IgnoreCase : RegexOptions.None);
        Matches = Regex.Matches(this.m_Rtb.Text, keywords, options);
        if (Matches != null) {
            this.m_Rtb.SelectAll();
            this.m_Rtb.SelectionColor = this.m_Rtb.ForeColor;
            this.m_Rtb.SelectionStart = 0;
            this.m_bsMatches = new BindingSource(Matches, null);
            SelectKeywords();
            return Matches.Count;
        }
        return 0;
    }

    private void SelectKeywords()
    {
        foreach (Match m in Matches) {
            SelectText(false);
            NextMatch();
        }
        this.m_bsMatches.MoveFirst();
    }
    private void SelectText(bool current)
    {
        this.m_Rtb.Select(CurrentMatch.Index, CurrentMatch.Length);
        this.m_Rtb.SelectionColor = current ? CurrentColor : SelectionColor;
    }
}

1 - I know, great name! It took me a while to come up with it so, please, don't changed it :)

这篇关于如何突出显示颜色与 RichTextBox 文本中所有其他选择不同的单词或短语?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆