4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【.NET】文字列が表示しきれないときに省略記号"..."を表示する

Last updated at Posted at 2020-12-30

はじめに

多言語対応の依頼があったのですが、1つの言語を切り替えて表示するのではなく複数言語(日本語と英語など)を一度に表示する方式でした。ラベルコントロールに1つに複数言語を表示するとなると改行して表示することになります。
長い文字列があり表示しきれない場合、省略記号"..."を末尾に表示する機能が、WinFormではラベルコントロールのAutoEllipsisプロパティをTrueにすることで実現できます。
しかし、言語ごとに実現したいので省略記号に変換した文字列を取得した上で改行して文字列連結するようにしたい。

Evacuation Sh...
避難場所

下記サイトに省略させる方法があるが、表示のみで省略された文字自体を取得することができない。
文字列が表示しきれないときに"..."を表示する - dobon.net
いい方法がないか検索したところ、下記サイトのプログラムを見つけたので、これを改良することにした。
Auto Ellipsis - CODE PROJECT

パス名の機能は除外し、DataGridView等に対応できるように引数を見直した。WinFormとWPFの両方作成した。

仕様

EllipsisクラスのTrimmingメソッドで省略された文字を取得することができます。
省略位置は、EllipsisFormatで指定します。Wordは他と組み合わせて指定します。
省略文字を変更することができます。

EllipsisFormat 省略方法
None 省略記号なし
End 末尾に省略記号を表示する
Start 先頭に省略記号を表示する
Middle 真ん中に省略記号を表示する
Word 単語単位で省略します

"Government of the people, by the people,"
Ellipsis.png
"あいうえいお かきくけこ さしすせそ たちつてと"
Ellipsis2.png
上から順に、NoneEndStartMiddleMiddle | Word で表示しています。

動作環境

  • Windows 10 Home
  • .NET Framework 4.7.2
  • Visual Studio 2019 Communication

使用例

WinForm

使用例
private void button1_Click(object sender, EventArgs e)
{
    string s = "Government of the people, by the people,";
    SetEllipsis(this.label1, s, Ellipsis.EllipsisFormat.End | Ellipsis.EllipsisFormat.Word);
}

private void SetEllipsis(Control ctrl, string text, Ellipsis.EllipsisFormat format)
{
    Graphics dc = ctrl.CreateGraphics();
    Font font = ctrl.Font;
    int width = ctrl.Width;

    ctrl.Text = Ellipsis.Trimming(text, dc, font, width, format);
}

WPF

使用例
private void Button_Click(object sender, RoutedEventArgs e)
{
    string s = "Government of the people, by the people,";
    SetEllipsis(this.Label1, s, Ellipsis.EllipsisFormat.Middle | Ellipsis.EllipsisFormat.Word);
}

private void SetEllipsis(ContentControl ctrl, string text, Ellipsis.EllipsisFormat format)
{
    double width = ctrl.Width;
    double fontSize = ctrl.FontSize;
    Typeface face = new Typeface(ctrl.FontFamily, ctrl.FontStyle, ctrl.FontWeight, ctrl.FontStretch);

    ctrl.Content = Ellipsis.Trimming(text, face, fontSize, width, format);
}

プログラム

Ellipsisクラスになります。

WinForm

Ellipsis.cs
using System;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Windows.Forms;

public class Ellipsis
{
    [Flags]
    public enum EllipsisFormat
    {
        None = 0,
        End = 1,
        Start = 2,
        Middle = 3,
        Word = 4
    }

    public static string EllipsisChars = "...";

    private static Regex prevWord = new Regex(@"\W*\w*$");
    private static Regex nextWord = new Regex(@"\w*\W*");

    public static string Trimming(string text, Graphics dc , Font font, int width, EllipsisFormat options)
    {
        if (string.IsNullOrEmpty(text))
            return text;

        if ((EllipsisFormat.Middle & options) == 0)
            return text;

        if (dc == null)
            throw new ArgumentNullException("dc");

        Size s = TextRenderer.MeasureText(dc, text, font);

        if (s.Width <= width)
            return text;

        string mid = text;
        string fit = "";
        int len = 0;
        int seg = mid.Length;

        while (seg > 1)
        {
            seg -= seg / 2;

            int left = len + seg;
            int right = mid.Length;

            if (left > right)
                continue;

            if ((EllipsisFormat.Middle & options) == EllipsisFormat.Middle)
            {
                right -= left / 2;
                left -= left / 2;
            }
            else if ((EllipsisFormat.Start & options) != 0)
            {
                right -= left;
                left = 0;
            }

            if ((EllipsisFormat.Word & options) != 0)
            {
                if ((EllipsisFormat.End & options) != 0)
                {
                    int left2 = left - prevWord.Match(mid, 0, left).Length;
                    if (left2 != 0) left = left2; 
                }
                if ((EllipsisFormat.Start & options) != 0)
                {
                    int right2 = right + nextWord.Match(mid, right).Length;
                    if (right2 != 0) right = right2;
                }
            }

            string str = mid.Substring(0, left) + EllipsisChars + mid.Substring(right);
            s = TextRenderer.MeasureText(dc, str, font);
            if (s.Width <= width)
            {
                len += seg;
                fit = str;
            }
        }

        return fit;
    }
}

WPF

Ellipsis.cs
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Media;

public class Ellipsis
{
    [Flags]
    public enum EllipsisFormat
    {
        None = 0,
        End = 1,
        Start = 2,
        Middle = 3,
        Word = 4
    }

    public static string EllipsisChars = "...";

    private static Regex prevWord = new Regex(@"\W*\w*$");
    private static Regex nextWord = new Regex(@"\w*\W*");

    public static string Trimming(string text, Typeface face, double fontSize, double width, EllipsisFormat options)
    {
        if (string.IsNullOrEmpty(text))
            return text;

        if ((EllipsisFormat.Middle & options) == 0)
            return text;

        if (face == null)
            throw new ArgumentNullException("face");

        Size s = MeasureText(text, face, fontSize);

        if (s.Width <= width)
            return text;

        string mid = text;
        string fit = "";
        int len = 0;
        int seg = mid.Length;

        while (seg > 1)
        {
            seg -= seg / 2;

            int left = len + seg;
            int right = mid.Length;

            if (left > right)
                continue;

            if ((EllipsisFormat.Middle & options) == EllipsisFormat.Middle)
            {
                right -= left / 2;
                left -= left / 2;
            }
            else if ((EllipsisFormat.Start & options) != 0)
            {
                right -= left;
                left = 0;
            }

            if ((EllipsisFormat.Word & options) != 0)
            {
                if ((EllipsisFormat.End & options) != 0)
                {
                    int left2 = left - prevWord.Match(mid, 0, left).Length;
                    if (left2 != 0) left = left2; 
                }
                if ((EllipsisFormat.Start & options) != 0)
                {
                    int right2 = right + nextWord.Match(mid, right).Length;
                    if (right2 != 0) right = right2;
                }
            }

            string str = mid.Substring(0, left) + EllipsisChars + mid.Substring(right);
            s = MeasureText(str, face, fontSize);
            if (s.Width <= width)
            {
                len += seg;
                fit = str;
            }
        }

        return fit;
    }

    static private Size MeasureText(string text, Typeface face, double fontSize)
    {
        var formattedText = new FormattedText(text,
                                              CultureInfo.
                                              CurrentCulture,
                                              FlowDirection.LeftToRight,
                                              face,
                                              fontSize,
                                              Brushes.Black,
                                              new NumberSubstitution(),
                                              1);

        return new Size(formattedText.Width, formattedText.Height);
    }
}

ライセンスっぽいこと

コード改変や配布は自由です。
このプログラムによる義務/責任を何ら負いません。

最後に

Visual Basic版も記述しようと思ったのですが、WinFormとWPFもとなると長くなりすぎるので Visual Basic版に関しては、「Telerik Code Converter」のサイトで Visual Basicに変換してください。
Visual BasicからC#への変換について

参照

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?