双击文本区域或文本框时指定突出显示行为?

Posted

技术标签:

【中文标题】双击文本区域或文本框时指定突出显示行为?【英文标题】:Specify highlight behavior when double clicking a text area or text box? 【发布时间】:2011-09-24 09:16:50 【问题描述】:

我注意到许多希望您进行大量文本编辑的应用程序会为双击文本提供非默认行为,因为该应用程序会突出显示它认为您最有可能尝试与之交互的文本。

作为一个简单的例子,这句话在不同的应用程序中表现不同:

这是一个“示例”句子

如果我在记事本中键入它并双击单词“sample”(理想情况下是单词的中间,例如在 sample 的“m”和“p”之间),那么记事本会从第一个引号突出显示到后面的空格包含第二个报价。如果该句子在 Visual Studio 的注释中,并且我在同一位置双击,它会从示例的“s”到“e”突出显示,而不突出显示引号。

如何在我自己的应用程序中自定义这些突出显示行为?它从winforms到WPF有什么不同吗?我想我可以破解我的方法让它在双击事件上工作,但有没有专门为此而设计的更优雅/更深思熟虑的解决方案?

【问题讨论】:

我的回答到底有没有用,还是这个问题是一个死问题? 如果我想推出自己的产品,你的答案就是我会做的。我一直在寻找面向事件驱动、上下文敏感的方法来为双击突出显示的文本设置自定义条件。显然没有办法做到这一点。 【参考方案1】:

是的,使用 DoubleClick 事件随心所欲地进行操作是很笨拙的,因为它看起来会进行两次选择,速度较慢,看起来更糟,并且可能会触发不需要的事件/代码。

所以下面的代码至少应该对 Winforms 有用。创建一个新类,并以通常的方式扩展 TextBox(或 RichTextBox)(使用应该神奇地出现在设计器中的新创建的控件)。我制作了一个简单的例程,您可以在其中指定要使用的分隔符。再多做一点工作,就可以很容易地考虑一个字符的范围,而不仅仅是一个字符,甚至可以创建其他更高级的选择方法。

如果您使用的是 TextBox 而不是 RichTextBox,只需删除在类定义中出现两次的“Rich”位。

class RichTextBoxX : RichTextBox

    char delimiter = ',';   // Specify what character to use for start and end of selection

    protected override void WndProc(ref System.Windows.Forms.Message m)
    
        if (m.Msg==0x0203) // WM_LBUTTONDBLCLK
        
            // Perfect situation for off-by-one bugs! Checked thoroughly for at least 10 mins, so should be okay now:
            int start = this.SelectionStart;
            if (start < 1) start = 1;
            int left = this.Text.LastIndexOf(delimiter, start - 1);
            int right = this.Text.IndexOf(delimiter, start);
            if (right == -1) right = Text.Length;
            this.SelectionStart = left + 1;
            this.SelectionLength = right - left - 1;
            return;             
        

        base.WndProc(ref m);
    

【讨论】:

我如何获得多个分隔符,你能举一个 char[] 的例子吗? 如果这对其他人不起作用,请将末尾的 base.WndProc(ref m); 替换为 else base.WndProc(ref m);【参考方案2】:

来自DarkPh03n1X 的改进答案几乎对我有用,但是它有一个讨厌的错误:如果找不到分隔符Text.IndexOf(c, start) 将返回-1,这将设置right-1 然后 if (right == -1) right = Text.Length 触发。

所以现在我们选择了直到文本的结尾,尽管预期的选择应该更短。我认为开始处理正确。

我删除了if (right == -1) right = Text.Length,但添加了&amp;&amp; pos != -1。这是固定版本:

class RichTextBoxX : RichTextBox

    // implement selection to work with "whole words" on double-click 
    // and without selecting the leading/trailing spaces/blanks/line breaks
    private char[] delimiterList = new[]  '\n', ',', ' ', '(', ')', '_', '/' ;

    protected override void WndProc(ref Message m)
    
        if (m.Msg == 0x0203) // WM_LBUTTONDBLCLK
        
            int start = SelectionStart;
            if (start < 1) start = 1;

            int left = -1;
            int right = Text.Length;
            int pos;

            foreach (char c in delimiterList)
            
                pos = Text.LastIndexOf(c, start - 1);
                if (pos > left) left = pos;

                pos = Text.IndexOf(c, start);
                if (pos < right && pos != -1) right = pos;
            

            SelectionStart = left + 1;
            SelectionLength = right - left - 1;
            return;
        

        base.WndProc(ref m);
    

为了验证行为,这是我使用的示例文本:

12.34.56.78  (ab1-2-3-4-5.test-1.example.com)
Jersey City
New Jersey
US, United States
ASN: Example.com/12345

我已经添加了一些其他的分隔符,请随意选择你需要的。

【讨论】:

【参考方案3】:

添加到 DanW 的工作中,我添加了多个分隔符,看起来效果很好。

class RichTextBoxX : RichTextBox

    private char[] delimiterList = new[]  ',', ' ';

    protected override void WndProc(ref System.Windows.Forms.Message m)
    
        if (m.Msg == 0x0203) // WM_LBUTTONDBLCLK
        
            int start = this.SelectionStart;
            if (start < 1) start = 1;

            int left = -1;
            int right = Text.Length;

            foreach (char c in delimiterList)
            
                if (this.Text.LastIndexOf(c, start - 1) > left)
                
                    left = this.Text.LastIndexOf(c, start - 1);
                

                if (this.Text.IndexOf(c, start) < right)
                
                    right = this.Text.IndexOf(c, start);
                    if (right == -1) right = Text.Length;
                
            

            this.SelectionStart = left + 1;
            this.SelectionLength = right - left - 1;
            return;
        

        base.WndProc(ref m);
    

还有一件事:要实现将上面的代码粘贴到您要使用它的表单“代码”中,现在使用“表单设计器”将 RichTextBox 拖放到您的表单上,现在转到表单的在我的案例 form1.desigener.cs 中的设计器类并找到实现字符串,例如:

this.richTextBox1 = new System.Windows.Forms.RichTextBox();

替换成

this.richTextBox1 = new project.form1.RichTextBoxX();

此后,该控件将像普通的 RichTextBox 实现一样工作,并具有额外的覆盖功能

【讨论】:

小心,请参阅上面 Eugen 的回答。【参考方案4】:

我使用正则表达式 \w 等于 [a-zA-Z0-9_] 替换 TextBox 选择

private void TextBox1_MouseDoubleClick(object sender, MouseEventArgs e)

    string text = TextBox1.SelectedText;
    var strA = Regex.Match(text, @"\w+");
    int indexA = TextBox1.SelectionStart + text.IndexOf(strA.Value);
    TextBox1.Select(indexA, strA.Value.Length);

原始结果:

这是一个"sample"sentence

上面的方法

这是一个“sample”的句子

【讨论】:

以上是关于双击文本区域或文本框时指定突出显示行为?的主要内容,如果未能解决你的问题,请参考以下文章

突出显示文本区域内的文本

如何以角度突出显示文本区域中的文本?

颜色:在 ie 中的文本上透明(使用覆盖技术突出显示文本区域中的文本)?

如何在文本区域(坐标)角度中获取位置突出显示的文本?

在 textarea Reactjs 中键入时突出显示文本

创建一个 chrome 扩展,它将页面上突出显示的文本插入到 popup.html 中的文本区域中