我有一个标签显示在一行以上,我想证明其中的文字(左右对齐)。实现这一目标的最佳方法是什么?
答案 0 :(得分:7)
不幸的是,只支持三种最基本和最简单的对齐方式:Right
,Left
和Center
。
第四个Justified
或Block
在任何.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;
}
答案 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' });
}
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'});
}
工人方法
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