不幸的是只有三个最基本和最简单的类型的对齐支持:Right,Left和Center.
第四个,Justified或者Block,在任何.NET控件afaik都不支持,甚至不在RichtTextBox:-(
唯一的解决方法是添加任何空格或更好更小的空白字符像thin space(U + 2009)或hair space 常规的空间后,即直到字之间(U + 200A)Label的Height变化.然后退一步,尝试找到下一个插入点,即下一行,依此类推......直到到达文本末尾.
有点棘手但不是很难.
这是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;
}
Run Code Online (Sandbox Code Playgroud)
另一个实现。
这个仅在单词之间插入“头发空格”。
编辑:
添加了一种实现段落块对齐的方法。
无论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' });
}
Run Code Online (Sandbox Code Playgroud)
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'});
}
Run Code Online (Sandbox Code Playgroud)
工人方法
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();
}))();
}
Run Code Online (Sandbox Code Playgroud)
关于RichTextBox。
@TaW表示它不支持块对齐,但这并非完全正确。
RichTextBox众所周知是基于RichEdit类,并且该类支持“ Justification”。
旧的Platform SDK(带有示例)中对此进行了报告。
RichTextBox的AdvancedTypographicsOption在句柄创建过程中被明确截断。
(这与实现PARAFORMAT与PARAFORMAT2结构无关,这无关紧要,这是有意为之)。
因此,这是处理不良RichTextBox的“方法”。从其派生并重写OnHandleCreated的类可重新启用“ Justification”。
适用于段落级别或从某个点开始。
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6731 次 |
| 最近记录: |