Página 1 de 1

Etiquetas - Harbour

Enviado: 05 Nov 2010 01:13
por Pablo César
Preciso de ajuda.
Decidí fazer a impressão de etiquetas em modo gráfico.
Para isso idealizei que devo guardar as coordenadas de cada etiquetas em pixels numa matriz.
Pretendo utilizar apenas um estilo de fonte "Courrier" (porque mantem a mesma dimensão de largura do caracter) mas com 2 tamanhos diferentes, em folha de A4. Mas não sei como fazer em Harbour.
Alguém pode me dar um exemplo prático, quais as funções, libs que devo utilizar ? E me indicar como compilar em Harbour ?. As coordenadas em pixels irei descobrir no momento dos testes e talvez com ajuda matemática. Mas preciso decolar e não sei como começar. O exemplo pode ser de três linhas para cada etiqueta por 7 colunas de etiquetas.
Se houver algum exemplo peço que me desculpem e anexarei este tópico ao existente no caso.
Conto com a boa ajuda de vocês e da paciência por eu não saber quase nada de Harbour.

Re: Etiquetas - Harbour

Enviado: 05 Nov 2010 11:05
por gvc
Bom, no xHarbour eu uso o WIN32PRN para montar alguns informes e o principio será o mesmo para etiquetas. Sei que vc esta querendo para o Harbour, mas acho que a idéia é valida e existe uma função euivalente ao WIN32PRN.
Etiquetas mesmo eu só montei usando o NODOSIMP.
Vou mandar algumas partes. Não posso mandar o fonte inteiro.
Como vc vê abaixo, dá para colocar cordenadas Linha, Coluna. Fica mais fácil do que colocar coordenadas em pixwl pois a resolução da impressora irá influenciar os valores. Já penei por isso tb.
Boa sorte.

Criar

Código: Selecionar todos

cprinter := getdefaultprinter()
oprinter:= win32prn():new(cprinter)
oPrinter:Landscape:= .F.
oPrinter:FormType := FORM_A4
oPrinter:Copies   := 1
oPrinter:Create()
oPrinter:startDoc()
corpo do relatório

Código: Selecionar todos

oPrinter:SetPrc(linha, 10)
oPrinter:TextOut('Total:')
oPrinter:SetPrc(linha, 40)
oPrinter:TextOut(transform(a_tot[3, 1], '@E 99,999,999,999.99'))
oPrinter:SetPrc(linha, 60)
oPrinter:TextOut(transform(a_tot[3, 2], '@E 99,999,999,999.99'))
oPrinter:SetPrc(linha++, 80)
oPrinter:TextOut(transform(a_tot[3, 3], '@E 99,999,999,999.99'))

...

oPrinter:SetPrc(linha++, 10)
oPrinter:TextOut("CNPJ: 99999999999999999", .T.)
oPrinter:SetPrc(linha++, 10)
oPrinter:TextOut("Informe de Recolhimento de Fornecedores - " + str(m->xano, 4), .T.)
Fecha o relatório

Código: Selecionar todos

oprinter:enddoc()
oprinter:destroy()

Etiquetas - Harbour

Enviado: 07 Nov 2010 01:44
por Pablo César
Obrigado Gilberto pelas dicas e desculpe não ter retornado antes. De fato sirviram-me em grande parte mas tive bastante trabalho para entender tudo como funciona.

1. Tive sempre o pensamento que tudo que era xHarbour não servia para Harbour. Existem poucas diferenças, nada que não possa ser adaptado de um para o outro. Uma delas neste meu caso é o uso do "WIN32PRN" do xHarbour que substiuí por WIN_PRN para funcionar com Harbour. Essa explicação tem de bastante no fórum.
2. Discordei com a utilização da função TextOut() através de linha e coluna (como no @ lin,col say do Clipper) ora porque eu disse que a minha necessidade estava em fazer em forma gráfica. Claro que fazer a impressão em modo gráfico, não é aconselhável em impressoras matricias, mais ainda pela imprecisão de posição do papel durante a troca de folha soltas (nem sempre é no mesmo lugar), por isso eu ja possuo impressão de etiqueta em formulário contínuo para etiquetas, onde a remalinas ajuda muito no tracionamento e fixação do papel. Daí sim é aconselhável o uso da impressão não gráfica. Mas como agora praticamente as impressoras USBs de jato de tinta e laser estão a um preço mais acessíveis e os formulário de etiquetas não se adequam a impressão não gráfica, isto é, porque o espaçamento de uma etiqueta a outra tem que ser corrigido constantemente e isso ja causou muito problema para meus clientes. Por isso decidí fazer duas formas de impressão, conforme a impressora. Então em lugar do TextOut() coloquei o TextOutAt() no qual posso informar em pixels o que me dá maior precisão no posicionamento de cada etiqueta. Que constem outras funções para impressão como:

Código: Selecionar todos

oPrinter:textAtFont([<nPosX>]      , ;
                    [<nPosY>]      , ;
                     <cString>     , ;
                    [<cFontName>]  , ;
                    [<nPointSize>] , ;
                    [<nFontWidth>] , ;
                    [<nFontWeight>], ;
                    [<lUnderLine>] , ;
                    [<lItalic>]    , ;
                    [<lNewLine>]   , ;
                    [<lUpdatePosX>], ;
                    [<nTextColor>] , ;
                    [<nTextAlign>]   ) --> lSuccess

oPrinter:textOutAt([<nPosX>]      , ;
                   [<nPosY>]      , ;
                    <cString>     , ;
                   [<lNewLine>]   , ;
                   [<lUpdatePosX>], ;
                   [<nTextAlign>]   ) --> lSuccess

3. Você fala de diferentes resoluções entre uma impressora e outra, mas mesmo assim não creio que isso interfira na precisão do posicionamento de cada etiqueta. Pois acredito que quando se trata em definir o tamanho da fonte de acordo o PointSize do SetFont() deva ser para todas as impressoras o mesmo. É dizer um caracter de tamanho 8cpp é igual para todas. Vou ainda fazer testes em jato tinta e laser para constatar essa questão.
4. No seu código exemplo, faltou o essencial: SetFont() e eu me batí muito, pois tinha visto um exemplo de um colega e que estava errado e ainda eu tinha colocado antes do "oPrinter:Create()" daí nunca mudava o tamanho e eu ficava fustrado, até que hoje de manhã percebí o meu erro.
5. Outra coisa que sempre me deixou em dúvidas, é como fazer a compilação para que fique registrado fiz assim:
HBMK2 -lhbwin -lxhb etq1.prg

Eu gosto de relatar a minha experiência, pois é assim que podemos contribuir para esclarecer futuras dúvidas de outros colegas. E por isso estou passando o meu primeiro exemplo de impressão:

Código: Selecionar todos

#include "hbcompat.ch"
#define FORM_A4 9

Function Main()
cprinter := GetDefaultPrinter()
oprinter:= win_prn():new(cprinter)
oPrinter:Landscape:= .F.
oPrinter:FormType := FORM_A4
oPrinter:Copies   := 1
oPrinter:CharSet(255)

oPrinter:Create()
oPrinter:startDoc()

// sintaxe: oPrinter:setFont(cFontName, nPointSize, nFontWidth, nFontWeight, lUnderline, lItalic, nCharSet)
oPrinter:SetFont('Times New Roman', 06, 0 , , , ,255)
oPrinter:TextOutAt( 30.00, 66.00, 'ABCDEFGHIJKLMNOPQR')
oPrinter:SetFont('Courier New', 18, 0 , , , ,255)
oPrinter:TextOutAt( 30.00, 106.00, '12345')
oPrinter:SetFont('Arial Narrow', 06, 0 , , , ,255)
oPrinter:TextOutAt( 30.00, 116.00, 'ABCDEFGHIJKLMNOPQRST')

oprinter:enddoc()
oprinter:destroy()
return nil
Vou ainda melhor este código, com certeza. Um dos pequenos desafios é centralizar o texto, mas não farei com PADC() é dizer não farei pela quantidade de caracteres, farei pelo tamnho em pixels que ocoupa uma determinada string com cada fonte utilizada. Só para efeito de aprendizado, pois fazendo pelo tamanho de string nem sempre fica perfeita a centralização, principalmente com fonte proporcionais não de tamanho fixo como a Courrier e Courrier New.

Re: Etiquetas - Harbour

Enviado: 07 Nov 2010 17:07
por rochinha
Amiguinho,

Não sei como voce montou o conjunto a ser impresso, mas aqui vai um trecho de um antigo sistema meu onde eu montava as etiquetas em vetores e depois imprimia.

A grande diferença é que as propriedades das etiquetas poderia ser intercambiadas no momento da impressão tornando o mais profissional possivel.

Eu criei um comando extendido para auxiliar:

Código: Selecionar todos

#command ETIQUETE COM TOPO <lbTOPO>            ;
                      CARREIRAS <lbCARREIRA>   ; 
                      LARGURA <lbLARGURA>      ; 
                      ALTURA <lbLINHAS>        ; 
                      ENTRE <lbENTRE>          ;
                      ESPACOS <lbESPACOS>      ;
                      MARGEM DE <lbMARGEM>     ;
                      [FOLHA <lbFOLHA>]        ;
                      [REPETIR <lbREPETIR>]    ;
                      [CAMPOS <list1,...>] =>  ;
         MALETI(<lbTOPO>,<lbCARREIRA>,<lbLARGURA>,<lbLINHAS>,<lbENTRE>,<lbESPACOS>,<lbMARGEM>,{<list1>},<lbREPETIR>,<lbFOLHA>)
Exemplo do comando:

Código: Selecionar todos

       ETIQUETE COM TOPO      M->lbTOPO       ; 
                    CARREIRAS M->lbCARREIRA   ; 
                    LARGURA   M->lbLARGURA    ; 
                    ALTURA    M->lbLINHAS     ; 
                    ENTRE     M->lbENTRE      ;
                    ESPACOS   M->lbESPACOS    ;
                    MARGEM DE M->lbMARGEM     ;
                    FOLHA     M->lbl_FOL      ;
                    CAMPOS    {||NOME}               , ;
                              {||ENDERECO}           , ;
                              {||BAIRRO+' - '+ESTADO}, ;
                              {||ALLTRIM(CIDADE)+' - '+CEP}                , ;
                              {||' '}                , ;
                              {||' '}                 
Veja que neste momento estou passando os campos que quero e que depois a função fará a avaliação e preenchimento do vetor.

A função:

Código: Selecionar todos

PROCEDURE MALETI( lbTOPO    , ;
                  lbCARREIRA, ;
                  lbLARGURA , ;
                  lbLINHAS  , ;
                  lbENTRE   , ;
                  lbESPACOS , ;
                  lbMARGEM  , ;
                  lbUDF     , ;
                  lbREPETIR , ;
                  lbFOLHAS  , ;
                  lbUDF2    )
   // INICIO *********************************************************************************
   M->lbID       := lbID   
   M->lbUDF      := lbUDF
   M->lbNOME     := lbNOME
   M->lbLARGURA  := lbLARGURA
   // Se o numero de campos forem menores que numero de linhas
   // o numero de linhas ENTER sera acrescido do restante 
   M->lbENTRE    := lbENTRE  // IIF(LEN(lbUDF)<lbLINHAS,lbENTRE+(lbLINHAS-LEN(lbUDF)),lbENTRE)
   // Se o numero de campos forem menores que numero de linhas
   // o numero de linhas sera igual a numero de campos
   M->lbLINHAS   := lbLINHAS // IIF(LEN(lbUDF)<lbLINHAS,LEN(lbUDF),lbLINHAS)
   M->lbMARGEM   := lbMARGEM
   M->lbTOPO     := lbTOPO
   M->lbESPACOS  := lbESPACOS
   M->lbCARREIRA := lbCARREIRA
   M->lbREPETIR  := IIF(lbREPETIR=NIL,1,lbREPETIR+1)
   M->lb_REPETIR := DIV(M->lbREPETIR,M->lbCARREIRA)
   IF (lbFOLHAS = 0 .OR. lbFOLHAS = NIL)
      M->lbFOLHAS   := 0
      M->lb_FOLHAS  := 0
   ELSE
      M->lbFOLHAS   := lbFOLHAS+M->lbCARREIRA
      M->lb_FOLHAS  := INT(DIV(M->lbFOLHAS ,M->lbCARREIRA))
   ENDIF
   // FIM *********************************************************************************
   M->TIPO_PRN="I"
   IF MENU_PRN() = NIL
      RESTSCREEN(LIN_MENU+1,00,23,79,TELA_PRI)
      RETURN
   ENDIF
   SET DEVI TO PRINT
   SETPRC(0,0)
   IF M->TIPO_PRN = 'I'
      @ PROW()+M->lbTOPO, PCOL() SAY CondOn
      IF (lbFOLHAS = 0 .OR. lbFOLHAS = NIL)
         M->lbTOPO := 0
      ENDIF
   ENDIF
   DO WHILE .NOT. EOF()
      IF INKEY()=27
         SET PRINT OFF
         SET CONSOLE ON
         IF PERG("Continua a impress„o ?")="S"
            MENSAGEM("Tecle <ESC> para pausa ou interrup‡„o")
            SET PRINT ON
            SET CONSOLE OFF
         ELSE
            SET PRINT ON
            SET CONSOLE OFF
            EXIT
         ENDIF
      ENDIF
      // INICIO *********************************************************************************
      Alabel := {}
      FOR TX = 1 TO M->lbCARREIRA // Dependendo de quantas carreiras preenche e libera a continuação
          TArray := {}
          FOR TY = 1 TO LEN(M->lbUDF)
              aadd( TArray, EVAL( M->lbUDF[TY] ) )
          NEXT
          aadd( Alabel, TArray )
          IF lbUDF2 # NIL
             EVAL( M->lbUDF2 )
          ENDIF
          SKIP
          IF recco() = 1
             GO BOTTOM
          ENDIF
      NEXT
      // FIM *********************************************************************************
      DO WHILE .T.
         // INICIO *********************************************************************************
		 // Esta função será a que voce produzirá com comandos Harbour
         PrintLabel( Alabel, M->lbLARGURA, M->lbLINHAS, M->lbENTRE, M->lbESPACOS, M->lbMARGEM )
         // FIM *********************************************************************************
         M->lb_REPETIR = M->lb_REPETIR - 1
         IF M->lb_FOLHAS <> 0
            M->lb_FOLHAS  = M->lb_FOLHAS  - 1
            IF M->lb_FOLHAS <= 1
               //EJECT
               SET DEVICE TO SCREEN
               SET CONSOLE ON
               IF PERG("Nova folha esta pronta ?")="S"
               ENDIF
               MENSAGEM(' ')
               SET CONSOLE OFF
               SET DEVICE TO PRINT
               M->lb_FOLHAS  = INT(DIV(M->lbFOLHAS ,M->lbCARREIRA))
               SETPRC(0,0)
               @ PROW()+M->lbTOPO, PCOL() SAY CondOn
            ENDIF
         ENDIF
         IF M->lb_REPETIR <= 1
            EXIT
         ENDIF
      ENDDO
      IF recco() < 2
         EXIT
      ENDIF
   ENDDO
   SET PRINT OFF
   SET CONSOLE ON
CLOSE DATABASES
deviceprinter( 250 )
RESTSCREEN(LIN_MENU+1,00,23,79,TELA_PRI)
RETURN

FUNCTION LB_CLI
   TArray := {}
   aadd( TArray, iif( eof(), '', NOME                   ) )
   aadd( TArray, iif( eof(), '', ENDERECO               ) )
   aadd( TArray, iif( eof(), '', BAIRRO+' - '+ESTADO    ) )
   aadd( TArray, iif( eof(), '', CEP                    ) )
   aadd( Alabel, TArray )
   RETURN .T.
A função controla até o tamanho da página a fim de me mostrar quando tenho que colocar outra folha, lógico que isto era válido para clientes que usavam matriciais e para não perder nenhuma etiqueta preferiam colocar uma folha por vez.

A partes que estão entre "// INICIO/FIM ******" exemplificam os trechos que voce necessita entender, já que o corpo é uma estrutura normal de relatório.

Acho que tá fácil de entender.

Re: Etiquetas - Harbour

Enviado: 08 Nov 2010 08:46
por asimoes
Olá Rochinha,

Muito bom o seu exemplo.

Para ficar completo faltou as seguintes funções:

Mensagem()
Div()
Perg()
DevicePrinter()
Menu_Prn()
PrintLabel()

[]´s

Etiquetas - Harbour

Enviado: 09 Nov 2010 12:55
por rochinha
Amiguinho,

Use o código para modelar a sua idéia. usando a estrutura como base.

As funções não são nada extraordinárias:

Mensagem(), basta um @ ..say com o parametro passado.
Div(), recebe os valores e retorna a divisão somente se os dois forem diferente de zero, já que existe um bug no Clipper relativo a divisão por zero.

Código: Selecionar todos

function div( valorA, valorB )
return iif( valorA=0.or.valorB=0, 0, valorA/valorB )
As outras funções fazem parte do conjunto gerado por programas como o MIRO e não são interessantes no contexto.

Código: Selecionar todos

FUNCTION PRINTLABEL( PALABEL, PCOLUNAS, PLINHAS, PABAIXO, PENTRE, PMARGEM )
LOCAL TX, TY
SETPRC(0,0)
FOR TX:=1 TO PLINHAS                               // Linhas dentro da etiqueta
    FOR TY:=1 TO LEN(PALABEL)                      // colunas dentro da etiqueta
        @ PROW(),(((PCOLUNAS+PENTRE)*(TY-1))+(TY-1))+PMARGEM SAY SUBSTR(PALABEL[TY][TX],1,PCOLUNAS-PENTRE)
    NEXT
    DEVPOS(PROW()+1,0)
NEXT
DEVPOS(IIF(PLINHAS=NIL,LEN(PALABEL),PLINHAS+PABAIXO),0)
RETURN NIL