2011-01-19 14 views
5

Sto lavorando a un progetto che mi ha fatto approssimare il rendering del testo come immagine e un editor DHTML per il testo. Le immagini vengono renderizzate utilizzando il metodo DrawText di .NET 4 DrawingContext.Calcolo del wrapping di testo in .NET DrawingContext Metodo DrawText

Il metodo DrawText acquisisce il testo insieme alle informazioni sui caratteri e alle dimensioni e calcola il wrapping necessario per far sì che il testo si adatti il ​​più possibile, posizionando un'ellissi alla fine se il testo è troppo lungo. Quindi, se ho il seguente codice per disegnare il testo in un rettangolo che si è abbrevaiate:

string longText = @"A choice of five engines, although the 2-liter turbo diesel, supposedly good for 48 m.p.g. highway, is not coming to America, at least for now. A 300-horsepower supercharged gasoline engine will likely be the first offered in the United States. All models will use start-stop technology, and fuel consumption will decrease by an average of 19 percent across the A6 lineup. A 245-horsepower A6 hybrid was also unveiled, but no decision has yet been made as to its North America sales prospects. Figure later in 2012, if sufficient demand is detected."; 

var drawing = new DrawingGroup(); 
using (var context = drawing.Open()) 
{ 
    var text = new FormattedText(longText, 
     CultureInfo.CurrentCulture, 
     FlowDirection.LeftToRight, 
     new Typeface("Calibri"), 
     30, 
     Brushes.Green); 
    text.MaxTextHeight = myRect.Height; 
    text.MaxTextWidth = myRect.Width; 

    context.DrawText(text, new Point(0, 0)); 
} 

var db = new DrawingBrush(drawing); 
db.Stretch = Stretch.None; 
myRect.Fill = db; 

C'è un modo per calcolare come il testo sarà avvolto? In questo esempio, il testo in uscita è avvolto ad "2 litri" e "48 m.p.g" ecc come visto nella figura: alt text

risposta

2

Non sono sicuro se hai ancora bisogno di una soluzione o se questa particolare soluzione è appropriato per la tua applicazione, ma se inserisci lo snippe sottostante t subito dopo il tuo blocco using ti mostrerà il testo in ogni riga (e quindi dove il testo è stato rotto per il wrapping).

Sono arrivato a questa soluzione utilizzando l'approccio molto ghetto/guerrilla delle sole proprietà di esplorazione durante il debug, cercando i segmenti di testo avvolti - li ho trovati e erano in proprietà accessibili ... quindi eccoci. Molto bene può essere un modo più corretto/diretto.

// Object heirarchy: 
// DrawingGroup (whole thing) 
// - DrawingGroup (lines) 
//  - GlyphRunDrawing.GlyphRun.Characters (parts of lines) 

// Note, if text is clipped, the ellipsis will be placed in its own 
// separate "line" below. Give it a try and you'll see what I mean. 

List<DrawingGroup> lines = drawing.Children.OfType<DrawingGroup>().ToList(); 

foreach (DrawingGroup line in lines) 
{ 
    List<char> lineparts = line.Children 
     .OfType<GlyphRunDrawing>() 
     .SelectMany(grd => grd.GlyphRun.Characters) 
     .ToList(); 

    string lineText = new string(lineparts.ToArray()); 

    Debug.WriteLine(lineText); 
} 

Btw, Ciao David. :-)

+0

* Perfetto *. Stavo guardando attraverso la fonte della struttura e ho visto la tecnica di enumerazione delle linee, ma sembrava che tutto sull'oggetto FormattedText fosse privato; Mi sono avvicinato al solo uso della riflessione per esporre queste proprietà, ma questa è una soluzione molto migliore. A proposito, Ciao Shaun! Molto tempo dopo le cattive strade di La Mirada! – t3rse

3

È possibile utilizzare la funzione Graphics.MeasureString (String, caratteri, Int32). Si passa la stringa, il carattere e la larghezza massima. Restituisce un SizeF con il rettangolo che si formerebbe. È possibile utilizzare questo per ottenere l'altezza complessiva, e quindi il numero di linee:

Graphics g = ...; 
Font f = new Font("Calibri", 30.0); 
SizeF sz = g.MeasureString(longText, f, myRect.Width); 
float height = sz.Height; 
int lines = (int)Math.round(height/f.Height); // overall height divided by the line height = number of lines 

Ci sono molti modi per ottenere un oggetto Graphics, e qualsiasi faranno da quando si utilizzano solo per misurare e non disegnare (potrebbe essere necessario correggere i suoi campi DPix, DpiY, e PageUnit dal momento che tali misure ad effetto

modi per ottenere un oggetto Graphics:.

Graphics g = e.Graphics; // in OnPaint, with PaintEventArgs e 
Graphics g = x.CreateGrahics(); // where x is any Form or Control 
Graphics g = Graphics.CreateFrom(img); // where img is an Image. 
+0

Graphics.MeasureString è * non * un sostituto di TextRenderer.MeasureText(). –

+0

+1 Hans. In realtà l'origine di questo problema è che il codice che utilizza la tecnica di cui sopra è impreciso su una base quasi regolare. – t3rse