How to test hits on a position within a line

I am writing a string using Graphics.DrawString, and you need to get the char index on the string given by the mouse position.

It would seem to be fairly straightforward, but I'm really trying to find an approach that works.

I found e.Graphics.MeasureStringthat returns the number of characters that he managed to write, but has several problems .

The only working approach that I have at the moment is the measurement a, then ab, then abc, until I get past my position x, but this is a terrible decision ...

+4
source share
2

, char , . , , .

0

, , MeasureCharacterRanges. , , . , -, .

, , , . , 32 :

// Measure the characters in a string with
// no more than 32 characters.
private List<RectangleF> MeasureCharactersInWord(
    Graphics gr, Font font, string text)
{
    List<RectangleF> result = new List<RectangleF>();

    using (StringFormat string_format = new StringFormat())
    {
        string_format.Alignment = StringAlignment.Near;
        string_format.LineAlignment = StringAlignment.Near;
        string_format.Trimming = StringTrimming.None;
        string_format.FormatFlags =
            StringFormatFlags.MeasureTrailingSpaces;

        CharacterRange[] ranges = new CharacterRange[text.Length];
        for (int i = 0; i < text.Length; i++)
        {
            ranges[i] = new CharacterRange(i, 1);
        }
        string_format.SetMeasurableCharacterRanges(ranges);

        RectangleF rect = new RectangleF(0, 0, 10000, 100);
        Region[] regions =
            gr.MeasureCharacterRanges(
                text, font, this.ClientRectangle,
                string_format);

        foreach (Region region in regions)
            result.Add(region.GetBounds(gr));
    }

    return result;
}

, , :

private List<RectangleF> MeasureCharacters(Graphics gr,Font font, int      
                                           posY,string text)
{
    List<RectangleF> results = new List<RectangleF>();

    // The X location for the next character.
    float x = 0;

    // Get the character sizes 31 characters at a time.
    for (int start = 0; start < text.Length; start += 32)
    {
        // Get the substring.
        int len = 32;
        if (start + len >= text.Length) len = text.Length - start;
        string substring = text.Substring(start, len);

        // Measure the characters.
        List<RectangleF> rects =
            MeasureCharactersInWord(gr, font, substring);

        // Remove lead-in for the first character.
        if (start == 0) x += rects[0].Left;

        // Save all but the last rectangle.
        for (int i = 0; i < rects.Count + 1 - 1; i++)
        {
            RectangleF new_rect = new RectangleF(
                x, posY,
                rects[i].Width, rects[i].Height);
            results.Add(new_rect);

            // Move to the next character X position.
            x += rects[i].Width;
        }
    }

    // Return the results.
    return results;
}

, :

List<List<RectangleF>> linesCharactersPositions = new List<List<RectangleF>>();
private void Form3_Paint(object sender, PaintEventArgs e)
{
    linesCharactersPositions = new List<List<RectangleF>>();
    string[] lines = new string[] { "12345678  0234567890123456789012asdjkhfkjasdhfklhasdlkfjhlasdkjhfasdlfhlasdc",
                                        "vm,xv,cxznvrtrutyquiortorutoqwruyoiurweyoquitiqwrtiqwetryqweiufhsduafh" };
    Font f = new Font("Arial", 18);

    int lineY = 10;
    foreach (string line in lines)
    {
        DrawLongStringWithCharacterBounds(e.Graphics, line, new Font("Arial", 18), new PointF(10, lineY));
        linesCharactersPositions.Add(MeasureCharacters(e.Graphics, f,lineY, line));
        lineY += 20;
    }


}

, MouseMove:

private void Form_MouseMove(object sender, MouseEventArgs e)
{
    Graphics g = this.CreateGraphics();
    int characterCount = 0;
    foreach(var linePositions in linesCharactersPositions)
    {
        for (int i = 0; i < linePositions.Count; i++)
        {
            if (linePositions[i].Contains(e.Location))
            {

                label1.Text = "Index: " + (i+characterCount);
            }
        }
        characterCount += linePositions.Count;
    }

}
0

Source: https://habr.com/ru/post/1662606/


All Articles