zu rechtfertigen Ich habe eine ziemlich rudimentäre "Justify" -Methode zum Zeichnen einer Zeichenfolge implementiert, jedoch möchte ich sie optimieren, so dass der Abstand etwas verstreut ist.Eine Zeichenfolge manuell für DrawString() -Methode in C#
Was ich habe, so weit ist dies:
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
ist eine benutzerdefinierte Methode wie folgt:
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;
}
Das Ergebnis ist in der Nähe, aber etwas Einstellen der Räume in der Zeichenfolge muss lineNoLastWord
.
Ein bisschen mehr Hintergrund hinter dem Code. line
ist das Ergebnis einer Methode, die dafür verantwortlich ist, zu erkennen, ob die Zeichenfolge außerhalb der Grenzen (Breite) liegt und diese in Zeilen und Wörter zerlegt, bricht und misst, um sicherzustellen, dass die gesamte Zeile innerhalb der Breite des Bereichs bleibt gezogen werden. Das Verfahren implementiert andere Eigenschaften in einer viel größeren Klasse, aber hier ist der Kern von ihm:
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;
}
}
Das folgende Bild zeigt das Problem, dass dies verursacht:
ich auch gesehen habe this stackoverflow question and answers, und festgestellt, dass es aufgrund der unbekannten Größe des Strings auch ein ineffizienter Weg zum Leerzeichen ist und die unbekannte Breite des Dokuments führt dazu, dass die Zeichenfolge zu lang ist, wenn zu viele Wörter oder zu kurz mit nichts richtig ausgerichtet. Die vollständige Ausrichtung bedeutet, dass der Text sowohl links als auch rechts ausgerichtet ist und dass der Inhalt im Inneren möglichst gleichmäßig verteilt ist. Dies würde ich gerne umsetzen.
Die Lösung, ist wahrscheinlich eine Berechnung auf dem lastWord
und lineNoLastWord
Strings mit einigen Messungen Lebensfähigkeit des Ausgangs dadurch, dass keine zwei Worte in der Kette, um sicherzustellen, zusammen oder Bündel läuft, und es wird auf die keine Polsterung sein rechte Seite, jedoch kann links noch einen Einzug oder eine Registerkarte enthalten. Ein weiterer zu berücksichtigender Teil ist, wenn die Zeichenfolge kürzer als ein bestimmter Schwellenwert ist, sollte keine Rechtfertigung angewendet werden.
UPDATE
Ich habe folgendes Konzept, das aus dem angegebenen Index sollte funktionieren, muss nur das Wort erhalten und den richtigen Platz ein:
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++;
}
Haben Sie [diese] nicht sehen (http://csharphelper.com/blog/2014/10/fully-justify-a-line-of-text-in- c /)? Wenn man einen Float berechnet, um zu wissen, wie weit man sich nach jedem Wort bewegen soll, so verteilt es die Wörter __levenly__ über die Zeile. – TaW
Ja, ich habe gesehen, dass ich selektiv Leerzeichen einfügen könnte, die schneller sind und weniger Grafikaufrufe verursachen. –
Nun, Sie können oder besser können Sie n-Leerzeichen verwenden, aber Sie müssen ihre Breite ziemlich genau wissen, die nicht so einfach ist, wie es klingt, da die meisten Meastring-Aufrufe nicht so genau sein werden, wie man hoffen würde. Aber Mach dir keine Sorgen über die Leistung, bevor du tatsächlich ein Problem hast .. (Siehe ['vorzeitige Optimierung'] (http://c2.com/cgi/wiki?PrematureOptimization) ;-) – TaW