Aquí os dejo una utilidad con la que leo un fichero de texto y lo escribo en pantalla justificacado por los dos lados como puede verse en la imagen de ejemplo.
![Image](http://img205.imageshack.us/img205/8318/formtext.jpg)
Este es el programa:
Code: Select all | Expand
FUNCTION Prueba()
LOCAL oDlg,oFont
LOCAL cText := MemoRead( "Fichero.txt" )
LOCAL nAncho := 420
LOCAL aText
*
DEFINE FONT oFont NAME "Arial" SIZE 0,-13 BOLD
DEFINE DIALOG oDlg OF oWMain SIZE 480,580 COLOR 0,CLR_HGRAY TITLE " Formateando Texto"
oDlg:bPainted := { |hDc| PaintPrueba(hDc,oFont,aText,nAncho) }
ACTIVATE DIALOG oDlg CENTER ;
ON INIT aText := FormatText(oDlg,oFont,cText,nAncho)
RETURN NIL
FUNCTION FormatText(oDlg,oFont,cText,nAncho)
LOCAL nCont,nTokn,nCrLf
LOCAL cTrozo,cLinea,lFinLin
LOCAL aTexto := {}
LOCAL hDc
*
hDc := oDlg:GetDc()
*
cLinea := ""
DO WHILE !Empty(cText)
lFinLin := .F.
cLinea := ""
cTrozo := StrToken(cText,1)
IF Left(cTrozo,2) = CRLF
cText := SubStr(cText,3)
cTrozo := ""
cLinea := ""
lFinLin := .T.
ENDIF
nTokn := 0
DO WHILE !Empty(cTrozo)
cTrozo := StrToken(cText,1)
nCrLf := AT( CRLF, cTrozo )
IF nCrLf > 0
cTrozo := Left(cTrozo,nCrLf-1)
lFinLin := .T. // <------ FIN DE PARRAFO / END OF PARAGRAPH
ENDIF
IF GetTextWidth(hDc,cLinea+cTrozo,oFont:hFont) > nAncho
EXIT
ELSEIF lFinLin // <------ FIN DE PARRAFO / END OF PARAGRAPH
cText := STUFF(cText,1,LEN(cTrozo)+2,"")
cLinea += cTrozo
++nTokn
EXIT
ELSE
cText := LTRIM(STUFF(cText,1,LEN(cTrozo),""))
cLinea += cTrozo+" "
++nTokn
ENDIF
ENDDO
AADD( aTexto, {RTRIM(cLinea),nTokn,lFinLin} )
ENDDO
ATail(aTexto)[3] := .T. // LA ULTIMA LINEA SIEMPRE ES FIN DE PARRAFO
// LAST LINE IS ALWAYS END OF PARAGRAPH
oDlg:ReleaseDc()
*
RETURN aTexto
FUNCTION PaintPrueba(hDc,oFont,aText,nAncho)
LOCAL hOldPen := SelectObject( hDc, GetStockObject( 7 ) )
LOCAL hOldBush := SelectObject( hDc, GetStockObject( 4 ) )
*
Rectangle(hDc, 20, 20, 570, 470 )
SelectObject( hDc, GetStockObject( 0 ) )
Rectangle(hDc, 10, 10, 560, 460 )
*
PainText(hDc,oFont,aText,nAncho)
*
SelectObject( hDc, hOldBush)
SelectObject( hDc, hOldPen )
RETURN NIL
FUNCTION PainText(hDc,oFont,aText,nAncho)
LOCAL hOldFnt := SelectObject( hDc, oFont:hFont )
LOCAL nCont,nLong,nExtra
LOCAL nLinea := 30
*
FOR nCont = 1 TO LEN(aText)
nLong := GetTextWidth(hDc,aText[nCont,1],oFont:hFont)
nExtra := 0
// SOLO SE JUSTIFICAN LAS LINEAS QUE NO SON FIN DE PARRAFO
// ONLY NOT END OF PARAGRAPH LINES ARE JUSTIFIED
IF !aText[nCont,3] .AND. Len( aText[nCont,1] ) < (nAncho-nLong)
// ESTABLECE NUEVO ESPACIADO ENTRE CARACTERES (MAX. 4 POR ESTETICA)
// FIX NEW SPACING BETWEEN CHARACTERS (MAX. 4 FOR AESTHETICS REASONS)
nExtra := Min( 4, Int((nAncho-nLong)/Len(aText[nCont,1])) )
nExtra := SetTextCharacterExtra( hDc, nExtra )
// MIDE LA LINEA CON EL ESPACIADO NUEVO
// MEASURE LINE WITH THE NEW SPACING
nLong := GetTextWidth(hDc,aText[nCont,1],oFont:hFont)
ENDIF
IF !aText[nCont,3] .AND. nLong < nAncho
// ESTABLECE NUEVEO ESPACIADO ENTRE PALABRAS
// FIX NEW GAP BETWEEN WORDS
SetTextJustification(hDc, nAncho-nLong, aText[nCont,2]-1)
ENDIF
ExtTextOut( hDc, nLinea, 22, {nLinea,22,nLinea+16,22+nAncho}, aText[nCont,1] )
nLinea += 18
// SE REPONEN LOS ESPACIADOS
// UPDATES SPACINGS
SetTextJustification(hDc, 0, 0)
SetTextCharacterExtra( hDc, nExtra )
NEXT
SelectObject( hDc, hOldFnt )
RETURN NIL
La función FormatText() parte el texto y guarda las líneas en un array multidimensional de tres dimensiones, la primera dimensión guarda el texto de la línea, la segunda el número de palabras (tokens) que hay en esa línea, y la tercera .T. o .F. dependiendo de si la línea es la última del párrafo o no, respectivamente. Esta función la llamo desde ON INIT porque necesito el DC del diálogo para medir cada línea.
El texto lo pinto en PainText() en la que, para justificar las líneas de texto, utilizo una combinación de dos funciones: SetTextJustification() y SetTextCharacterExtra(). La primera viene con el FWH pero la segunda, como en mi versión de FWH no viene, la he implementado muy facilmente con:
Code: Select all | Expand
#pragma BEGINDUMP
#include <hbapi.h>
#include <windows.h>
HB_FUNC( SETTEXTCHARACTEREXTRA )
{
hb_retni( SetTextCharacterExtra( ( HDC ) hb_parnl( 1 ), ( int ) hb_parni( 2 ) ) ) ;
}
#pragma ENDDUMP
SetTextJustification() controla el espaciado entre palabras, hay que decirle cuantos pixels quieres distribuir (nAncho-nLong) y cuantos espacios hay en la línea (aText[nCont,2]-1), y ella solita se encarga de repartir los pixels entre esos espacios (unos espaciados serán 1 pixel más grandes que otros).
SetTextCharacterExtra() añade pixels entre letras. En realidad el pixel se añade a cada glypho (a todos menos al último) de manera que la letra ocupe más espacio. Sólo hay que decirle cuantos pixels quieres añadir. En el programa, verán que sólo llamo a esta función si hay menos letras que espacio sobrante. Len( aText[nCont,1] ) < (nAncho-nLong)
En la imagen ejemplo, se aprecia muy bien el efecto SetTextJustification() en la primera línea del cuarto párrafo y el efecto SetTextCharacterExtra() en la segunda línea del tercer párrafo. En la primera línea del último párrafo se nota que han ctuado ambas funciones.
Espero que les sirva.
Un saludo