Texto justificado

Texto justificado

Postby antolin » Mon Jun 28, 2010 3:55 pm

Hola Foreros

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

Este es el programa:

Code: Select all  Expand view
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 view
#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
Peaaaaaso de foro...
antolin
 
Posts: 492
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Texto justificado

Postby antolin » Mon Jun 28, 2010 3:57 pm

I'll try to explain it in English

This is an utility to read text from a file and paint it justifying each line in the two side (see the picture in the task above).

FormatText() breaks text in lines and save them in a multidimensional array (3 dimensions). In the first dimension I save the line's text, in the second one the number of words (tokens) in the line, and in the last one .T. or .F. depending if this is the last line in a paragraph or not, respectively. I call it from the ON INT clause because I need use the dialog DC to measure the text.

PainText() paint the text justified in each side. I use a combination of two functions: SetTextJustification() and SetTextCharacterExtra(). The firt one is included in FWH, the second one, in my FWH not, but I easily implement it like this:

Code: Select all  Expand view
#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() controls the gap between words. We must provide how many pixels we want to distribute (nAncho-nLong) and how many spaces are in the line (aText[nCont,2]-1). The function look after the pixels are allocated between all spaces (some spaces will be 1 pixel greater than others).

SetTextCharacterExtra() adds pixels between characters. In fact, pixels are added into each character's glyph (except into the last one) so that, characters take up more space. We only must tell the function how many pixels we want to add. In the program I only call this function when there are less characters than spare space. Len( aText[nCont,1] ) < (nAncho-nLong)

In the sample picture, you can see the SetTextJustification() effect on the first line of the fourth paragraph and the SetTextCharacterExtra() effect on the second line of the third paragraph. On the first line of the last paragraph you can observe the two effects.

Regards
Peaaaaaso de foro...
antolin
 
Posts: 492
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Texto justificado

Postby Patricio Avalos Aguirre » Wed Jun 30, 2010 5:30 pm

se agradece

gracias
Saludos
Patricio

__________________________________________________________________
Version: Harbour 3.2.0dev (r1307082134),Compiler: Borland C++ 5.8.2 (32-bit)
PCode version: 0.3, FWH 13.2
http://www.sialm.cl
User avatar
Patricio Avalos Aguirre
 
Posts: 1059
Joined: Fri Oct 07, 2005 1:56 pm
Location: La Serena, Chile

Re: Texto justificado

Postby Manuel Aranda » Wed Jun 30, 2010 8:09 pm

Antolín,
Muchííísimas gracias por el aporte.
Un saludo,
Manuel

xH 1.2.3, FWH 23.07 32 bits, BC++ 7.4, xVerce CW 1.0, PellesC
User avatar
Manuel Aranda
 
Posts: 603
Joined: Wed Oct 19, 2005 8:20 pm
Location: España

Re: Texto justificado

Postby FranciscoA » Wed Jun 30, 2010 8:21 pm

Agradecido por el aporte. Saludos.
Francisco J. Alegría P.
Chinandega, Nicaragua.

Fwxh-MySql-TMySql
User avatar
FranciscoA
 
Posts: 2114
Joined: Fri Jul 18, 2008 1:24 am
Location: Chinandega, Nicaragua, C.A.

Re: Texto justificado

Postby antolin » Thu May 30, 2013 5:04 pm

Hola a todos, gracias al foro he detectado un pequeño bug en mi función que hacia que en algunas circuntancias el texto no se justificaba, pero lo he solucionado.

No hay más que cambiar la función FormatText por esta otra muy similar:

Code: Select all  Expand view
FUNCTION FormatText(oDlg,oFont,cText,nAncho)   // SEPARA EL TEXTO EN LINEAS
   LOCAL cTrozo,cLinea,lFinLin                 // Y LAS GUARDA EN UN ARRAY
   LOCAL aTexto := {}
   LOCAL nCrlf  := 0
   LOCAL nTokn  := 0
   LOCAL hDc    := oDlg:GetDc()
   LOCAL nChar  := Int(nAncho/GetTextWidth(hDc,"B",oFont:hFont))
   *
   DO WHILE !Empty(cText)
      lFinLin := .F.
      cLinea  := ""
      nTokn := 0
      *
      cTrozo  := StrToken(cText,1)
      IF Left(cTrozo,2) = CRLF
         cText  := SubStr(cText,3)
         cTrozo := ""
         lFinLin := .T.
      ENDIF
      IF GetTextWidth(hDc,cTrozo,oFont:hFont) > nAncho
     cLinea := Left(cTrozo,nChar)
     cText  := STUFF(cText,1,LEN(cLinea),"")
     cTrozo := ""
      ENDIF
      *
      DO WHILE !Empty(cTrozo) .AND. !Empty(cText)
         cTrozo := StrToken(cText,1)
         nCrLf  := AT( CRLF, cTrozo )
         IF nCrLf > 0
            cTrozo  := Left(cTrozo,nCrLf-1)
            lFinLin := .T. //  <------------  FIN DE PARRAFO
         ENDIF
         *
         IF GetTextWidth(hDc,cLinea+cTrozo,oFont:hFont) > nAncho
        IF GetTextWidth(hDc,cTrozo,oFont:hFont) > (nAncho*0.4)
           cLinea := Left(cLinea+" "+cTrozo,nChar)
           cText  := STUFF(cText,1,LEN(cLinea),"")
        ENDIF
        lFinLin := .F. //  <------------  NO FIN DE PARRAFO
        cTrozo  := ""
         ELSEIF lFinLin
            cText := STUFF(cText,1,LEN(cTrozo)+2,"")
            cLinea += cTrozo
        cTrozo := ""
            ++nTokn
         ELSE
            cText := LTRIM(STUFF(cText,1,LEN(cTrozo),""))
            cLinea += cTrozo+" "
            ++nTokn
         ENDIF
     *
     IF Empty(cText)    // LA ULTIMA LINEA SIEMPRE HA DE SER FIN DE PARRAFO
        lFinLin := .T.
     ENDIF
      ENDDO
      *
      AADD( aTexto, {RTRIM(cLinea),nTokn,lFinLin} )
   ENDDO
   oDlg:ReleaseDc()
RETURN aTexto


Un saludo
Peaaaaaso de foro...
antolin
 
Posts: 492
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Texto justificado

Postby FranciscoA » Thu May 30, 2013 5:12 pm

Antolin, gracias.
Saludos.
Francisco J. Alegría P.
Chinandega, Nicaragua.

Fwxh-MySql-TMySql
User avatar
FranciscoA
 
Posts: 2114
Joined: Fri Jul 18, 2008 1:24 am
Location: Chinandega, Nicaragua, C.A.

Re: Texto justificado

Postby Antonio Linares » Thu May 30, 2013 5:22 pm

Gracias! :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41404
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Texto justificado

Postby cnavarro » Thu May 30, 2013 5:36 pm

Muy util
Muchas gracias
Saludos
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6504
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Texto justificado

Postby juanjogascem » Tue Jul 22, 2014 6:37 am

Hola, encontre estas funciones para justificar el texto en pantalla. Pero por mas que intento trasladarlo a la impresora, no soy capaz de que me imprima nada. ¿Alguien lo hizo o sabe como hacerlo?

Un saludo
Juanjo
juanjogascem
 
Posts: 100
Joined: Wed May 31, 2006 8:49 am

Re: Texto justificado

Postby antolin » Wed Aug 06, 2014 4:03 pm

A mi me funciona así:

Code: Select all  Expand view
PRINT oPrn NAME "FICHA DE PARAMETRO" // PREVIEW
*
DEFINE FONT oFont[1] NAME "Arial" SIZE 0,-12  OF oPrn
DEFINE FONT oFont[2] NAME "Arial" SIZE 0,-14  OF oPrn
*
oPrn:SetPage(9)
oPrn:SetPortrait()
*
PAGE
...
... // CABECERAS, TITULOS Y DEMAS

aTexto := FormatText(oPrn,oFont[1],cText,nAncho)  // cText -> TEXTO A IMPRIMIR
PainText(oPrn,oFont[1],aTexto,6,8,0.2,nAncho)   // DE VARIAS LINEAS DE LARGO

...  // PIE, Nº DE PAGINA, ETC.
...
ENDPAGE
*
oFont[1]:End()
oFont[2]:End()
ENDPRINTER
SysRefresh()
RETURN NIL

-------------------------------------------------------

FUNCTION PainText(oPrn,oFont,aText,nX,nY,nLin,nPix,oFnP)    // nX,nY COORDENADAS INICIO TEXTO
   LOCAL nLong,nExtra,nPass                 // nL -> PASO DE LINEA
                                // nPix -> ANCHO MAXIMO DE LINEA
   LOCAL nCont := 0
   *
   oFont:Activate( oPrn:hDCOut )
   oPrn:Cmtr2Pix(@nX, @nY)
   oPrn:Cmtr2Pix(@nLin, nCont)
   SetbkMode( oPrn:hDCOut, 1 )
   nLin += oFont:nHeight
   nPass := 27.5    // ULTIMA LINEA DE PAGINA
   oPrn:Cmtr2Pix(@nPass, nCont)
   *
   FOR nCont = 1 TO Len(aText)
       nLong  := GetTextWidth( oPrn:hDCOut, aText[nCont,1], oFont:hFont)
       nExtra := 0
       IF !aText[nCont,3] .AND. Len( aText[nCont,1] ) < (nPix-nLong)
      nExtra := Min( 3, Int((nPix-nLong)/Len(aText[nCont,1])) )
          nExtra := SetExtraChar( oPrn:hDcOut, nExtra )
      nLong  := GetTextWidth( oPrn:hDCOut, aText[nCont,1], oFont:hFont)
       ENDIF
       IF !aText[nCont,3] .AND. nLong < nPix
          SetTextJustification(oPrn:hDcOut,nPix-nLong,aText[nCont,2]-1)
       ENDIF
       ExtTextOut( oPrn:hDCOut,nX,nY,{nX,nY,nX+oFont:nHeight+5,nY+nPix-1},aText[nCont,1])
       nX += nLin
       SetTextJustification(oPrn:hDcOut, 0, 0)
       SetExtraChar( oPrn:hDcOut, nExtra )
       IF nX > nPass
      oFont:DeActivate( oPrn:hDCOut )

      // CAMBIO DE PAGINA: Pie_de_Página() + ENDPAGE + PAGE + Cabecera(), ETC
      ++nPage
      nX := ... // DONDE EMPIEZA LA SIGUIENTE PAGINA. PUEDE VENIR DE Cabecera()

      oFont:Activate( oPrn:hDCOut )
       ENDIF
   NEXT
   oFont:DeActivate( oPrn:hDCOut )
RETURN nX // DEVUELVE nX PARA PODER IMPRIMIR MAS COSAS DETRAS
 

Un saludo
Peaaaaaso de foro...
antolin
 
Posts: 492
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Texto justificado

Postby antolin » Wed Aug 06, 2014 4:14 pm

Independientemente, he modificado FormatText() para corregir algunos desajustes:
Code: Select all  Expand view
FUNCTION FormatText(hDc,cFrase,hFnt,nAnch,nCuantos)
   LOCAL cTrozo,cRengl,lFin
   LOCAL nChar := Int(nAnch/GetTextWidth(hDc,"B",hFnt))-5
   LOCAL aLins := {}
   LOCAL nCrlf := 0
   LOCAL nCnt  := 0
   LOCAL nTok  := 0

   DEFAULT nCuantos := 9999
   *
   DO WHILE !Empty(cFrase) .AND. nCnt < nCuantos
      ++nCnt
      lFin   := .F.
      cRengl := ""
      nTok   := 0
      *
      nCrlf  := Len(cFrase)-Len(LTRIM(cFrase))  // POR SI EMPIEZA CON ESPACIOS
      cTrozo := Space(nCrlf)+StrToken(cFrase,1)
      *
      IF Left(cTrozo,2) = CRLF
     cFrase := SubStr(cFrase,3)
     cTrozo := ""
     lFin   := .T.
      ENDIF
      IF GetTextWidth(hDc,cTrozo,hFnt) > nAnch
     cRengl := Left(cTrozo,nChar)
     cFrase := SubStr(cFrase,nChar+1)
     cTrozo := Left(cFrase,1)
     DO WHILE !( GetTextWidth(hDc,cRengl+cTrozo,hFnt) > nAnch )
        cRengl := cRengl+cTrozo
        cFrase := SubStr(cFrase,2)
        cTrozo := Left(cFrase,1)
     ENDDO
     IF !Empty(cRengl)
        nTok   := 1
     ENDIF
     cTrozo := ""
      ENDIF
      *
      DO WHILE !Empty(cTrozo) .AND. !Empty(cFrase)
         nCrlf  := Len(cFrase)-Len(LTRIM(cFrase))   // POR SI EMPIEZA CON ESPACIOS
     cTrozo := Space(nCrlf)+StrToken(cFrase,1)
     *
     nCrlf  := AT( CRLF, cTrozo )
     IF nCrlf > 0
        cTrozo := Left(cTrozo,nCrlf-1)
        lFin := .T.
     ENDIF
     *
     IF GetTextWidth(hDc,cRengl+cTrozo,hFnt) > nAnch
        IF nAnch > 100 .AND. GetTextWidth(hDc,cRengl,hFnt) < (nAnch*0.75)
           cFrase := cRengl+cFrase
           cRengl := Left(cRengl+cTrozo,nChar)
           cFrase := SubStr(cFrase,LEN(cRengl)+1)
           cTrozo := Left(cFrase,1)
           DO WHILE !( GetTextWidth(hDc,cRengl+cTrozo,hFnt) > nAnch )
          cRengl := cRengl+cTrozo
          cFrase := SubStr(cFrase,2)
          cTrozo := Left(cFrase,1)
           ENDDO
           ++nTok
        ENDIF
        lFin   := .F.
        cTrozo := ""
     ELSEIF lFin
        cFrase := SubStr(cFrase,LEN(cTrozo)+2+1)    // +2 POR EL CRLF
        cRengl += cTrozo
        cTrozo := ""
        ++nTok
     ELSE
        cFrase := SubStr(cFrase,LEN(cTrozo)+1)
        cRengl += cTrozo
        ++nTok
     ENDIF
     *
     IF Empty(cFrase)   // LA ULTIMA LINEA SIEMPRE HA DE SER FIN DE PARRAFO
        lFin := .T.
     ENDIF
      ENDDO
      *
      nCrlf := Len(cRengl)-Len(LTRIM(cRengl))
      IF nCrlf < 2
     cRengl := ALLTRIM(cRengl)
      ELSE
     cRengl := RTRIM(SubStr(cRengl,2))
      ENDIF
      *
      AADD(aLins,cRengl)
   ENDDO
RETURN aLins


Los parámetros de FormatText(hDc,cFrase,hFnt,nAnch,nCuantos) han cambiado porque ya llevo algunas versiones de la función y la ultima la utilicé así, pero es fácil modificarla para adaptarla a tus necesidades.

De todas formas, quédate también con la antigua por si te funciona mejor.

Un saludo.
Peaaaaaso de foro...
antolin
 
Posts: 492
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Texto justificado

Postby antolin » Wed Aug 06, 2014 4:17 pm

UPS... la antepenúltima líneas era:
Code: Select all  Expand view
AADD(aLins,{cRengl,nTok,lFin})
Peaaaaaso de foro...
antolin
 
Posts: 492
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Texto justificado

Postby sysctrl2 » Wed Aug 06, 2014 11:35 pm

puedes poner un ejemplo con todo y .exe ?
la imagen ya no aparece,

saludos..
Cesar Cortes Cruz
SysCtrl Software
Mexico

' Sin +- FWH es mejor "
User avatar
sysctrl2
 
Posts: 971
Joined: Mon Feb 05, 2007 7:15 pm

Re: Texto justificado

Postby antolin » Fri Aug 08, 2014 8:35 am

Esta era la imagen:

Image
Peaaaaaso de foro...
antolin
 
Posts: 492
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Next

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 84 guests