Spanish Imprimir bluetooth desde varias activity

vecino

Well-Known Member
Licensed User
Longtime User
Hola, amigos, espero que estén todos bien de salud.
Iba a escribir esta pregunta en el foro "principal", pero tras haberla traducido al inglés (con el google translator y el deepl), creo que no se entendía bien, así que mejor me explico en español.
Tengo una aplicación típica de ventas que cuando se termina de hacer una factura/albarán/pedido/etc. pregunta si quiere imprimirla (siempre por bluetooth), y funciona bien.
Estoy usando el código de este otro hilo.
Ùltimamente le he añadido la funcionalidad de imprimir también recibos de cobros, y ahí empezó el problema, me explico:
El usuario selecciona "ventas", escoge el cliente, el programa le avisa de que debe dinero de otras ventas anteriores, entonces desde esa activity "ventas" se abre la activity "cobros", ahí se cobra y pregunta si quiere imprimir un recibo del cobro para entregar al cliente.
Una vez terminado el cobro, se cierra la activity "cobros" y regresa a la de "ventas", hace la factura/albarán/etc. y la imprime, bueno, lo intenta, porque ahí está el problema.
Si se abre "cobros" entonces se puede imprimir tantos recibos como se quiera.
Si se abre "ventas" entonces se puede imprimir tantos facturas/albaranes/etc. como se quiera.

El problema es cuando va de ventas a cobros, y de cobros a ventas. Se pierde la conexión con la impresora, si se intenta conectar salta una excepción, si la cierro antes salta excepción, si no la cierro para abrirla tampoco funciona, etc. etc. etc. muchos problemas que no sé "por dónde cogerlos" ("asir" para los argentinos :D).

He intentado muchas cosas, he declarado compartida las variables para todas las activity, luego las he puesto privadas para cada activity por separado, he creado conexiones "para todos", y luego para cada activity por separado, etc.

No sé si tenéis hecho algo similar, o sea, poder imprimir desde disstintas activity que se llaman unas a otras, imprimir una factura en "ventas", enlazar a "cobros" e imprimir un recibo, volver a "ventas" e imprimir un albarán, etc. etc. etc.

Gracias, y perdón por el mogollón que he soltado :D

El código, básicamente es el del hilo que he indicado antes, lo pego aquí:
B4X:
    #Region Module Attributes
    #FullScreen: False
    #IncludeTitle: True
    #ApplicationLabel: Bluetooth POS Printing
    #VersionCode: 1
    #VersionName:
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
#End Region

Sub Process_Globals
    Dim PrintBuffer As String

    Dim BtAdmin As BluetoothAdmin
    Dim BTConnection As Serial
    Dim Printer As TextWriter
End Sub

Sub Globals
   
End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        BtAdmin.Initialize("BlueTooth")
        BTConnection.Initialize("Printer")
        Dim PairedDevices As Map
        PairedDevices = BTConnection.GetPairedDevices
        Dim l As List
        Dim DeviceName, MacAddress As String
        l.Initialize
        For i = 0 To PairedDevices.Size - 1 'Check all devices
            l.Add(PairedDevices.GetKeyAt(i))
            DeviceName=PairedDevices.Getkeyat(i)
            MacAddress=PairedDevices.GetValueAt(i)
            Log(DeviceName & " -> " & MacAddress)
            If DeviceName.Contains("Thermal") Then 'Insert the BT-Name of the printer or use the MAC address
                Exit
            End If
        Next
        BTConnection.Connect(MacAddress)
    End If
End Sub

Sub Activity_Resume
   
End Sub

Sub Activity_Pause
   
End Sub

Sub Printer_Connected (Success As Boolean)
    If Success Then
        Printer.Initialize2(BTConnection.OutputStream,"windows-1252") 'important to print f.e. German/French chars
        PrintBuffer=Chr(27)&"t"&Chr(16)&"Hello öäüßéèê" 'Set codepage 1252 
        Printer.WriteLine(PrintBuffer)
        Printer.Flush

        Msgbox("Printed!","")
        Printer.Close
        BTConnection.Disconnect 'disable this if you like
    Else
        Msgbox("No printer found...","Print error")
    End If
End Sub
 

José J. Aguilar

Expert
Licensed User
Hola vecino¡¡

Sin tener demasiada idea de imprimir con bluetooth, etc... y sin querer entrar en algo que ya imaginarás pero que supongo que te supone demasiado trabajo ahora mismo, que es que cambies a B4XPages para así dejar de sufrir con el ciclo de vida de Android, creo que deberías implementar todo el tema de impresión en un servicio, ya que probablemente la conexión de la impresora se cerrará en algún Activity_Pause o algo así.

También te diría que probases (de esto no estoy nada seguro), a en vez de hacer "BTConnection.Connect(MacAddress)" en Activity_Create, hicieras algo así cuando vayas a imprimir:

B4X:
Sub btnImprimir_Click (Parametros As ....)

BTConnection.Connect(MacAddress)
Wait for Printer_Connected (Success As Boolean)
   If Success Then
        Printer.Initialize2(BTConnection.OutputStream,"windows-1252") 'important to print f.e. German/French chars
        PrintBuffer=Chr(27)&"t"&Chr(16)&"Hello öäüßéèê" 'Set codepage 1252 
        Printer.WriteLine(PrintBuffer)
        Printer.Flush

        Msgbox("Printed!","")
        Printer.Close
        BTConnection.Disconnect 'disable this if you like
    Else
        Msgbox("No printer found...","Print error")
    End If
End Sub

Quizás @scsjc pueda ayudarte con este tema (creo que su app tiene módulo para imprimir), aunque sé que está últimamente bastante liado.

saludos,
 

vecino

Well-Known Member
Licensed User
Longtime User
Gracias, José J., realmente estoy haciéndolo como dices, no en el "create" del ejemplo original que he puesto.
En el "pause" y en el "activate" eliminé también todo lo referente a la impresión, así que no sé si es que cuando se cambia entre activitys es que se pierda la conexión, o yo qué sé lo que hace.

Lo de cambiar a B4XPages este programa me temo que no vale la pena, sería muchísimo trabajo y tiempo, al menos con mis conocimientos actuales.
Este programa lleva ya más de 8 años instalado en un centenar de clientes y no le saco un rendimiento económico como para hacer una nueva versión, me limito a mantenerlo, añadir cosas que van pidiendo, arreglar otras, etc.

A ver si "scjc", o alguien, puede echarme una mano con algo que en teoría es muy simple, pero me lleva por la calle de la amargura últimamente y no sé qué solución darle.
Gracias de nuevo, siempre estás ahí ayudando a los demás :)
Saludos.
 

vecino

Well-Known Member
Licensed User
Longtime User
Por cierto, lo de implementar la impresión en un servicio, lo había pensado, pero no sé cómo hacerlo :confused:
 

José J. Aguilar

Expert
Licensed User
Por cierto, lo de implementar la impresión en un servicio, lo había pensado, pero no sé cómo hacerlo
Echa un ojo a este ejemplo,


en especial a lo que dice Erel
All the non-UI code is implemented in a class named BluetoothManager. It is initialized in Service_Create of the starter service.

It is always better to implement communication related code in a service or a class initialized from a service. This way the communication state is not affected by the activities more complicated state.

The activities call the class methods directly. Calling the activities subs is done with CallSub. Remember that CallSub doesn't do anything if the activity is paused.
 

vecino

Well-Known Member
Licensed User
Longtime User
¡¡¡Gracias!!!, parece que eso es lo que necesito.
A ver si puedo transformar ese "chat" en un "printer" :D
Saludos.
 

elsanto1970

Member
Licensed User
Longtime User
Hola Vecino : sin tener mucha experiencia en B4X , tengo funcionando una App de para impresión de etiquetas de góndolas con una impresora EPSON conectada por blt , y utilizo este modulo de clase (https://www.b4x.com/android/forum/threads/bluetooth-esc-pos-printer-class.106553/)que llamo de varias activity 's que tengo y funciona muy bien lo que hago es conectarme cada vez que entro y desconecto cuando salgo de la activity te paso la clase que uso , le agregue algunas funciones que no tenia por ej QRCode espero que te ayude a tu problema
Saludos

B4X:
Sub Process_Globals
    Dim EpsonPrinter As EscPosPrinter
End Sub
Sub Activity_Create(FirstTime As Boolean)
'*************************************************************************************
    '* Inicializo el driver de impresion
    '*************************************************************************************
'    If FirstTime Then
       
        EpsonPrinter.Initialize(Me, "EpsonPrinter")
       
'    End If
Sub Activity_Resume
    Drawer.LeftOpen = False
    If EpsonPrinter.IsBluetoothOn = False Then
        'Msgbox("El Bluetooth no esta activado", "")
        ToastMessageShow("El Bluetooth no esta activado", False)
    Else If EpsonPrinter.IsConnected = False Then
        EpsonPrinter.Connect
       
    End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    EpsonPrinter.DisConnect
End Sub

B4X:
'*****************************************************
'Imprime los articulos seleccionados de la tabla
'*****************************************************
Sub MandoImprimir(FilaId As Long)
   
    DateTime.DateFormat = "dd/MM/yyyy"
    Dim FechaActual As String  = "Fecha " & DateTime.Date(DateTime.Now) '& " " & "Hora " & DateTime.Time(DateTime.Now)
   
    Dim TablaSeleccionados       As Map = B4XTable1.GetRow(FilaId)
    Dim ArtCodigo      As String
    Dim ArtDescripcion As String
    Dim ArtPrecio      As Double
    Dim TipoBarra      As Int
    Dim ht             As Int = 40 ' Altura de la codigo de barras
   
    EpsonPrinter.CodePage = 0 ' change this number to determine the codepage, see the printer manual
    EpsonPrinter.CharacterFont = 1
    '*****************************************************
    'Busca en la tabl que imprimir
    '*****************************************************
    For i= 0 To TablaSeleccionados.Size -1
       

        ArtCodigo = TablaSeleccionados.GetValueAt(0)
        ArtDescripcion = TablaSeleccionados.GetValueAt(1)
        ArtPrecio = TablaSeleccionados.GetValueAt(2)

    Next
    'formateo el campo precio para pasarlo al label
    Dim formatter As B4XFormatter
    formatter.Initialize
    formatter.GetDefaultFormat.MaximumFractions = 2
    formatter.GetDefaultFormat.MinimumFractions = 2
    formatter.GetDefaultFormat.Prefix = "$ "
   

    '*****************************************************
    'DATOS A IMPRIMIR
    '*****************************************************
       
    '*****************************************************
    ' DESCRIPCION impresion
    '******************************************************
    EpsonPrinter.Justify = 0 'descric left
    EpsonPrinter.WriteString(Chr(27) & "!"  & Chr(10))'Selects double-height mode
   
    'Log(Len(ArtDescripcion))
    If Len(ArtDescripcion) < 32 Then
        EpsonPrinter.WriteString(Chr(27) & "!"  & Chr(10))'Selects double-height mode
    Else
        EpsonPrinter.WriteString(Chr(27) & "!"  & Chr(9))'Selects double-height mode
    End If
   
    EpsonPrinter.WriteString(ArtDescripcion & CRLF)
    EpsonPrinter.WriteString(Chr(27) & "!"  & Chr(0))
   
    '*****************************************************
    ' PRECIO impresion  optativo
    If Starter.setimprimeprecio = "1" Then
        'EpsonPrinter.WriteString(Chr(27) & "!"  & Chr(17))'Selects double-height mode
        EpsonPrinter.Justify = 1 'precio derecha
        EpsonPrinter.WriteString(Chr(27) & "!"  & Chr(120))'Selects double-height mode
        EpsonPrinter.WriteString(formatter.Format(ArtPrecio) & CRLF)
        EpsonPrinter.WriteString(Chr(27) & "!"  & Chr(0))
    End If

    '*****************************************************
    'Seteo codigo de barras
    '*****************************************************
    EpsonPrinter.BarCodeLeft = 0
    EpsonPrinter.Justify = 1
    EpsonPrinter.HRIposn = 2
    EpsonPrinter.HRIfont = 1
    EpsonPrinter.BarCodeHeight = ht
   
    '*****************************************************
    'PARA SABER EL TIPO DE CODIGO DE BARRAS PARA IMPRIMIR
    '*****************************************************
    TipoBarra = Len(ArtCodigo)
       
'    Log("ca"& TipoBarra)
    If TipoBarra < 6 Or TipoBarra = 6 Then
'        Log("6")
        EpsonPrinter.WriteBarCode("E" ,ArtCodigo.Trim) '  CODE39
    End If
    If TipoBarra = 7 Then
'        Log("7")
        EpsonPrinter.WriteBarCode("D" , ArtCodigo.Trim) 'EAN8 SIN VERIFICADOR
    End If
    If TipoBarra = 8 Then
'        Log("8")
        EpsonPrinter.WriteBarCode("D" , ArtCodigo.Trim) 'EAN8
    End If

    If TipoBarra = 12 Then
'        Log("12")
        EpsonPrinter.WriteBarCode("C" , ArtCodigo.Trim) 'EAN13 SIN VERIFICADOR
    End If
    If TipoBarra = 13 Then
'        Log("13")
        EpsonPrinter.WriteBarCode("C" , ArtCodigo.Trim) 'EAN13
    End If
    '*****************************************************
    ' imagen logo impresion  optativa
    '*****************************************************
    If Starter.setimprimelogo = "1" Then
        'Log("logo")
        EpsonPrinter.Justify = 0
        'Load an image to print and resize it to the maximum mage dimensions for the printer
        Dim bmp As Bitmap
        bmp.InitializeResize(Starter.setdireccionlogo, "", 80, 512, True) 'ignore
        ' Convert the RGB image to one with luminance values
        Dim myimage As AnImage = EpsonPrinter.ImageToBWIMage(bmp)
        ' Choose thresholding the image or dithering it to get a black and white bit image
        myimage = EpsonPrinter.DitherImage2D(myimage, 128)
        ' Send the black and white bit image to the printer
        myimage= EpsonPrinter.PackImage(myimage)
        'Printer1.WriteString(CRLF) ' nudge the printer to show the user something is happening
        EpsonPrinter.PrintImage(myimage)
    End If
    '*****************************************************
    ' FECHA impresion  optativa
    '*****************************************************
   
    If Starter.setimprimefecha = "1" Then
        EpsonPrinter.Justify = 2
        If Starter.setimprimelogo = "0" Then
            EpsonPrinter.WriteString(Chr(27) & "d" & Chr(1)) ' LINEA ESPACIO
        End If
        EpsonPrinter.WriteString(FechaActual) ' fecha
    End If
       
    '**********************************************************************
    'Avanza 3 lines
    ' PONER UN PARAMETRO PARA LA CANTIDAD DE LINEAS A AVANZAR POR LADUDAS
    '**********************************************************************
    EpsonPrinter.WriteString(Chr(27) & "d" & Chr(Starter.setlineasimpre))
    'Log( "col1:" & ArtCodigo & "col2:" & ArtDescripcion & ArtPrecio)
    '''''''''''''''''''''
       
   
End Sub
 

Attachments

  • EscPosPrinter.bas
    46.6 KB · Views: 114

vecino

Well-Known Member
Licensed User
Longtime User
Gracias, elsanto1970, a ver si soy capaz de echar a andar esto con la ayuda de todos vosotros.

Por cierto, me ha parecido entender que imprimes desde varias activitys, pero, ¿desde activitys enlazadas desde otras activitys?
Me explico, el problema que tengo no es imprimir desde cualquier activity, sino que mejor lo explico con un ejemplo para que quede más claro:

Desde "main" abro la activity "ventas", ahí imprimo albaranes, facturas, etc. Todo bien.
Desde esa activity "ventas" abro la activity "cobros" (callsubdelayed2(...)), ahí imprimo recibos de cobros. Todo bien.
Ahora cierro la activiy "cobros", se regresa de nuevo a la activity "ventas".
Si ahora intento imprimir... ¡¡¡problema!!!

Gracias de nuevo.
Saludos.
 

elsanto1970

Member
Licensed User
Longtime User
Vecino : Entendi tu ejemplo ,yo tambien hago lo mismo.

Tengo 7 actividades, en todas tienen la opcion de imprimir , el usuario puede saltar por todos las actividades
pero para antes de llamar a la otra actividad la cierro con Activity.Finish y para llamar a cobros siguiendo tu ejemplo StartActivity(Cobros) no utilizo callsubdelayed2(...) puede que tu problema este ahi
y en el ejemplo que te puse realizo lo mismo en todas las actividades
B4X:
Sub Process_Globals
    Dim EpsonPrinter As EscPosPrinter
End Sub
Sub Activity_Create(FirstTime As Boolean)
'*************************************************************************************
    '* Inicializo el driver de impresion
    '*************************************************************************************

    
        EpsonPrinter.Initialize(Me, "EpsonPrinter")
    

Sub Activity_Resume
  
    If EpsonPrinter.IsBluetoothOn = False Then
    
        ToastMessageShow("El Bluetooth no esta activado", False)
    Else If EpsonPrinter.IsConnected = False Then
        EpsonPrinter.Connect
    
    End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    EpsonPrinter.DisConnect
End Sub
Sub EpsonPrinter_Connected (Success As Boolean)
    'Log("EpsonPrinter_Connected" & Success)
    If Success Then
    '    ToastMessageShow("La impresora esta conectada", False)
        btnimprimir.Enabled = True
    Else
        'ToastMessageShow("Error de comunicación con la Impresora ", False)
        btnimprimir.Enabled = False
      
    End If
End Sub
Yo lo hago asi , no se si sera la forma mas adecuada , pero me ha funcionado perfectamente ,
tengo poca experiencia en b4x pero los clientes están satisfechos ....

Nunca tengo problemas de conexión con el impresor por ahi puede ser mas lenta la app (nose)
pero con la potencia de los equipos ni se nota , pero no tengo perdidas de conexión

De todas maneras estamos trabajando con distintas librerias de impresión
Saludos
 

Attachments

  • Elsis Articulos Impresion.png
    Elsis Articulos Impresion.png
    165.6 KB · Views: 129
Last edited:

vecino

Well-Known Member
Licensed User
Longtime User
Hola, no me ha funcionado tampoco 😢
Cuando regresa de cobros a ventas ya pierde la conexión, y si intento reconectar tampoco lo hace, indicando que no encuentra ninguna impresora :/

Lo volveré a revisar a ver si me he equivocado en algo.
 

vecino

Well-Known Member
Licensed User
Longtime User
Tengo 7 actividades, en todas tienen la opcion de imprimir , el usuario puede saltar por todos las actividades
pero para antes de llamar a la otra actividad la cierro con Activity.Finish y para llamar a cobros siguiendo tu ejemplo StartActivity(Cobros) no utilizo callsubdelayed2(...) puede que tu problema este ahi
No lo consigo, a veces funciona y otras veces no, algunas veces funciona una o dos veces y a la tercera ya tampoco, y así.
Seguramente es lo que dices, si abres una activity, imprimes, cierras y luego abres otra activity y haces lo mismo, entonces sí funciona.
El problema es que no puedo hacer eso (usar StartActivity()) porque necesito abrir las otras activitys con parámetros llamando a alguna "Sub" y luego volver a la activity que la llamó y seguir justo "por donde iba", y no volver a empezar de nuevo.
O sea, el ejemplo de antes, desde "ventas" elije un cliente y muestra sus datos, indicando que debe un importe, entonces se llama a "cobros" que se abre con los datos debidos de ese cliente. Cuando termina entonces se cierra "cobros" y vuelve a "ventas" justo por donde iba, con los datos del mismo y esperando para introducir líneas de ventas.
No sé si eso se puede hacer de otra manera.
 

elsanto1970

Member
Licensed User
Longtime User
Vecino una sugerencia , prepara un proyecto pequeño con 3 actividades y la libreria de la impresora que estas usando , con la misma logica y subilo haber si te podemos ayudar a imprimir sin perder conexion .....
Saludos
 

vecino

Well-Known Member
Licensed User
Longtime User
Justo estoy preparándolo :D
En cuanto lo tenga, lo pongo por aquí.
¡Gracias!
 

vecino

Well-Known Member
Licensed User
Longtime User
Bueno, en principio lo he intentando con EscPosPrinter, y no he conseguido nada :/
Aquí lo adjunto.
Voy ahora a prepararlo con lo que estaba usando antes y lo subo también.
Saludos.
 

Attachments

  • pruimpresora.zip
    24.5 KB · Views: 101

edgar_ortiz

Active Member
Licensed User
Longtime User
Vecino,

En lo personal imprimo a "mano", es decir no utilizo la clase y además defino los objetos relacionados a la impresión en el "Starter"

B4X:
    '
    Dim o_Serial                        As Serial        ' Objeto que contiene la comunicacion con los dispositivos
    Dim o_Printer                      As AsyncStreams    ' Objeto que contiene la informacion a imprimir
    Dim o_Printer_Conected     As Boolean        ' Indica si la impresora está conectada

Además, tengo una "actividad" solo para conectar la impresora y "nunca" la desconecto.

Espero te sirva.

Saludos,

Edgar
 

José J. Aguilar

Expert
Licensed User
Hola Vecino:

La verdad es que hace mucho que hice lo de pasar código a una clase y no recuerdo bien ahora cómo iba, y para colmo no tengo impresora para probar, pero echa un ojo a este intento que he hecho para que veas que (corrigiendo los errores que haya), pasar las funciones de la impresora a una clase, e inicializándola desde un servicio (Starter en este caso), no es complicado.

Mira si por casualidad funcionara así de primeras ( o al menos que consigas que se conecte y no se desconecte), y ya lo pulimos si optas por esta solución.
 

Attachments

  • pruimpresoraServicio.zip
    25.4 KB · Views: 87

vecino

Well-Known Member
Licensed User
Longtime User
Vecino, En lo personal imprimo a "mano", es decir no utilizo la clase y además defino los objetos relacionados a la impresión en el "Starter"
Gracias, edgar_ortiz, así es como lo he estado usando hasta ahora y siempre ha funcionado, hasta que he tenido que estar imprimiendo enlazando de activity a activity.
Seguramente el problema soy yo, que algo estoy haciendo mal y no descubre el qué.
 

edgar_ortiz

Active Member
Licensed User
Longtime User
Gracias, edgar_ortiz, así es como lo he estado usando hasta ahora y siempre ha funcionado, hasta que he tenido que estar imprimiendo enlazando de activity a activity.
Seguramente el problema soy yo, que algo estoy haciendo mal y no descubre el qué.

Vecino...

En lugar de usar usa "clase" utiliza los "objetos" a nivel (global) del "starter" accedes a la impresora en un "Code Module", defines unas "funciones", le pasas los parámetros respectivos y FUNCIONA!!!

Saludos,

Edgar
 
Top