0

「Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus arcu massa, tempus non tincidunt ut, tempus sit amet odio. Mauris in dui sed enim vulputate dictum」という文字列があるとします。

その文字列を特定の長さ (ピクセル単位) で、言葉を壊さずにラップしたい。たとえば、80 ピクセル。

文字列の描画に使用する Font 変数と Graphics 変数 (「g」と呼ばれることが多い) があるため、必要に応じて文字列の長さを測定できます。

私が見つけたすべてのサンプルは、テキストを文字長で折り返すだけでしたが、GDI+ 描画にはピクセル単位で必要です。バグがあるように見えるので、TextRenderer コントロールを使用したくありません。時々、それ自体のテキストの高さが間違っていると測定されます。まれですが、起こります。

これまでのところ、次のものが得られました。

public static string WrapTextByPixels(string text, ref Graphics g, Font font, float maxWidth)
        {
            string[] originalLines = text.Split(new[] { " " }, StringSplitOptions.None);

            var wrapBuilder = new StringBuilder();

            float currentLineWidth = 0;

            foreach (var item in originalLines)
            {
                float itemWidth = g.MeasureString(item, font).Width;

                currentLineWidth += itemWidth;
                if (currentLineWidth > maxWidth ||
                    itemWidth > maxWidth) // When a single word is longer than the maxWidth then just add it
                {
                    wrapBuilder.Append(Environment.NewLine);
                    currentLineWidth = 0;
                }
                wrapBuilder.Append(item + " ");
            }

            return wrapBuilder.ToString();
        }

しかし、上記のコードは機能しません。一部の行はまだ長すぎます。

4

3 に答える 3

2

ここでTextRendererをバイパスすることはできません。後で、DrawText()メソッドがテキストをレンダリングするときに、計算されたレイアウトがレンダリングされたものと一致するように、そのMeasureText()メソッドを使用する必要があります。Graphics.MeasureString()など、文字列の長さを計算する他の方法では、エラーが増えるだけで、Graphicsクラスのテキストレイアウトは大きく異なります。そして、かなり壊れています。TextRendererが.NET2.0で追加された理由

悪い結果が得られた場合、それはほとんどの場合、TextFormatFlagsを正しく指定しなかったことが原因です。DrawText()メソッド呼び出しで使用されるフラグと正確に一致する必要があります。これは、特にフレームワーク内にコードをペイントしてテキストを描画する場合は、必ずしも簡単に見つけることができるとは限りません。参照ソースを使用して調べてください。

于 2012-11-09T13:46:41.147 に答える
1

GDI+ テキスト フォーマッタが壊れていると完全に確信しているわけではありませんが、必要なことを実行できず、自分でワード ラップを行う必要がある場合があります。

「単純な」アプローチは、文字列をスキャンして、改行を挿入してもよい場所 (スペースなど - ただし、コンマやダッシュなどの句読点を潜在的な場所として考慮することもできます) を探すことです。

単語ごとに新しい文字列を作成するときに、 を使用Graphics.MeasureStringして線の新しい幅を決定します。必要な幅を超える場合は、現在の単語の前に改行を挿入する必要があります。

使用可能な幅で分割できないテキスト (スペースを含まない非常に長い単語、または非常に狭いフォーマット幅) では問題が発生することに注意してください。そのため、これらの状況では単語内で分割するフォールバック メカニズムが必要になる場合があります (収まる最後の文字で停止するか、気が狂ってハイフネーション システムを追加します)。

また、StringFormat使用する は、測定しているテキストの開始/終了に空白を含める/除外するように設定できるため、このようなテキストフラグメントを操作するときに問題を引き起こす可能性があることに注意してください。これにより、幅の計算が台無しになる可能性があります。最後の文字が書式設定領域の端を「かすめる」ときは、ワードラップが少し早すぎるか遅すぎます。同様に、行末の空白や複数の空白文字列にも注意する必要があります。

デバッグの場合、ウィンドウの幅に基づいて書式設定の幅を設定し、再描画のたびにテキストを再書式設定することをお勧めします。次に、ウィドウを徐々にドラッグして前後にドラッグし、フォーマッタが理想的な幅でワード ラップを行っていること、狭いフォーマット領域などに対応していることを確認します。

于 2012-11-09T13:35:11.187 に答える
1

これは私がかつて見つけた拡張メソッドです。これは私自身のものではなく、クレジットを提供したいのですが、どこから入手したか覚えていません。

public static string WrapText(this string text, double pixels, string fontFamily, float emSize)
    {
        string[] originalLines = text.Split(new[] { " " }, StringSplitOptions.None);

        var wrapBuilder = new StringBuilder();

        double actualWidth = 0;

        foreach (var item in originalLines)
        {
            var formatted = new FormattedText(
                item,
                CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                new Typeface(fontFamily),
                emSize,
                Brushes.Black);

            actualWidth += formatted.Width;
            if (actualWidth > pixels)
            {
                wrapBuilder.Append(Environment.NewLine);
                actualWidth = 0;
            }
            wrapBuilder.Append(item + " ");
        }

        return wrapBuilder.ToString();
    }

これは途中で役立つはずです。

于 2012-11-09T12:52:30.557 に答える