Custom links in RichTextBox

2020-04-11 18:11发布

Suppose I want every word starting with a # to generate an event on double click. For this I have implemented the following test code:

private bool IsChannel(Point position, out int start, out int end)
{
    if (richTextBox1.Text.Length == 0)
    {
        start = end = -1;
        return false;
    }

    int index = richTextBox1.GetCharIndexFromPosition(position);
    int stop = index;

    while (index >= 0 && richTextBox1.Text[index] != '#')
    {
        if (richTextBox1.Text[index] == ' ')
        {
            break;
        }
        --index;
    }

    if (index < 0 || richTextBox1.Text[index] != '#')
    {
        start = end = -1;
        return false;
    }

    while (stop < richTextBox1.Text.Length && richTextBox1.Text[stop] != ' ')
    {
        ++stop;
    }
    --stop;

    start = index;
    end = stop;

    return true;
}

private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
    textBox1.Text = richTextBox1.GetCharIndexFromPosition(new Point(e.X, e.Y)).ToString();
    int d1, d2;
    if (IsChannel(new Point(e.X, e.Y), out d1, out d2) == true)
    {
        if (richTextBox1.Cursor != Cursors.Hand)
        {
            richTextBox1.Cursor = Cursors.Hand;
        }
    }
    else
    {
        richTextBox1.Cursor = Cursors.Arrow;
    }
}

This handles detecting words that start with # and making the mouse cursor a hand when it hovers over them. However, I have the following two problems:

  1. If I try to implement a double click event for richTextBox1, I can detect when a word is clicked, however that word is highlighted (selected), which I'd like to avoid. I can deselect it programmatically by selecting the end of the text, but that causes a flicker, which I would like to avoid. What ways are there to do this?
  2. The GetCharIndexFromPosition method returns the index of the character that is closest to the cursor. This means that if the only thing my RichTextBox contains is a word starting with a # then the cursor will be a hand no matter where on the rich text control it is. How can I make it so that it is only a hand when it hovers over an actual word or character that is part of a word I'm interested in? The implemented URL detection also partially suffers from this problem. If I enable detection of URLs and only write www.test.com in the rich text editor, the cursor will be a hand as long as it is on or below the link. It will not be a hand if it's to the right of the link however. I'm fine even with this functionality if making the cursor a hand if and only if it's on the text proves to be too difficult.

I'm guessing I'll have to resort to some sort of Windows API calls, but I don't really know where to start.

I am using Visual Studio 2008 and I would like to implement this myself.

Update: The flickering problem would be solved if I could make it so that no text is selectable through double clicking, only through dragging the mouse cursor and programmatically. Is this easier to achieve? Because I don't really care if one can select text or not by double clicking in this case.

1条回答
ら.Afraid
2楼-- · 2020-04-11 19:00

On point (2) you could try:

After if (richTextBox1.Text.Length == 0){ ... }

//get the mouse point in client coordinates
Point clientPoint = richTextBox1.PointToClient(richTextBox1.PointToScreen(position));
int index = richTextBox1.GetCharIndexFromPosition(position);
//get the position of the closest char
Point charPoint = richTextBox1.GetPositionFromCharIndex(index);

bool notOnTheSameLine = ((clientPoint.Y < charPoint.Y) || (clientPoint.Y > charPoint.Y + richTextBox1.Font.Height));
bool passedTheWord = (clientPoint.X > charPoint.X + richTextBox1.Font.SizeInPoints);

if (notOnTheSameLine || passedTheWord)
{
  start = end = -1;
  return false;
}


For point (1) maybe have a different way of following the link than dbl-click? Maybe cntl-click would avoid the issues of the word becoming selected...

查看更多
登录 后发表回答