B4J Question ABMaterial Draw Barcode on Modal Sheet

walterf25

Expert
Licensed User
Longtime User
Hi all, i was wondering if anyone has ha any experience drawing a barcode with ABMaterial framework, specifically on a modalsheet.

I found this thread which has a few code modules that generate different types of barcodes, while the code is very simple to follow, it requires a canvas object to draw the barcode on.

I found that with ABMaterial there is a ABMCanvas object, but it seems to be a bit different than the standard Canvas Object in B4X, I tried replacing the regular Canvas object with the ABMaterialCanvas Object but for some reason I can't seem to get this to work.

Below is my code.
B4X:
    Dim cnvs1 As ABMCanvas
    cnvs1.Initialize(page, "barcodecanvas", ABM.COLOR_BLACK, ABM.INTENSITY_DARKEN4, 800, 400dip, False)
    cont1.Cell(2, 1).AddComponent(cnvs1)
    Dim cnvObject As ABMCanvasObject
    cnvObject.InitializeAsRectangle(page, "cnvObject", 0, 0, 800, 400, False)
    cnvs1.AddObject(cnvObject)
    cnvs1.Refresh

This part is inside the ModalSheet generation code.
Inside the modalsheet I have a table, and the idea is that when the user Enters a PartNumber, the part number should be used to generate a barcode and show it below the table.
The code below shows when a change is done on any column of the table.

B4X:
Sub itemEntryTable_Changed(Params As Map)
    ''Log("params changed: " & Params)
    Dim col, row As Int
    col = Params.Get("column")
    row = Params.Get("row")
    Dim val As String
    If col = 1 And row = 0 Then
        val = Params.Get("value")
        Dim modal As ABMModalSheet = page.ModalSheet("ItemEntry") '''page.Component("ItemEntry")
        Dim container As ABMContainer = modal.Content.Component("itementrycontainer")
        Log("container id: " & container.ID)
        Dim cnv As ABMCanvas = container.Component("barcodecanvas")
        Dim cnvObject As ABMCanvasObject = cnv.GetObject("cnvObject")
        draw_barcode_Code39(cnvObject, Code39.Draw_Code39("1234567890"))
        cnv.Refresh
        cnvObject.Refresh
        '''modal.Refresh
    End If
End Sub

And Here's is the code that should actually generate the barcode which is based on the examples shown on the link provided above.
B4X:
Sub draw_barcode_Code39 (cnv As ABMCanvasObject, mes As String)
    Dim su As StringUtilities
    su.Initialize
    Dim mywidth As Int = cnv.Width
    Dim myheight As Int = cnv.Height
    Dim silent As Int = (mywidth - 4*su.stringLength(mes))/2

    Log (mywidth)
    Log (myheight)
    Log (silent)
    cnv.beginPath
    Dim cnt As Int = silent + 1
    For i = 0 To su.stringLength(mes) - 1
        If su.Mid(mes,i,1) = "1" Then
            '''cnv.fillRect(cnt, 10, 4, 80)
            '''cnv.rect(cnt, 10, 4, 80)
            cnv.fillText("Walter", cnt, 80)
            cnv.fillStyleColor(ABM.COLOR_BLACK)
            cnv.fill
            '''cnv.DrawRect(cnt,10,4,80,ABM.COLOR_BLACK,True,2)
        Else
            '''Canvas2.DrawRect(cnt,10,4,80,fx.Colors.White,True,2)
            cnv.rect(cnt, 10, 4, 80)
            cnv.fillStyleColor(ABM.COLOR_WHITE)
            cnv.fill
            
            '''cnv.fillRect(cnt, 10, 4, 80)
        End If
        cnt = cnt + 4
    Next
    
'''    cnv.Refresh
End Sub

I'm not sure if I'm not understanding correctly how the ABMCanvas object should be used, but it just doesn't seem to draw anything.

I also found another thread somewhere mentioning that there was a bug on ABMaterial when trying to draw a canvas inside a modalsheet, can't find that thread for now, but not sure if this was already fixed or not.

Does anyone have any other ideas on how to accomplish this?

Walter
 

alwaysbusy

Expert
Licensed User
Longtime User
We use this custom component in our ABM and BANano apps. It is very lightweight and does not require any canvas.

CompBarCode class:
B4X:
'Class module
Sub Class_Globals
    Public ABMComp As ABMCustomComponent
    Private myValue As String
    Public mySize As Double
    Public myID As String
    Public mBCType As String = "CODE39"
    Public mRotation As Int = 0
    Public mHeight As Int = 40
End Sub
 
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(InternalPage As ABMPage, ID As String, value As String, size As Double, bcType As String, rotation As Int, height As Int)
    ABMComp.Initialize("ABMComp", Me, InternalPage, ID, "")
    myValue = value      
    mySize = size
    mBCType = bcType
    mRotation = rotation
    mHeight = height
End Sub
 
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String  
    Dim varID As String = internalID.Replace("-", "_")
    myID = varID
    If mRotation <> 0 Then
          Return $"<div style="transform: rotate(${mRotation}deg)"><svg id="${varID}svg" class="barcode"></svg></div>"$
    Else
        Return $"<svg id="${varID}svg" class="barcode"></svg>"$
    End If        
End Sub
 
' Is useful to run some initalisation script.
Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)
    If myValue = "" Then Return
    Dim varID As String = internalID.Replace("-", "_")
    Dim script As String = $"JsBarcode("#${varID}svg", "${myValue}", {
        format: "${mBCType}",
        textMargin: 0,
        width: ${mySize},
        background: "transparent",
        displayValue: false,
        height: ${mHeight},
        fontSize: 15 
    });"$
 
      InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
      ' flush not needed, it's done in the refresh method in the lib
End Sub
 
' runs when a refresh is called
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
    Dim varID As String = internalID.Replace("-", "_")
    Dim script As String
    If myValue = "" Then 
        script = $"$('#${varID}svg').hide();"$
    Else    
        script = $"JsBarcode("#${varID}svg", "${myValue}", {
            format: "${mBCType}",
            textMargin: 0,
            width: ${mySize},
            background: "transparent",
            displayValue: false,
            height: ${mHeight},
            fontSize: 15 
        });
        $('#${varID}svg').show()"$     
          
    End If
    InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
End Sub

public Sub SetValue(InternalPage As ABMPage, value As String)    
    myValue = value
    ABMComp_Refresh(InternalPage, myID)
    InternalPage.ws.Flush
End Sub
 
' do the stuff needed when the object is removed
Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String)
 
End Sub

In BuidPage (see attachement for the jsBarcode file that you place in the www/js/custom/ folder):
B4X:
page.AddExtraJavaScriptFile("custom/JsBarcode.all.min.js")

Usage:
B4X:
Dim bcBarCode As CompBarCode
bcBarCode.Initialize(page, Name & "bcBarCode", "/419000005", 1.5, "CODE128", 0, 40)
cont.Cell(1,1).AddComponent(bcBarCode.ABMComp)

Alwaysbusy
 

Attachments

  • JsBarcode.all.min.zip
    8.6 KB · Views: 91
Upvote 0

walterf25

Expert
Licensed User
Longtime User
We use this custom component in our ABM and BANano apps. It is very lightweight and does not require any canvas.

CompBarCode class:
B4X:
'Class module
Sub Class_Globals
    Public ABMComp As ABMCustomComponent
    Private myValue As String
    Public mySize As Double
    Public myID As String
    Public mBCType As String = "CODE39"
    Public mRotation As Int = 0
    Public mHeight As Int = 40
End Sub
 
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(InternalPage As ABMPage, ID As String, value As String, size As Double, bcType As String, rotation As Int, height As Int)
    ABMComp.Initialize("ABMComp", Me, InternalPage, ID, "")
    myValue = value     
    mySize = size
    mBCType = bcType
    mRotation = rotation
    mHeight = height
End Sub
 
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String 
    Dim varID As String = internalID.Replace("-", "_")
    myID = varID
    If mRotation <> 0 Then
          Return $"<div style="transform: rotate(${mRotation}deg)"><svg id="${varID}svg" class="barcode"></svg></div>"$
    Else
        Return $"<svg id="${varID}svg" class="barcode"></svg>"$
    End If       
End Sub
 
' Is useful to run some initalisation script.
Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)
    If myValue = "" Then Return
    Dim varID As String = internalID.Replace("-", "_")
    Dim script As String = $"JsBarcode("#${varID}svg", "${myValue}", {
        format: "${mBCType}",
        textMargin: 0,
        width: ${mySize},
        background: "transparent",
        displayValue: false,
        height: ${mHeight},
        fontSize: 15
    });"$
 
      InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
      ' flush not needed, it's done in the refresh method in the lib
End Sub
 
' runs when a refresh is called
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
    Dim varID As String = internalID.Replace("-", "_")
    Dim script As String
    If myValue = "" Then
        script = $"$('#${varID}svg').hide();"$
    Else   
        script = $"JsBarcode("#${varID}svg", "${myValue}", {
            format: "${mBCType}",
            textMargin: 0,
            width: ${mySize},
            background: "transparent",
            displayValue: false,
            height: ${mHeight},
            fontSize: 15
        });
        $('#${varID}svg').show()"$    
         
    End If
    InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
End Sub

public Sub SetValue(InternalPage As ABMPage, value As String)   
    myValue = value
    ABMComp_Refresh(InternalPage, myID)
    InternalPage.ws.Flush
End Sub
 
' do the stuff needed when the object is removed
Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String)
 
End Sub

In BuidPage (see attachement for the jsBarcode file that you place in the www/js/custom/ folder):
B4X:
page.AddExtraJavaScriptFile("custom/JsBarcode.all.min.js")

Usage:
B4X:
Dim bcBarCode As CompBarCode
bcBarCode.Initialize(page, Name & "bcBarCode", "/419000005", 1.5, "CODE128", 0, 40)
cont.Cell(1,1).AddComponent(bcBarCode.ABMComp)

Alwaysbusy
Awesome, thanks for the quick reply, I will give it a try tomorrow morning.

Thanks,
walter
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
We use this custom component in our ABM and BANano apps. It is very lightweight and does not require any canvas.

CompBarCode class:
B4X:
'Class module
Sub Class_Globals
    Public ABMComp As ABMCustomComponent
    Private myValue As String
    Public mySize As Double
    Public myID As String
    Public mBCType As String = "CODE39"
    Public mRotation As Int = 0
    Public mHeight As Int = 40
End Sub
 
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(InternalPage As ABMPage, ID As String, value As String, size As Double, bcType As String, rotation As Int, height As Int)
    ABMComp.Initialize("ABMComp", Me, InternalPage, ID, "")
    myValue = value     
    mySize = size
    mBCType = bcType
    mRotation = rotation
    mHeight = height
End Sub
 
Sub ABMComp_Build(InternalPage As ABMPage, internalID As String) As String 
    Dim varID As String = internalID.Replace("-", "_")
    myID = varID
    If mRotation <> 0 Then
          Return $"<div style="transform: rotate(${mRotation}deg)"><svg id="${varID}svg" class="barcode"></svg></div>"$
    Else
        Return $"<svg id="${varID}svg" class="barcode"></svg>"$
    End If       
End Sub
 
' Is useful to run some initalisation script.
Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String)
    If myValue = "" Then Return
    Dim varID As String = internalID.Replace("-", "_")
    Dim script As String = $"JsBarcode("#${varID}svg", "${myValue}", {
        format: "${mBCType}",
        textMargin: 0,
        width: ${mySize},
        background: "transparent",
        displayValue: false,
        height: ${mHeight},
        fontSize: 15
    });"$
 
      InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
      ' flush not needed, it's done in the refresh method in the lib
End Sub
 
' runs when a refresh is called
Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String)
    Dim varID As String = internalID.Replace("-", "_")
    Dim script As String
    If myValue = "" Then
        script = $"$('#${varID}svg').hide();"$
    Else   
        script = $"JsBarcode("#${varID}svg", "${myValue}", {
            format: "${mBCType}",
            textMargin: 0,
            width: ${mySize},
            background: "transparent",
            displayValue: false,
            height: ${mHeight},
            fontSize: 15
        });
        $('#${varID}svg').show()"$    
         
    End If
    InternalPage.ws.Eval(script, Array As Object(ABMComp.ID))
End Sub

public Sub SetValue(InternalPage As ABMPage, value As String)   
    myValue = value
    ABMComp_Refresh(InternalPage, myID)
    InternalPage.ws.Flush
End Sub
 
' do the stuff needed when the object is removed
Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String)
 
End Sub

In BuidPage (see attachement for the jsBarcode file that you place in the www/js/custom/ folder):
B4X:
page.AddExtraJavaScriptFile("custom/JsBarcode.all.min.js")

Usage:
B4X:
Dim bcBarCode As CompBarCode
bcBarCode.Initialize(page, Name & "bcBarCode", "/419000005", 1.5, "CODE128", 0, 40)
cont.Cell(1,1).AddComponent(bcBarCode.ABMComp)

Alwaysbusy
Is there a way to convert to a png or jpg image, I have a bluetooth thermal printer that doesn't seem to work very well, it does print images, so I wanted to try to convert this barcode into an image?

Any suggestions?

Thx,
Walter
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
We use this snippet to print the barcode to zebra label printers. Maybe you can use it too. No idea how to convert an svg to a jpg/png. May be possible using some javescript.

B4X:
Dim Script As String = $"
            var divContents = $("#TheIDHoldingTheBarCode").html();
            var a = window.open('', '', 'height=500, width=700'); 
            a.document.write('<html>'); 
            a.document.write('<body onafterprint="self.close()">'); 
            a.document.write('<div style="width: 100%;height: 100%;text-align:center;">');
            a.document.write(divContents); 
            a.document.write('</div>');
            a.document.write('</body></html>'); 
            a.document.close();
            a.print();
            "$        
            
Page.ws.eval(Script, Null)
Page.ws.Flush

Alwaysbusy
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
We use this snippet to print the barcode to zebra label printers. Maybe you can use it too. No idea how to convert an svg to a jpg/png. May be possible using some javescript.

B4X:
Dim Script As String = $"
            var divContents = $("#TheIDHoldingTheBarCode").html();
            var a = window.open('', '', 'height=500, width=700');
            a.document.write('<html>');
            a.document.write('<body onafterprint="self.close()">');
            a.document.write('<div style="width: 100%;height: 100%;text-align:center;">');
            a.document.write(divContents);
            a.document.write('</div>');
            a.document.write('</body></html>');
            a.document.close();
            a.print();
            "$       
           
Page.ws.eval(Script, Null)
Page.ws.Flush

Alwaysbusy
Quick question, is the barcode supposed to show in the preview when you run this code, I only see the numbers, and how exactly are you connected to the printer, usb, bluetooth?

Walter
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
usb, but that should not matter, it should show in the preview. What version of ABM do you use? I'll have a look at my code tomorrow if I have missed something that should be done extra for printing to work (can't think of anything, but just in case...)
I am using ABMaterial version 4.51, I have a cheap thermal bluetooth printer which I would like to use to print the barcode label, but I am only seeing the numbers in the preview.

Thanks,
Walter
 
Upvote 0
Top