如何证明标签中的文字

时间:2016-05-11 06:55:39

标签: c# winforms label justify

我有一个标签显示在一行以上,我想证明其中的文字(左右对齐)。实现这一目标的最佳方法是什么?

3 个答案:

答案 0 :(得分:7)

不幸的是,只支持三种最基本和最简单的对齐方式:RightLeftCenter

第四个JustifiedBlock在任何.NET控件中都不受支持,即使在RichtTextBox中也不支持: - (

唯一的解决方法是在单词之间添加空格或更好的小空格字符,如thin space(U + 2009)或hair space(U + 200A),即在常规空格之后直到Label Height次更改public static void ProcessQueueMessage([ServiceBusTrigger("mysb")] string message) { // do something with message } 。然后退一步,尝试找到下一个插入点,即下一行,依此类推......直到到达文本末尾。

有点棘手但不是很难。

答案 1 :(得分:7)

这是TaW提出的解决方案的实现。它只是实现的基本代码 - 没有自动重新调整等。

public void Justify(System.Windows.Forms.Label label)
{
    string text = label.Text;
    string[] lines = text.Split(new[]{"\r\n"}, StringSplitOptions.None).Select(l => l.Trim()).ToArray();

    List<string> result = new List<string>();

    foreach (string line in lines)
    {
        result.Add(StretchToWidth(line, label));
    }

    label.Text = string.Join("\r\n", result);
}

private string StretchToWidth(string text, Label label)
{
    if (text.Length < 2)
        return text;

    // A hair space is the smallest possible non-visible character we can insert
    const char hairspace = '\u200A';

    // If we measure just the width of the space we might get too much because of added paddings so we have to do it a bit differently
    double basewidth = TextRenderer.MeasureText(text, label.Font).Width;
    double doublewidth = TextRenderer.MeasureText(text + text, label.Font).Width;
    double doublewidthplusspace = TextRenderer.MeasureText(text + hairspace + text, label.Font).Width;
    double spacewidth = doublewidthplusspace - doublewidth;

    //The space we have to fill up with spaces is whatever is left
    double leftoverspace = label.Width - basewidth;

    //Calculate the amount of spaces we need to insert
    int approximateInserts = Math.Max(0, (int)Math.Floor(leftoverspace / spacewidth));

    //Insert spaces
    return InsertFillerChar(hairspace, text, approximateInserts);
}

private static string InsertFillerChar(char filler, string text, int inserts)
{
    string result = "";
    int inserted = 0;

    for (int i = 0; i < text.Length; i++)
    {
        //Add one character of the original text
        result += text[i];

        //Only add spaces between characters, not at the end
        if (i >= text.Length - 1) continue;

        //Determine how many characters should have been inserted so far
        int shouldbeinserted = (int)(inserts * (i+1) / (text.Length - 1.0));
        int insertnow = shouldbeinserted - inserted;
        for (int j = 0; j < insertnow; j++)
            result += filler;
        inserted += insertnow;
    }

    return result;
}

行动中:
Demo

答案 2 :(得分:3)

另一种实施方式 这个插入&#34;头发空间&#34;只在单词之间。

修改
添加了一个实现段落对齐的方法 JustifyParagraph()JustifyLine()都会调用工作方法Justify()

<强> EDIT2:
方法调用已更改。

label1.Text = JustifyParagraph(label1.Text, label1.Font, label1.ClientSize.Width);

public string JustifyParagraph(string text, Font font, int ControlWidth)
{
    string result = string.Empty;
    List<string> ParagraphsList = new List<string>();
    ParagraphsList.AddRange(text.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList());

    foreach (string Paragraph in ParagraphsList) {
        string line = string.Empty;
        int ParagraphWidth = TextRenderer.MeasureText(Paragraph, font).Width;

        if (ParagraphWidth > ControlWidth) {
            //Get all paragraph words, add a normal space and calculate when their sum exceeds the constraints
            string[] Words = Paragraph.Split(' ');
            line = Words[0] + (char)32;
            for (int x = 1; x < Words.Length; x++) {
                string tmpLine = line + (Words[x] + (char)32);
                if (TextRenderer.MeasureText(tmpLine, font).Width > ControlWidth)
                {
                    //Max lenght reached. Justify the line and step back
                    result += Justify(line.TrimEnd(), font, ControlWidth) + "\r\n";
                    line = string.Empty;
                    --x;
                } else {
                    //Some capacity still left
                    line += (Words[x] + (char)32);
                }
            }
            //Adds the remainder if any
            if (line.Length > 0)
            result += line + "\r\n";
        }
        else {
            result += Paragraph + "\r\n";
        }
    }
    return result.TrimEnd(new[]{ '\r', '\n' });
}

enter image description here
enter image description here

JustifyLines()仅处理单行文字(短于客户区)

textBox1.Text = JustifyLines(textBox1.Text, textBox1.Font, textBox1.ClientSize.Width);

public string JustifyLines(string text, Font font, int ControlWidth)
{
    string result = string.Empty;
    List<string> Paragraphs = new List<string>();
    Paragraphs.AddRange(text.Split(new[] { "\r\n" }, StringSplitOptions.None).ToList());

    //Justify each paragraph and re-insert a linefeed
    foreach (string Paragraph in Paragraphs) {
        result += Justify(Paragraph, font, ControlWidth) + "\r\n";
    }
    return result.TrimEnd(new[] {'\r', '\n'});
}


enter image description here
enter image description here


工人方法

private string Justify(string text, Font font, int width)
{
    char SpaceChar = (char)0x200A;
    List<string> WordsList = text.Split((char)32).ToList();
    if (WordsList.Capacity < 2)
        return text;

    int NumberOfWords = WordsList.Capacity - 1;
    int WordsWidth = TextRenderer.MeasureText(text.Replace(" ", ""), font).Width;
    int SpaceCharWidth = TextRenderer.MeasureText(WordsList[0] + SpaceChar, font).Width
                       - TextRenderer.MeasureText(WordsList[0], font).Width;

    //Calculate the average spacing between each word minus the last one 
    int AverageSpace = ((width - WordsWidth) / NumberOfWords) / SpaceCharWidth;
    float AdjustSpace = (width - (WordsWidth + (AverageSpace * NumberOfWords * SpaceCharWidth)));

    //Add spaces to all words
    return ((Func<string>)(() => {
        string Spaces = "";
        string AdjustedWords = "";

        for (int h = 0; h < AverageSpace; h++)
            Spaces += SpaceChar;

        foreach (string Word in WordsList) {
            AdjustedWords += Word + Spaces;
            //Adjust the spacing if there's a reminder
            if (AdjustSpace > 0) {
                AdjustedWords += SpaceChar;
                AdjustSpace -= SpaceCharWidth;
            }
        }
        return AdjustedWords.TrimEnd();
    }))();
}


关于RichTextBox。
@TaW表示它并不支持Block Align,但这并不完全正确 众所周知,RichTextBox基于RichEdit类,并且该类支持&#34; Justification&#34;。
这在旧版Platform SDK中报告(带示例) RichTextBox在创建句柄时显式截断了AdvancedTypographicsOption (它不是关于实现PARAFORMAT与PARAFORMAT2结构,这是无关紧要的,是故意的。)

所以这是一个&#34;治愈&#34;对于可怜的RichTextBox。 一个派生自它的类,并重写OnHandleCreated以重新启用&#34; Justification&#34;。
适用于段落级别或从某一点开始。

public class JustifiedRichTextBox : RichTextBox
{
    [DllImport("user32", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, [In] [Out] ref PARAFORMAT2 pf);

    [DllImport("user32", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

    public enum TextAlignment
    {
        Left = 1,
        Right,
        Center,
        Justify
    }

    private const int EM_SETEVENTMASK = 1073;
    private const int EM_GETPARAFORMAT = 1085;
    private const int EM_SETPARAFORMAT = 1095;
    private const int EM_SETTYPOGRAPHYOPTIONS = 1226;
    private const int TO_ADVANCEDTYPOGRAPHY = 0x1;
    private const int WM_SETREDRAW = 11;
    private const int PFM_ALIGNMENT = 8;
    private const int SCF_SELECTION = 1;

    [StructLayout(LayoutKind.Sequential)]
    private struct PARAFORMAT2
    {
        //----------------------------------------
        public int cbSize;             // PARAFORMAT
        public uint dwMask;
        public short wNumbering;
        public short wReserved;
        public int dxStartIndent;
        public int dxRightIndent;
        public int dxOffset;
        public short wAlignment;
        public short cTabCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public int[] rgxTabs;
        //----------------------------------------
        public int dySpaceBefore;   // PARAFORMAT2
        public int dySpaceAfter;
        public int dyLineSpacing;
        public short sStyle;
        public byte bLineSpacingRule;
        public byte bOutlineLevel;
        public short wShadingWeight;
        public short wShadingStyle;
        public short wNumberingStart;
        public short wNumberingStyle;
        public short wNumberingTab;
        public short wBorderSpace;
        public short wBorderWidth;
        public short wBorders;
    }

    private int updating = 0;
    private int oldEventMask = 0;

    public new TextAlignment SelectionAlignment
    {//SelectionAlignment is not overridable
        get
        {
            PARAFORMAT2 pf = new PARAFORMAT2();
            pf.cbSize = Marshal.SizeOf(pf);
            SendMessage(this.Handle, EM_GETPARAFORMAT, SCF_SELECTION, ref pf);
            if ((pf.dwMask & PFM_ALIGNMENT) == 0) return TextAlignment.Left;
            return (TextAlignment)pf.wAlignment;
        }
        set
        {
            PARAFORMAT2 pf = new PARAFORMAT2();
            pf.cbSize = Marshal.SizeOf(pf);
            pf.dwMask = PFM_ALIGNMENT;
            pf.wAlignment = (short)value;
            SendMessage(this.Handle, EM_SETPARAFORMAT, SCF_SELECTION, ref pf);
        }
    }

    //Overrides OnHandleCreated to enable RTB advances options
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);

        //EM_SETTYPOGRAPHYOPTIONS allows to enable RTB (RichEdit) Advanced Typography
        SendMessage(this.Handle, EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY);
    }
}   //JustifiedRichTextBox

enter image description here
enter image description here