2016-12-02 12 views
4

Graphics.DrawStringを使用して文字列を書き出しています。マウス位置が与えられていると文字列内でcharインデックスを取得する必要があります。文字列内の位置についてヒットテストを実行する方法

これはかなり簡単なはずですが、私は本当にうまくいくアプローチを見つけるのに苦労しています。

書き込みが管理された文字数を返すe.Graphics.MeasureStringが見つかりましたが、その文字数はissuesです。

そしてその後、現時点で私が持っている唯一の作業アプローチは aを測定している

ababc私は私のx位置を越えて行くが、これはひどいソリューションになるまで...

+0

可能な重複が[MeasureStringは常に空白が収まると思っ](http://stackoverflow.com/questions/40910320/measurestring-always-thinks-whitespace-will-fit) – pinkfloydx33

+0

https://msdn.microsoft。 com/ru-ru/library/windows/desktop/dd144860(v = vs.85).aspx –

+0

https://www.codeproject.com/tips/844745/analyzing-text-with-directwrite-in-net-using -sharp –

答えて

0

あなたはかつての長方形の座標を計算することができますあなたが書いた文字列の各文字を占めています。その後、このリストをスキャンして、マウス座標がこの長方形内にあるかどうかを調べることができます。

+1

*一般的なケースでは、これを不可にします。文字は実際に重なっています。 "Wa": "a"が始まる* * "W"が終わる前。 https://en.wikipedia.org/wiki/Kerning –

0

1つのコメントがあなたに言ったように、これはMeasureCharacterRangesを使用して達成することができます。私は最初に、私が以前の答えを編集して削除したと言わなければならない。次に、このコードはすべてhereに適合しています。

このソリューションは完璧ではありませんが、あなたが望むものを実現する可能性があります。まず、私たちは長い文字列最大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's 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 023456789asdjkhfkjasdhfklhasdlkfjhlasdkjhfasdlfhlasdc", 
             "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イベント:

これは、文字列や店舗2つのライン内のすべての文字位置を描画する方法であり、
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

これは解決策ですが、1024文字でラップされた画面がたくさんあるため、私の使用例ではうまくいくとは思えません。だから、それらの完全な画面(それらがすべて表示されていない場合でも私はまだそこに場所を追跡する必要があるので、どこを描画するか分からない)はおそらく150キロの文字です。私は多分描画コードの変更でこれを少し減らすことができるかもしれませんが、あなたはまだ画面上に30kの可視文字を持っているかもしれません。 – Sprotty

+0

@Sprotty私の更新された回答を参照してください。あなたのケースにはまだまだ合わないかもしれませんが、おそらくそれを適応させるかもしれません。それが役に立てば幸い。 – Pikoh

+0

これはうまくいきますが、画面が文字でいっぱいになっても、驚くほど高速ですが、文字が同期しなくなります。私はこれが32文字のブロックが個別に測定されていると思います。 私が尺度を取得して同期させることができた唯一の方法は、TextRenderer.DrawTextとTextRenderer.MeasureTextをTextFormatFlags.TextBoxControlで使用することです。 – Sprotty

関連する問題