Я применил довольно рудиментарный метод «Justify» для рисования строки, однако я бы хотел ее оптимизировать, чтобы расстояние было немного более разбросанным.Обоснование строки вручную для метода DrawString() в C#
То, что я до сих пор, это:
string lastword = line.Split(' ').Last();
string lineNoLastWord = line.Substring(0,line.LastIndexOf(" ")).Trim();;
g.DrawString(lineNoLastWord, Font, brush, textBounds, sf);
g.DrawString(lastword, Font, brush, textBounds, ConvertAlignment(System.Windows.TextAlignment.Right));
ConvertAlignment
является пользовательский метод следующим образом:
private StringFormat ConvertAlignment(System.Windows.TextAlignment align) {
StringFormat s = new StringFormat();
switch (align) {
case System.Windows.TextAlignment.Left:
case System.Windows.TextAlignment.Justify:
s.LineAlignment=StringAlignment.Near;
break;
case System.Windows.TextAlignment.Right:
s.LineAlignment=StringAlignment.Far;
break;
case System.Windows.TextAlignment.Center:
s.LineAlignment=StringAlignment.Center;
break;
}
s.Alignment = s.LineAlignment;
return s;
}
Результат близок, но нуждается в некоторой наладке пространств в строке lineNoLastWord
.
Немного больше фона за кодом. line
является результатом метода, который отвечает за обнаружение того, что строка выходит за границы (ширина) и разбивает ее на строки и слова, разбивая и измеряя, когда она идет, чтобы обеспечить полную линию в пределах ширины области до нарисовать. Метод реализует другие свойства в гораздо более широком классе, но вот суть его:
internal LineBreaker breakIntoLines(string s, int maxLineWidth) {
List<string> sResults = new List<string>();
int stringHeight;
int lineHeight;
int maxWidthPixels = maxLineWidth;
string[] lines = s.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.None);
using (Graphics g=Graphics.FromImage(Pages[CurrentPage - 1])) {
g.CompositingQuality = CompositingQuality.HighQuality;
if (maxLineWidth<=0||maxLineWidth>(Pages[CurrentPage-1].Width-X)) {
maxWidthPixels=Pages[CurrentPage-1].Width-X;
}
lineHeight = (Int32)(g.MeasureString("X", Font).Height*(float)((float)LineSpacing/(float)100));
stringHeight = (Int32)g.MeasureString("X", Font).Height;
foreach (string line in lines) {
string[] words=line.Split(new string[] { " " }, StringSplitOptions.None);
sResults.Add("");
for (int i=0; i<words.Length; i++) {
if (sResults[sResults.Count-1].Length==0) {
sResults[sResults.Count-1]=words[i];
} else {
if (g.MeasureString(sResults[sResults.Count-1]+" "+words[i], Font).Width<maxWidthPixels) {
sResults[sResults.Count-1]+=" "+words[i];
} else {
sResults.Add(words[i]);
}
}
}
}
}
return new LineBreaker() {
LineHeight = lineHeight,
StringHeight = stringHeight,
MaxWidthPixels = maxWidthPixels,
Lines = sResults
};
}
internal class LineBreaker {
public List<string> Lines { get; set; }
public int MaxWidthPixels { get; set; }
public int StringHeight { get; set; }
public int LineHeight { get; set; }
public LineBreaker() {
Lines = new List<string>();
MaxWidthPixels = 0;
StringHeight = 0;
LineHeight = 0;
}
public LineBreaker(List<string> lines, int maxWidthPixels, int stringHeight, int lineHeight) {
Lines = lines;
MaxWidthPixels = maxWidthPixels;
LineHeight = lineHeight;
StringHeight = stringHeight;
}
}
Следующее изображение демонстрирует проблему, что это является причиной:
Я также видел this stackoverflow question and answers, и обнаружил, что это также неэффективный путь к пространству из-за неизвестного размера строки, а неизвестная ширина документа приведет к тому, что строка будет слишком длинной, если слишком много слов, или слишком коротким, при этом ничего не будет оправдано. Полное обоснование означает, что текстовые строки расположены как на левой, так и на правой сторонах, и, как правило, содержимое внутри равномерно разнесено как можно больше. Вот как я хотел бы его реализовать.
Решение, вероятно, расчет на lastWord
и lineNoLastWord
строк с некоторыми измерениями, чтобы обеспечить жизнеспособность выхода в том, что нет двух слов в строке будет работать или кучу вместе, и там не будет обивки на правая сторона, однако левая может по-прежнему содержать отступ или вкладку. Другая часть, которую следует рассмотреть, - это если строка короче определенного порога, тогда никакое обоснование не должно применяться.
UPDATE
У меня есть следующая концепция, которая должна работать, просто нужно, чтобы получить слово из указанного индекса и вставьте правильное место:
int lastwordwidth = (Int32)g.MeasureString(" " + lastword, Font).Width;
int extraspace=lines.MaxWidthPixels-(Int32)(g.MeasureString(" "+lineNoLastWord, Font).Width+lastwordwidth);
int totalspacesneeded = (Int32)Math.Floor((decimal)(extraspace/lines.SpaceWidth));
int spacecount = lineNoLastWord.Count(x => x == ' ');
int currentwordspace = 0;
for (int i=0; i<spacecount; i++) {
if (currentwordspace>spacecount) { currentwordspace = 0; }
// insert spaces where spaces already exist between each word
// use currentwordspace to determine which word to replace with a word and another space
if (currentwordspace==0) {
// insert space after word
} else {
// insert space before word
}
currentwordspace++;
}
Разве вы не видели [это] (http://csharphelper.com/blog/2014/10/fully-justify-a-line-of-text-in- с /)? Если вы вычисляете float, чтобы знать, как далеко двигаться после слова __each__, чтобы он распространял слова __evenly__ по строке. – TaW
Да, я видел, что, я полагаю, я мог бы выборочно вставлять пробелы, которые будут быстрее вызывать меньше графических вызовов. –
Ну, вы можете или лучше использовать n-пространства, но вам нужно будет точно узнать их ширину, что не так просто, как кажется, учитывая, что большинство измерительных вызовов не будут такими точными, как хотелось бы. не беспокойтесь о производительности, прежде чем у вас действительно возникнет проблема. (http://c2.com/cgi/wiki?PrematureOptimization) ;-) – TaW