none
Ayuda para imprimir factura en impresora matricial

    Question

  • Hola, 

    Les escribo para que me den una mano ya que estoy algo trancado.

    Tengo un proyecto el cual obtiene datos de una base de datos de SQL Server y a éstos los debe imprimir en una factura pre-diseñada (de esas con los agujeros a los costados) en una impresora de matriz de punto EPSON LX-300+.

    Tengo el siguiente código, el cual lo hice midiendo y midiendo con regla la factura, pero estoy seguro que hay alguna forma mas sencilla de hacerlo.

    private void button1_Click(object sender, EventArgs e)
        {
          printDialog1.Document = printDocument1;
          if (printDialog1.ShowDialog() == DialogResult.OK)
          {
            printDocument1.Print();
          }
          
          
        }
        public DataSet oset = new DataSet();
        private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
    
          int fecha_x = 79;
          int fecha_y = 215;
          int contado_x = 661;
          int contado_y = 215;
          int nombre_x = 102;
          int nombre_y = 246;
          int ruc_x = 79;
          int ruc_y = 234;
          int tel_x = 571;
          int tel_y = 265;
          int direccion_x = 102;
          int direccion_y = 267;
          int parcial_x = 129;
          int parcial_y = 518;
          int cant_cartones_x = 79;
          int cant_cartones_y = 325;
          int detalle_x = 136;
          int detalle_y = 325;
          int precio_carton_x = 439;
          int precio_carton_y = 325;
          int exentas_x = 560;
          int exentas_y = 325;
          int minimo_x = 635;
          int minimo_y = 325;
          int maximo_x = 749;
          int maximo_y = 325;
          int salto_y = 15;
    
          DatosFactura fact = new DatosFactura();
          oset = fact.ObtenerDatos();
          DataRow fila = oset.Tables[0].Rows[0];
          Font letra = new Font("Courier New", 10);
          fact.fecha = Convert.ToDateTime(fila["fecha"]).ToShortDateString();
          fact.nombre_cliente = fila["nombre_cliente"].ToString();
          fact.ruc_cliente = fila["ruc_cliente"].ToString();
          fact.tel_cliente = fila["tel_cliente"].ToString();
          fact.direccion_cliente = fila["direccion_cliente"].ToString();
          fact.total_pagar = Convert.ToDouble(fila["total_pagar"]);
          e.Graphics.DrawString(fact.fecha, letra, Brushes.Black, 79, 215);
          e.Graphics.DrawString("X", letra, Brushes.Black, 661, 215);
          e.Graphics.DrawString(fact.nombre_cliente, letra, Brushes.Black, 102, 246);
          e.Graphics.DrawString(fact.ruc_cliente, letra, Brushes.Black, 79, 234);
          e.Graphics.DrawString(fact.tel_cliente, letra, Brushes.Black, 571, 265);
          e.Graphics.DrawString(fact.direccion_cliente, letra, Brushes.Black, 102, 265);
          e.Graphics.DrawString("PARCIAL", letra, Brushes.Black, 129, 518);
          
          double total = 0;
          int contador = 0;
          foreach (DataRow r in oset.Tables[0].Rows)
          {
            if (contador > 0)
            {
              cant_cartones_y += salto_y;
              detalle_y += salto_y;
              precio_carton_y += salto_y;
              exentas_y += salto_y;
              minimo_y += salto_y;
              maximo_y += salto_y;
            }
            fact = new DatosFactura();
            fact.cantidad_cartones = Convert.ToDouble(r["cantidad_cartones"]);
            fact.detalle = r["detalle"].ToString();
            fact.precio_unit_cartones = Convert.ToDouble(r["precio_unit_cartones"]);
            total = total + fact.total_pagar;
    
            e.Graphics.DrawString(fact.cantidad_cartones.ToString(), letra, Brushes.Black, cant_cartones_x, cant_cartones_y);
            e.Graphics.DrawString(fact.detalle, letra, Brushes.Black, detalle_x, detalle_y);
            e.Graphics.DrawString(fact.precio_unit_cartones.ToString(), letra, Brushes.Black, precio_carton_x, precio_carton_y);
            e.Graphics.DrawString("Ex.", letra, Brushes.Black, exentas_x, exentas_y);
            e.Graphics.DrawString("5%", letra, Brushes.Black, minimo_x, minimo_y);
            e.Graphics.DrawString("10%", letra, Brushes.Black, maximo_x, maximo_y);
            contador++;
          }
          e.Graphics.DrawString(total.ToString(), letra, Brushes.Black, 129, 548);
    
        }

    Algo que se ve en el código es que agrego un salto de línea con una suma de pixeles a la línea actual (con la variable salto_y) cosa que estoy seguro que no es algo bien hecho  y quisiera saber cómo realmente se hace esto.

    He buscado mucho cómo pasar códigos de escape desde c# a la impresora, pero no he encontrado ningún ejemplo liso y llano que me diga como hacerlo, así como el imprimir 2 veces lo mismo (ya que es una factura de dos vías).

     

    Espero me puedan ayudar, muchas gracias de antemano!

    Thursday, June 03, 2010 4:05 PM

Answers

  • Si estás utilizando la clase RawPrinterHelper, podrías hacer lo siguiente, yo extendí esa clase para poder posicionar textos en determinadas coordenadas, lo primero sería extender la clase con éstos métodos :

        public static bool SendArraylistToPrinter(string szPrinterName, ArrayList szArray)
        {
          for (int x = 0; x < szArray.Count; x++)
          {
            SendStringToPrinter(szPrinterName, szArray[x].ToString()+"\n");        
          }
          return true;
        }
    
        /// <summary>
        /// Este metodo debería tomar una tabla y convertirla en un arreglo de strings que viajarán hacia la impresora!.
        /// El reto de este método es tomar varios campos que van en una sola fila y acomodarlos en su respectiva posición.
        /// Tampoco debería olvidarse de adicionar las filas vacías en donde hayan espacios
        /// </summary>
        /// <param name="szPrinterName">El nombre de la Impresora</param>
        /// <param name="dtTable">Esta tabla debe tener los siguientes campos, x, y, texto</param>
        /// <returns></returns>
        public static bool SendDataTableToPrinter(string szPrinterName, DataTable dtTabla)
        {
          ArrayList alPrint = new ArrayList();
          int yoffset=0, xoffset=0;
          string cadena="";
          string linea="";
          DataView dv = dtTabla.DefaultView;
          dv.Sort = "yoffset,xoffset";
          foreach (DataRow r in dv.Table.Rows)
          {
            if (yoffset == 0)
            {
              yoffset = Convert.ToInt32(r["yoffset"]);
              for (int x = 0; x < yoffset-1; x++)
                alPrint.Add(" ");
            }
    
            if (yoffset>0 && yoffset != Convert.ToInt32(r["yoffset"]))
            {
              alPrint.Add(linea);          
              linea = "";
              for (int x = yoffset; x < Convert.ToInt32(r["yoffset"]) - 1; x++)
                alPrint.Add(" ");
              
              yoffset = Convert.ToInt32(r["yoffset"]);        
            }
    
            xoffset = Convert.ToInt32(r["xoffset"]);
            cadena = r["cadena"].ToString().Trim();
    
            linea += cadena.PadLeft(cadena.Length + ( xoffset - linea.Length ), ' ');
    
          }
    
          SendArraylistToPrinter(szPrinterName, alPrint);
          return true;
        }
    
        public static DataTable IniciaTabla()
        {
          DataTable dt = new DataTable();
          dt.Columns.Add("yoffset", System.Type.GetType("System.Int32"));
          dt.Columns.Add("xoffset", System.Type.GetType("System.Int32"));
          dt.Columns.Add("cadena", System.Type.GetType("System.String"));
          return dt;
        }

    Una vez que tienes eso simplemente tienes que llenar el datatable con los datos a imprimir, por ejemplo :

     

        private bool ImprimeGuia()
        {
          DataTable dt = RawPrinterHelper.IniciaTabla();
          DataRow r;
    
          r = dt.NewRow();
          r["yoffset"] = 4;
          r["xoffset"] = 5;
          r["cadena"] = txtDestinatario.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 4;
          r["xoffset"] = 55;
          r["cadena"] = txtTeleDestinatario.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 6;
          r["xoffset"] = 5;
          r["cadena"] = txtDireDestinatario.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 7;
          r["xoffset"] = 115;
          r["cadena"] = txtPeso.Text + " Kgs";
          dt.Rows.Add(r); 
          
          r = dt.NewRow();
          r["yoffset"] = 8;
          r["xoffset"] = 5;
          r["cadena"] = txtRemitente.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 8;
          r["xoffset"] = 55;
          r["cadena"] = txtTeleRemite.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 9;
          r["xoffset"] = 115;
          r["cadena"] = txtValorFlete.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 10;
          r["xoffset"] = 5;
          r["cadena"] = txtDireRemite.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 14;
          r["xoffset"] = 70;
          r["cadena"] = txtNumGuia.Text;
          dt.Rows.Add(r);
          
          r = dt.NewRow();
          r["yoffset"] = 15;
          r["xoffset"] = 6;
          r["cadena"] = "*";
          dt.Rows.Add(r);
    
          // Allow the user to select a printer.
          PrintDialog pd = new PrintDialog();
          pd.PrinterSettings = new PrinterSettings();
          if (DialogResult.OK == pd.ShowDialog(this))
          {
            // Send a printer-specific to the printer.
            RawPrinterHelper.SendDataTableToPrinter(pd.PrinterSettings.PrinterName, dt);
          }
    
          return true;
        }

    Como verás incluso puedes enviar varias string en una misma línea mientras no se superpongan.

    Saludos,


    Mauricio Atanache G. - MCP
    Bogotá - Colombia
    "Bienaventurados los Pesimistas. Por que hacen BACKUPS."
    Thursday, June 10, 2010 3:40 AM
  • En posiciónes del caracter (XOffset) y en retornos de carro (YOffset) al estilo antiguo.

     

    Saludos,

     


    Mauricio Atanache G. - MCP
    Bogotá - Colombia
    "Bienaventurados los Pesimistas. Por que hacen BACKUPS."
    Friday, June 11, 2010 5:43 AM

All replies

  • Hola!

    Bueno, una forma alternativa de hacerlo sería usando Crystal Reports, con el diseñas gráficamente el informe o factura y despues en tiempo de ejecución solo le pasas los datos que quieres imprimir y el solo imprime todo. lo bueno es que ademas puedes pedir que te devuelva el informe como una hoja de excel, como un pdf o como un documento de word, por lo que añades funcionalidades extra de forma automática. Puedes encontrar mucha información aquí

    Supongo que la LX-300+ al igual que la 200, será de papel continuo y el diseño de la factura lo tendrás preimpreso en el papel, por lo que realmente tienes que dejar correr el papel entre una hoja y otra, por lo que no veo incorrecto el salto de pixeles que haces, no creo que haya muchas más opciones.

    Para volver a imprimir lo mismo crea una variable que contenga el numero de páginas que quieres imprimir y otra variable que contenga el numero de páginas que ya has impreso, crealas fuera del metodo printDocument1_PrintPage, de esta forma lo que harías en la ultima línea de printDocument1_PrintPage sumarias uno a la variable que controla las páginas impresas y despues compruebas que la variable de páginas impresas sea menor que la variable de páginas a imprimir, si es así estableces la propiedad HasMorePages de la variable e a True, si no es así, la estableces a falso, Algo así:

      int PaginasAImprimir = 2;
      int PaginasImpresas = 0;
      private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
      {
        //Todo tu código aquí.
    
        PaginasImpresas += 1;
        if (PaginasImpresas == PaginasAImprimir)
          {
            e.HasMorePages = False;
          }
        else
          {
            e.HasMorePages = True;
          }
    
      }
    
    Espero que te sirva, un gran saludo!
    MCTS .NET Framework 3.5 Windows Forms Application Development
    MCTS .NET Framework 3.5 Windows Presentation Foundation
    Visita mi Blog
    Sigueme en Twitter
    Thursday, June 03, 2010 7:23 PM
    Moderator
  • Encuentro que en las impresoras de matriz de punto es mejor imprimir mandado comandos directos a la impresora que dibujando con la clase Graphics.

    Un ejemplo.

    http://support.microsoft.com/kb/322090/es


    Enterprise Library
    Friday, June 04, 2010 5:04 AM
  • Encuentro que en las impresoras de matriz de punto es mejor imprimir mandado comandos directos a la impresora que dibujando con la clase Graphics.

    Un ejemplo.

    http://support.microsoft.com/kb/322090/es


    Enterprise Library

    Hola Heraclito, 

    Sobre lo que me pasaste ya lo he visto, pero el tema es que primero que todo yo no necesito imprimir un simple "Hello, this is a test", ya que lo que necesito es un poco mas complejo, y ese ejemplo no me dice prácticamente nada sobre lo que quiero, ya que ahí solamente pasan texto o un archivo, pero cómo pasar los comandos de escape, y alguna otra cosa, no lo dice o al menos yo no lo entiendo, no se tu, pero si me puedes dar una mejor explicación sobre ese ejemplo, te lo agradecería :D

    Saludos y gracias por responder!

    Friday, June 04, 2010 12:17 PM
  • Hola!

    Bueno, una forma alternativa de hacerlo sería usando Crystal Reports, con el diseñas gráficamente el informe o factura y despues en tiempo de ejecución solo le pasas los datos que quieres imprimir y el solo imprime todo. lo bueno es que ademas puedes pedir que te devuelva el informe como una hoja de excel, como un pdf o como un documento de word, por lo que añades funcionalidades extra de forma automática. Puedes encontrar mucha información aquí

    Supongo que la LX-300+ al igual que la 200, será de papel continuo y el diseño de la factura lo tendrás preimpreso en el papel, por lo que realmente tienes que dejar correr el papel entre una hoja y otra, por lo que no veo incorrecto el salto de pixeles que haces, no creo que haya muchas más opciones.

    Para volver a imprimir lo mismo crea una variable que contenga el numero de páginas que quieres imprimir y otra variable que contenga el numero de páginas que ya has impreso, crealas fuera del metodo printDocument1_PrintPage, de esta forma lo que harías en la ultima línea de printDocument1_PrintPage sumarias uno a la variable que controla las páginas impresas y despues compruebas que la variable de páginas impresas sea menor que la variable de páginas a imprimir, si es así estableces la propiedad HasMorePages de la variable e a True, si no es así, la estableces a falso, Algo así:

     int PaginasAImprimir = 2;
     int PaginasImpresas = 0;
     private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
     {
      //Todo tu código aquí.
    
      PaginasImpresas += 1;
      if (PaginasImpresas == PaginasAImprimir)
       {
        e.HasMorePages = False;
       }
      else
       {
        e.HasMorePages = True;
       }
    
     }
    
    
    Espero que te sirva, un gran saludo!
    MCTS .NET Framework 3.5 Windows Forms Application Development
    MCTS .NET Framework 3.5 Windows Presentation Foundation
    Visita mi Blog
    Sigueme en Twitter

    Muchas gracias por responder Josue!, voy a ver si puedo hacer eso que me comentas, aunque no se si voy a implementar lo de Crystal Reports ya que no he escuchado buenos comentarios de éstos cuando se utilizan para imprimir (dicen que es lento), aunque si los implemento, me gustaría saber si me puedes pasar un ejemplo sobre como aplicarlos contra elementos de una base de datos.

    Muchas gracias!

    Friday, June 04, 2010 12:20 PM
  • Seguiste el ejemplo?
    Si logras que la impresora efectivamente imprima "Hello, this is a test"... el resto es muy facil.

    Cada impresora tiene un set de comandos representados por caracteres ascii.
    Hay un caracter ascii para inicializar el trabajo, otro para salto de linea, otro para salto de pagina, otro para terminar el trabajo, otro para definir el tamaño de letra, etc.
    En el manual de tu impresora deben estar estos caracteres.

    Entonces, por ejemplo si quieres que la impresora imprima  (notar salto de linea):
    "Hello,
    this is a test"
    Debes concatenar con los caracteres para salto de linea.

    Por ejemplo  "Hello" + Chr(13) + Chr(10) + "this is a test"
    Suponiendo que en tu impresora caracter 13 y 10 simbolizan el salto de linea, como sucede en la mia.

    Puede definir una pequeña clase que te sirva para construir el string con mas facilidad. Las funciones pueden agregar los caracteres necesarios para terminar linea, inicializar el trabajo, finalizar el trabajo, etc.
    ConstructorTextoImprimir miClase = new ConstructorTextoImprimir();
    miClase.Inicializar()
    miClase.AgregarLinea("Cliente: ACME INC.");
    miClase.AgregarLinea("Telefono: (065)4546444                               Fecha: 21-06-2010");
    miClase.Finalizar()

    Una vez que el string esta terminado, debes convertirlo a un array de bytes usando la codificacion que tu impresora requiera, puede ser ascii o en mi caso es Unicode.
    string textoImprimir = miClase.Texto;
    Byte[] unicodeBytes = System.Text.Encoding.Unicode.GetBytes(textoImprimir);

    Y le pasas este array de bytes la funcion SendBytesToPrinter.


    Enterprise Library
    Friday, June 04, 2010 3:58 PM
  • Seguiste el ejemplo?
    Si logras que la impresora efectivamente imprima "Hello, this is a test"... el resto es muy facil.

    Cada impresora tiene un set de comandos representados por caracteres ascii.
    Hay un caracter ascii para inicializar el trabajo, otro para salto de linea, otro para salto de pagina, otro para terminar el trabajo, otro para definir el tamaño de letra, etc.
    En el manual de tu impresora deben estar estos caracteres.

    Entonces, por ejemplo si quieres que la impresora imprima  (notar salto de linea):
    "Hello,
    this is a test"
    Debes concatenar con los caracteres para salto de linea.

    Por ejemplo  "Hello" + Chr(13) + Chr(10) + "this is a test"
    Suponiendo que en tu impresora caracter 13 y 10 simbolizan el salto de linea, como sucede en la mia.

    Puede definir una pequeña clase que te sirva para construir el string con mas facilidad. Las funciones pueden agregar los caracteres necesarios para terminar linea, inicializar el trabajo, finalizar el trabajo, etc.
    ConstructorTextoImprimir miClase = new ConstructorTextoImprimir();
    miClase.Inicializar()
    miClase.AgregarLinea("Cliente: ACME INC.");
    miClase.AgregarLinea("Telefono: (065)4546444                               Fecha: 21-06-2010");
    miClase.Finalizar()

    Una vez que el string esta terminado, debes convertirlo a un array de bytes usando la codificacion que tu impresora requiera, puede ser ascii o en mi caso es Unicode.
    string textoImprimir = miClase.Texto;
    Byte[] unicodeBytes = System.Text.Encoding.Unicode.GetBytes(textoImprimir);

    Y le pasas este array de bytes la funcion SendBytesToPrinter.


    Enterprise Library

    Excelente explición Heraclito!!

    Entendí todo lo que me dijiste, ahora, la única duda que tengo es la siguiente:
    Tengo un pdf de epson el cual se titula "Comandos ESC/POS ordenados por temas", es eso lo que necesito? si es eso, éste pdf tiene tablas de la siguiente forma:

    ASCII | Dec. | Hex. | Descripción

    ESC @ | 64   | 40    | Inicializar la impresora

    CR      | 13   | 0D    | Retorno de carro.

     

    Con esto, cómo lo utilizo? Debo formar la palabra "ESC @" por ejemplo para que me quede "Chr(x) + Chr(y)...."?

    Es algo que no entiendo mucho y espero me puedas esplicar, muchas gracias!

    Friday, June 04, 2010 6:12 PM
  • Se pueden pasar estos códigos utilizando "Graphics.DrawString"? Sea posible o no, he intentado pasar datos por ejemplo:

     

    En el manual dice:

     

    Format

    ASCII ESC |  J  | n

    Hex     1B  | 4A | n

    Decimal 27 | 74 | n

    Parameter range:

    0 <= n <= 255

    Esto me estaría diciendo que haga un texto del tipo: 

    string escAdvPrintPosVert = Convert.ToChar(27).ToString() + Convert.ToChar(74).ToString + 4; 

    Pero ésto no me hace un "Advance print position vertically", además de que me imprime el "4" del final del string. Qué estoy haciendo mal?

    Y otra cosa, este string, debe estar separado por un espacio de otro string de escape u otro string que vaya impreso? es decir, algo así:

    string salida = escAdvPrintPosVert + " " + "Hola mundo!";
    
    string salida2= escAdvPrintPosVert + " " + escOtroEscape + " " + "Hola mundo 2!";

    Además... cuándo van éstos strings que indican la posición u orientación de los textos? al principio? al final? tienen algún caracter de "corte"? ya que por ejemplo para caracteres de escape para las negritas por ejemplo, hay un negritaOn y negritaOff que se pone entre el texto a colocar en negrita, pero éstos? como se colocan?

     

     

    Espero me puedan ayudar, y gracias de antemano!

     

     

    Wednesday, June 09, 2010 12:40 PM
  • Se pueden pasar estos códigos utilizando "Graphics.DrawString"? Sea posible o no, he intentado pasar datos por ejemplo:

    No, no puedes usar Graphics.DrawString para pasar comandos directos a la impresora, esa clase es para dibujar graficos raster.
    Para pasar comandos directos a la impresora debes usar la tecnica del ejemplo, en mi opinion es mejor pues la impresion es mas clara, rapida y gasta menos tinta en las impresoras de matriz.

     

    En el manual dice:

     

    Format

    ASCII ESC |  J  | n

    Hex     1B  | 4A | n

    Decimal 27 | 74 | n

    Parameter range:

    0 <= n <= 255

    Esto me estaría diciendo que haga un texto del tipo: 

     

    string escAdvPrintPosVert = Convert.ToChar(27).ToString() + Convert.ToChar(74).ToString + 4; 
    
    

    Exactamente debes ir concatenando los caracteres, si requiere caracter de escape se pone ese primero, tal como lo hiciste.

     

    Pero ésto no me hace un "Advance print position vertically", además de que me imprime el "4" del final del string. Qué estoy haciendo mal?

    Y otra cosa, este string, debe estar separado por un espacio de otro string de escape u otro string que vaya impreso? es decir, algo así:

     

    string salida = escAdvPrintPosVert + " " + "Hola mundo!";
    
    
    
    string salida2= escAdvPrintPosVert + " " + escOtroEscape + " " + "Hola mundo 2!";
    
    

     

    Además... cuándo van éstos strings que indican la posición u orientación de los textos? al principio? al final? tienen algún caracter de "corte"? ya que por ejemplo para caracteres de escape para las negritas por ejemplo, hay un negritaOn y negritaOff que se pone entre el texto a colocar en negrita, pero éstos? como se colocan?

     

     

    Espero me puedan ayudar, y gracias de antemano!

     

     


    Ese comando con parametro para avanzar multiples lineas tampoco me funciono. No se porque. Entonces opte por usar saltos de linea.
    No creo que necesites separar los comando con espacio, al menos que el manual diga.

    Como la pagina tiene un ancho y alto fijo en numero de caracteres, y los caracteres tienen un ancho y alto standard, tengo una funcion que si quiero alinear a la derecha concatena los espacios necesarios a la izquierda. Tambien puedes hacer una funcion que te concatenes los espacios necesarios para centrar un texto.
    "                                                                                        Por ejemplo este texto esta a la derecha."
    "                                                 Este texto esta centrado.                                                               "
    Para mover hacia abajo uso los saltos de linea que sean necesarios. Es algo artesanal pero funciona, el punto es que hagas una clase que te ayude a formar el string de impresion para aminorar la carga, el string final se puede volver complejo con tanto caracter concatenado. Por ejemplo:

    myClase.AgregarLineaCentrado("Este texto esta centrado.");  //Agrega caracteres de espacio, texto y saldo te linea
    myClase.SaltarLinea(4);  //Esta funcion agrega 4 veces Chr(13) + Chr(10)


    Enterprise Library
    Wednesday, June 09, 2010 2:43 PM
  • Yo he usado esta clase y me ha ido muy bien, espero te sirva,

    http://support.microsoft.com/kb/322091/es

     

    Cordial saludo,


    Mauricio Atanache G. - MCP
    Bogotá - Colombia
    "Bienaventurados los Pesimistas. Por que hacen BACKUPS."
    Wednesday, June 09, 2010 7:05 PM
  • Se pueden pasar estos códigos utilizando "Graphics.DrawString"? Sea posible o no, he intentado pasar datos por ejemplo:

    No, no puedes usar Graphics.DrawString para pasar comandos directos a la impresora, esa clase es para dibujar graficos raster.
    Para pasar comandos directos a la impresora debes usar la tecnica del ejemplo, en mi opinion es mejor pues la impresion es mas clara, rapida y gasta menos tinta en las impresoras de matriz.

     

    En el manual dice:

     

    Format

    ASCII ESC |  J  | n

    Hex     1B  | 4A | n

    Decimal 27 | 74 | n

    Parameter range:

    0 <= n <= 255

    Esto me estaría diciendo que haga un texto del tipo: 

     

    string escAdvPrintPosVert = Convert.ToChar(27).ToString() + Convert.ToChar(74).ToString + 4; 
    
    

    Exactamente debes ir concatenando los caracteres, si requiere caracter de escape se pone ese primero, tal como lo hiciste.

     

    Pero ésto no me hace un "Advance print position vertically", además de que me imprime el "4" del final del string. Qué estoy haciendo mal?

    Y otra cosa, este string, debe estar separado por un espacio de otro string de escape u otro string que vaya impreso? es decir, algo así:

     

    string salida = escAdvPrintPosVert + " " + "Hola mundo!";
    
    
    
    string salida2= escAdvPrintPosVert + " " + escOtroEscape + " " + "Hola mundo 2!";
    
    

     

    Además... cuándo van éstos strings que indican la posición u orientación de los textos? al principio? al final? tienen algún caracter de "corte"? ya que por ejemplo para caracteres de escape para las negritas por ejemplo, hay un negritaOn y negritaOff que se pone entre el texto a colocar en negrita, pero éstos? como se colocan?

     

     

    Espero me puedan ayudar, y gracias de antemano!

     

     


    Ese comando con parametro para avanzar multiples lineas tampoco me funciono. No se porque. Entonces opte por usar saltos de linea.
    No creo que necesites separar los comando con espacio, al menos que el manual diga.

    Como la pagina tiene un ancho y alto fijo en numero de caracteres, y los caracteres tienen un ancho y alto standard, tengo una funcion que si quiero alinear a la derecha concatena los espacios necesarios a la izquierda. Tambien puedes hacer una funcion que te concatenes los espacios necesarios para centrar un texto.
    "                                                                                        Por ejemplo este texto esta a la derecha."
    "                                                 Este texto esta centrado.                                                               "
    Para mover hacia abajo uso los saltos de linea que sean necesarios. Es algo artesanal pero funciona, el punto es que hagas una clase que te ayude a formar el string de impresion para aminorar la carga, el string final se puede volver complejo con tanto caracter concatenado. Por ejemplo:

    myClase.AgregarLineaCentrado("Este texto esta centrado.");  //Agrega caracteres de espacio, texto y saldo te linea
    myClase.SaltarLinea(4);  //Esta funcion agrega 4 veces Chr(13) + Chr(10)


    Enterprise Library

    Gracias por responder! 

    He entendido lo que me dices, pero sigo  sin entender si dos secuencias de escape deben ir unidas o separadas por un espacio, y otra cosa...

    En la factura que debo imprimir tengo por ejemplo:

    Nombre: XXXXXXXXX Direccion: XXXXXXX

    El campo nombre, lo puedo llenar bien, posicionando con espacios y saltos de línea, pero cómo ubico la dirección que debo llenar? es decir, tengo que calcular el largo de el nombre para poder agregar la cantidad de espacios necesarios para llegar a la ubicación de la dirección?

    Me podrías ayudar con un código de ejemplo?

    También, si no te es mucha molestia, me gustaría ver esa función que me muestras "AgregarLineaCentrado".

     

    Muchas gracias nuevamente!

    Wednesday, June 09, 2010 7:48 PM
  • Si estás utilizando la clase RawPrinterHelper, podrías hacer lo siguiente, yo extendí esa clase para poder posicionar textos en determinadas coordenadas, lo primero sería extender la clase con éstos métodos :

        public static bool SendArraylistToPrinter(string szPrinterName, ArrayList szArray)
        {
          for (int x = 0; x < szArray.Count; x++)
          {
            SendStringToPrinter(szPrinterName, szArray[x].ToString()+"\n");        
          }
          return true;
        }
    
        /// <summary>
        /// Este metodo debería tomar una tabla y convertirla en un arreglo de strings que viajarán hacia la impresora!.
        /// El reto de este método es tomar varios campos que van en una sola fila y acomodarlos en su respectiva posición.
        /// Tampoco debería olvidarse de adicionar las filas vacías en donde hayan espacios
        /// </summary>
        /// <param name="szPrinterName">El nombre de la Impresora</param>
        /// <param name="dtTable">Esta tabla debe tener los siguientes campos, x, y, texto</param>
        /// <returns></returns>
        public static bool SendDataTableToPrinter(string szPrinterName, DataTable dtTabla)
        {
          ArrayList alPrint = new ArrayList();
          int yoffset=0, xoffset=0;
          string cadena="";
          string linea="";
          DataView dv = dtTabla.DefaultView;
          dv.Sort = "yoffset,xoffset";
          foreach (DataRow r in dv.Table.Rows)
          {
            if (yoffset == 0)
            {
              yoffset = Convert.ToInt32(r["yoffset"]);
              for (int x = 0; x < yoffset-1; x++)
                alPrint.Add(" ");
            }
    
            if (yoffset>0 && yoffset != Convert.ToInt32(r["yoffset"]))
            {
              alPrint.Add(linea);          
              linea = "";
              for (int x = yoffset; x < Convert.ToInt32(r["yoffset"]) - 1; x++)
                alPrint.Add(" ");
              
              yoffset = Convert.ToInt32(r["yoffset"]);        
            }
    
            xoffset = Convert.ToInt32(r["xoffset"]);
            cadena = r["cadena"].ToString().Trim();
    
            linea += cadena.PadLeft(cadena.Length + ( xoffset - linea.Length ), ' ');
    
          }
    
          SendArraylistToPrinter(szPrinterName, alPrint);
          return true;
        }
    
        public static DataTable IniciaTabla()
        {
          DataTable dt = new DataTable();
          dt.Columns.Add("yoffset", System.Type.GetType("System.Int32"));
          dt.Columns.Add("xoffset", System.Type.GetType("System.Int32"));
          dt.Columns.Add("cadena", System.Type.GetType("System.String"));
          return dt;
        }

    Una vez que tienes eso simplemente tienes que llenar el datatable con los datos a imprimir, por ejemplo :

     

        private bool ImprimeGuia()
        {
          DataTable dt = RawPrinterHelper.IniciaTabla();
          DataRow r;
    
          r = dt.NewRow();
          r["yoffset"] = 4;
          r["xoffset"] = 5;
          r["cadena"] = txtDestinatario.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 4;
          r["xoffset"] = 55;
          r["cadena"] = txtTeleDestinatario.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 6;
          r["xoffset"] = 5;
          r["cadena"] = txtDireDestinatario.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 7;
          r["xoffset"] = 115;
          r["cadena"] = txtPeso.Text + " Kgs";
          dt.Rows.Add(r); 
          
          r = dt.NewRow();
          r["yoffset"] = 8;
          r["xoffset"] = 5;
          r["cadena"] = txtRemitente.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 8;
          r["xoffset"] = 55;
          r["cadena"] = txtTeleRemite.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 9;
          r["xoffset"] = 115;
          r["cadena"] = txtValorFlete.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 10;
          r["xoffset"] = 5;
          r["cadena"] = txtDireRemite.Text;
          dt.Rows.Add(r);
    
          r = dt.NewRow();
          r["yoffset"] = 14;
          r["xoffset"] = 70;
          r["cadena"] = txtNumGuia.Text;
          dt.Rows.Add(r);
          
          r = dt.NewRow();
          r["yoffset"] = 15;
          r["xoffset"] = 6;
          r["cadena"] = "*";
          dt.Rows.Add(r);
    
          // Allow the user to select a printer.
          PrintDialog pd = new PrintDialog();
          pd.PrinterSettings = new PrinterSettings();
          if (DialogResult.OK == pd.ShowDialog(this))
          {
            // Send a printer-specific to the printer.
            RawPrinterHelper.SendDataTableToPrinter(pd.PrinterSettings.PrinterName, dt);
          }
    
          return true;
        }

    Como verás incluso puedes enviar varias string en una misma línea mientras no se superpongan.

    Saludos,


    Mauricio Atanache G. - MCP
    Bogotá - Colombia
    "Bienaventurados los Pesimistas. Por que hacen BACKUPS."
    Thursday, June 10, 2010 3:40 AM
  • Si estás utilizando la clase RawPrinterHelper, podrías hacer lo siguiente, yo extendí esa clase para poder posicionar textos en determinadas coordenadas, lo primero sería extender la clase con éstos métodos :

      public static bool SendArraylistToPrinter(string szPrinterName, ArrayList szArray)
      {
       for (int x = 0; x < szArray.Count; x++)
       {
        SendStringToPrinter(szPrinterName, szArray[x].ToString()+"\n");    
       }
       return true;
      }
    
      /// <summary>
      /// Este metodo debería tomar una tabla y convertirla en un arreglo de strings que viajarán hacia la impresora!.
      /// El reto de este método es tomar varios campos que van en una sola fila y acomodarlos en su respectiva posición.
      /// Tampoco debería olvidarse de adicionar las filas vacías en donde hayan espacios
      /// </summary>
      /// <param name="szPrinterName">El nombre de la Impresora</param>
      /// <param name="dtTable">Esta tabla debe tener los siguientes campos, x, y, texto</param>
      /// <returns></returns>
      public static bool SendDataTableToPrinter(string szPrinterName, DataTable dtTabla)
      {
       ArrayList alPrint = new ArrayList();
       int yoffset=0, xoffset=0;
       string cadena="";
       string linea="";
       DataView dv = dtTabla.DefaultView;
       dv.Sort = "yoffset,xoffset";
       foreach (DataRow r in dv.Table.Rows)
       {
        if (yoffset == 0)
        {
         yoffset = Convert.ToInt32(r["yoffset"]);
         for (int x = 0; x < yoffset-1; x++)
          alPrint.Add(" ");
        }
    
        if (yoffset>0 && yoffset != Convert.ToInt32(r["yoffset"]))
        {
         alPrint.Add(linea);     
         linea = "";
         for (int x = yoffset; x < Convert.ToInt32(r["yoffset"]) - 1; x++)
          alPrint.Add(" ");
         
         yoffset = Convert.ToInt32(r["yoffset"]);    
        }
    
        xoffset = Convert.ToInt32(r["xoffset"]);
        cadena = r["cadena"].ToString().Trim();
    
        linea += cadena.PadLeft(cadena.Length + ( xoffset - linea.Length ), ' ');
    
       }
    
       SendArraylistToPrinter(szPrinterName, alPrint);
       return true;
      }
    
      public static DataTable IniciaTabla()
      {
       DataTable dt = new DataTable();
       dt.Columns.Add("yoffset", System.Type.GetType("System.Int32"));
       dt.Columns.Add("xoffset", System.Type.GetType("System.Int32"));
       dt.Columns.Add("cadena", System.Type.GetType("System.String"));
       return dt;
      }
    

    Una vez que tienes eso simplemente tienes que llenar el datatable con los datos a imprimir, por ejemplo :

     

      private bool ImprimeGuia()
      {
       DataTable dt = RawPrinterHelper.IniciaTabla();
       DataRow r;
    
       r = dt.NewRow();
       r["yoffset"] = 4;
       r["xoffset"] = 5;
       r["cadena"] = txtDestinatario.Text;
       dt.Rows.Add(r);
    
       r = dt.NewRow();
       r["yoffset"] = 4;
       r["xoffset"] = 55;
       r["cadena"] = txtTeleDestinatario.Text;
       dt.Rows.Add(r);
    
       r = dt.NewRow();
       r["yoffset"] = 6;
       r["xoffset"] = 5;
       r["cadena"] = txtDireDestinatario.Text;
       dt.Rows.Add(r);
    
       r = dt.NewRow();
       r["yoffset"] = 7;
       r["xoffset"] = 115;
       r["cadena"] = txtPeso.Text + " Kgs";
       dt.Rows.Add(r); 
       
       r = dt.NewRow();
       r["yoffset"] = 8;
       r["xoffset"] = 5;
       r["cadena"] = txtRemitente.Text;
       dt.Rows.Add(r);
    
       r = dt.NewRow();
       r["yoffset"] = 8;
       r["xoffset"] = 55;
       r["cadena"] = txtTeleRemite.Text;
       dt.Rows.Add(r);
    
       r = dt.NewRow();
       r["yoffset"] = 9;
       r["xoffset"] = 115;
       r["cadena"] = txtValorFlete.Text;
       dt.Rows.Add(r);
    
       r = dt.NewRow();
       r["yoffset"] = 10;
       r["xoffset"] = 5;
       r["cadena"] = txtDireRemite.Text;
       dt.Rows.Add(r);
    
       r = dt.NewRow();
       r["yoffset"] = 14;
       r["xoffset"] = 70;
       r["cadena"] = txtNumGuia.Text;
       dt.Rows.Add(r);
       
       r = dt.NewRow();
       r["yoffset"] = 15;
       r["xoffset"] = 6;
       r["cadena"] = "*";
       dt.Rows.Add(r);
    
       // Allow the user to select a printer.
       PrintDialog pd = new PrintDialog();
       pd.PrinterSettings = new PrinterSettings();
       if (DialogResult.OK == pd.ShowDialog(this))
       {
        // Send a printer-specific to the printer.
        RawPrinterHelper.SendDataTableToPrinter(pd.PrinterSettings.PrinterName, dt);
       }
    
       return true;
      }
    

    Como verás incluso puedes enviar varias string en una misma línea mientras no se superpongan.

    Saludos,


    Mauricio Atanache G. - MCP
    Bogotá - Colombia
    "Bienaventurados los Pesimistas. Por que hacen BACKUPS."
    Hola, excelente propuesta me diste! la voy a comenzar a aplicar, pero te tengo una última pregunta. En qué valores están los xoffset e yoffset? cómo los puedo calcular? Gracias!!
    Thursday, June 10, 2010 1:05 PM
  • En posiciónes del caracter (XOffset) y en retornos de carro (YOffset) al estilo antiguo.

     

    Saludos,

     


    Mauricio Atanache G. - MCP
    Bogotá - Colombia
    "Bienaventurados los Pesimistas. Por que hacen BACKUPS."
    Friday, June 11, 2010 5:43 AM