Heul!
Da programmiert man stundenlang, nur um festzustellen, dass es einen viel einfacheren Weg gibt.
Vielleicht sollte ich eine direkte Hotline für Editorgadgets zu dir legen.
Nachdem du jetzt schon einige Dinge aus dem Ärmel gezaubert hast, probiere ich es doch mal mit einer Frage, die mich schon seit Ewigkeiten zur Verzweiflung treibt:
Projekt: Ich erzeuge aus dem Inhalt eines Editorgadget eine PDF-Ausgabe.
Problem: Die Textbreitenberechnung (automatischer Zeilenumbruch) ist äußerst ungenau (im Vergleich zu PDF), was manchmal zu unterschiedlichen Zeilenumbrüchen führt.
Frage 1: Gibt es eine Möglichkeit ein Editorgadget zu einem genaueren Zeilenumbruch zu bewegen.
Frage 2: Hast du Codeschnipsel, WinAPI-Befehle oder Ideen zum Erstellen eines eigenen Editorgadgets mit einer eigenen Breitenberechnung.
Für die Vorgehensweise der Berechnung gibt es einen C++ Code, aber das hilft mir nichts solange ich keine passendes Eingabefenster habe:
Code: Alles auswählen
/*----------------------------------------------------------------------
GetCharDesignWidths: Liefert die Zeichenbreiten der Schrift unskaliert
----------------------------------------------------------------------*/
UINT GetCharDesignWidths (HDC hdc, UINT uFirst, UINT uLast, int * piWidths)
{
HFONT hFont, hFontDesign ;
LOGFONT lf ;
OUTLINETEXTMETRIC otm ;
hFont = GetCurrentObject (hdc, OBJ_FONT) ;
GetObject (hFont, sizeof (LOGFONT), &lf) ;
// Outline-Textmetrik abfragen. Hier geht es ausschließlich um die Größe
// des vom Schriftdesigners verwendeten Koordinatensystems, der Geräte-
// kontext spielt dabei keine Rolle
otm.otmSize = sizeof (OUTLINETEXTMETRIC) ;
GetOutlineTextMetrics (hdc, sizeof (OUTLINETEXTMETRIC), &otm) ;
// Neue Schrift mit einer logischen Größe anlegen, die dem
// TrueType-intenen Koordinatensystem exakt entspricht
lf.lfHeight = - (int) otm.otmEMSquare ; // Zeichenhöhe, nicht Zeilenabstand!
lf.lfWidth = 0 ;
hFontDesign = CreateFontIndirect (&lf) ;
// Schrift in den Gerätekontext einsetzen und Zeichenbreiten ermitteln
SaveDC (hdc) ;
SetMapMode (hdc, MM_TEXT) ;
SelectObject (hdc, hFontDesign) ;
GetCharWidth (hdc, uFirst, uLast, piWidths) ;
SelectObject (hdc, hFont) ;
RestoreDC (hdc, -1) ;
// Aufräumen
DeleteObject (hFontDesign) ;
return otm.otmEMSquare ;
}
/*---------------------------------------------------------------------------
GetScaledWidths: Liefert die Zeichenbreiten für die gewählte Schriftgröße
als Gleitkommawerte
---------------------------------------------------------------------------*/
void GetScaledWidths (HDC hdc, double * pdWidths)
{
double dScale ;
HFONT hFont ;
int aiDesignWidths [LASTCHAR + 1] ;
int i ;
LOGFONT lf ;
UINT uEMSquare ;
// Outline-Zeichenbreiten abfragen
uEMSquare = GetCharDesignWidths (hdc, 0, LASTCHAR, aiDesignWidths) ;
// Abfrage der aktuell in den Kontext eingesetzten Schrift
hFont = GetCurrentObject (hdc, OBJ_FONT) ;
GetObject (hFont, sizeof (LOGFONT), &lf) ;
// Zeichenbreiten entsprechend skalieren und als Gleitkomma-Array speichern
dScale = (double) -lf.lfHeight / (double) uEMSquare ;
for (i = 0 ; i <= LASTCHAR ; i++)
pdWidths[i] = dScale * aiDesignWidths[i] ;
}
/*----------------------------------------------------------------
GetTextExtentFloat: Berechnet Textbreiten mit Gleitkommawerten
----------------------------------------------------------------*/
double GetTextExtentFloat (double * pdWidths, PTSTR psText, int iCount)
{
double dWidth = 0 ;
int i ;
for (i = 0 ; i < iCount ; i++)
dWidth += pdWidths [psText[i]] ;
return dWidth ;
}
/*--------------------------------------------------------------------------------------
Justify mit Breitenberechnung über die Originaldaten der Schrift, ohne Rundungsfehler
--------------------------------------------------------------------------------------*/
void Justify (HDC hdc, PTSTR pText, RECT * prc, int iAlign)
{
double dWidth, adWidths[LASTCHAR + 1] ;
int xStart, yStart, cSpaceChars ;
PTSTR pBegin, pEnd ;
SIZE size ;
// Array adWidths mit skalierten Gleitkomma-Zeichenbreiten besetzen
GetScaledWidths (hdc, adWidths) ;
yStart = prc->top ;
do // für jede Textzeile
{
cSpaceChars = 0 ; // bis jetzt 0 Leerzeichen
while (*pText == ' ') // führende Leerzeichen überspringen
pText++ ;
pBegin = pText ; // Zeiger auf den Zeilenanfang
do // solange, bis die Zeile bearbeitet ist
{
pEnd = pText ; // aktuelles Zeilenende (beim 1. Mal = Zeilenstart)
// Suche nach dem ersten/nächsten Leerzeichen
while (*pText != '\0' && *pText++ != ' ') ;
if (*pText == '\0')
break ;
// Leerzeichen gefunden. Wie viel Platz braucht die Zeile jetzt?
cSpaceChars++ ;
dWidth = GetTextExtentFloat (adWidths, pBegin, pText - pBegin - 1) ;
}
while (dWidth < (double) (prc->right - prc->left)) ;
cSpaceChars-- ; // dieses Leerzeichen nicht mitzählen
while (*(pEnd - 1) == ' ') // und weitere Leerzeichen am Zeilenende raus
{
pEnd-- ;
cSpaceChars-- ;
}
// Textende erreicht oder keine Leerzeichen gefunden?
if (*pText == '\0' || cSpaceChars <= 0)
pEnd = pText ;
// Platzbedarf erst jetzt über die Standardfunktion abfragen
GetTextExtentPoint32(hdc, pBegin, pEnd - pBegin, &size) ;
switch (iAlign) // Ausrichtung == xStart
{
case IDM_ALIGN_LEFT:
xStart = prc->left ;
break ;
case IDM_ALIGN_RIGHT:
xStart = prc->right - size.cx ;
break ;
case IDM_ALIGN_CENTER:
xStart = (prc->right + prc->left - size.cx) / 2 ;
break ;
case IDM_ALIGN_JUSTIFIED:
if (*pText != '\0' && cSpaceChars > 0)
SetTextJustification (hdc, prc->right - prc->left - size.cx, cSpaceChars) ;
xStart = prc->left ;
break ;
}
// Ausgabe einer Zeile
TextOut (hdc, xStart, yStart, pBegin, pEnd - pBegin) ;
// Vorbereitungen für die nächste Zeile
SetTextJustification (hdc, 0, 0) ;
yStart += size.cy ;
pText = pEnd ;
}
while (*pText && yStart < prc->bottom - size.cy) ;
}
Ich wäre für jeden Codeschnippsel und jede Anregung dankbar, bevor ich mich ans C++ lernen mache, um obigen Code nach PB zu übersetzen.
PS: Kompleter Code (C. Petzold):
http://thorsten-hoeppner.de/download/Justify2.zip