BANano 4.50 released and Anywhere Software drops a bomb!

“A very exiting week it is” would Yoda say.

The latest version of BANano introduces the BANanoServer.b4xlib library, which is an easy to use wrapper around jServer, the same B4J lib ABMaterial uses. One can now use BANano to make stand-alone Web sites, but also interfaces for e.g. IoT and Raspberry Pi (when using the BANanoServer lib: as this is a normal B4J app, it can use all B4J libs on the server side) and build complex Web Apps.

NOTE: BANano still works without the BANAnoServer Library as it did before in case you want to use another backend like PHP, but only having to program in one language has huge advantages and is what RAD is al about. :)

When you will look at the code of BANanoServer, ABM users will recognize the powerful Caching system, Root, Websocket support and HTTP/2 filters. In BANano, all that code is removed from your own projects view (but still accessible as it is an open source .b4xlib).

Some ‘easy-to-use’ methods to communicate between the browser and the server are added (to call methods from each other and to exchange files).

More info and download BANano for free here: BANano Download

But the biggest news this week must have been the BOMB Erel from Anywhere Software dropped: B4A, the tool to make native Android apps, is from now on free to use for everyone!

From his announcement a couple of weeks ago:

I’m very proud in the continuing progress of B4X tools. I’m also very proud to be part of this amazing developers community.

In the last couple of years, I have a growing feeling that B4X tools do not realize their potential. While there are all kinds of development tools, B4X offers a unique set of features: simple, powerful, mature, great community, RAD, native, cross platform and more.
B4X tools are an excellent choice for a wide range of real-world use cases.

So, the question is how to make B4X more popular? Obviously, it is not a simple nor a short-term task.
A clear growth barrier is the fact that unlike most development tools today, B4A and B4i are not free. This wasn’t the case 10 years ago.

The big announcement today is that B4A will become free in a few weeks. The framework – set of internal libraries, will be open sourced.

We will accept contributions for B4A like currently done with B4J.
We’ve also secured funds from a US investor who shares my vision of making B4X a popular development tool. These resources will allow us to further expand.

Two huge points were raised here: for one, the tool that started it all (B4A) to make native Android apps, is now 100% free (download it here)! It is clear that nowadays paying for a development platform is so 2009. Some development vendors may exist for 20+ years, but haven’t grown accordingly and seem to be stuck in overprotecting their (outdated?) technology.  Clearly, Erel is not one of them and is thinking on how to expand his tools into the next decade.

But the second part may be even more exciting: a private US investor has shown interest in the potential of B4X and shares Erel view of the future.  This opens a whole new world to the development tool and allows to think a lot bigger. He can expand his team not only with new developers, but even more important, surround himself with professionals to market his brand and let the world know of the big impact his technology can have on any software developer.

Just read up on the forum (100K+ members) and one quickly realizes the brought spectrum of apps that can be written with B4X. It is used by big corporations like NASA, IBM and Bosch to name a few, but also by small companies and citizen developers. I for one use it daily in my day job at OneTwo and we feel so secure with the tools we use it as the foundation of all our software.  Very rarely one comes across a tool where the developers are so close to its users and actually listens to their concerns and wishes.  I remember having found a bug (yeah, you really have to go deep to find one) and after reporting it to the Anywhere Software team, 10 minutes(!) later, an update was released.  This has never been seen and blocked me zero time in my own development.

I am a big fan of the B4X suite. It allowed me to write ABMaterial and BANano, two libraries to make modern Websites and Webapps.  Something I can’t see me do in any other tool, at least not with such ease and speed. And it is fun, really fun to work with too. 🙂

So I think Yoda would concur: ‘The future, bright it is!’


Young Africans learn IoT programming with B4X


Some young and interested African tech enthusiasts completed their first IoT course using the free B4X tools from Anywhere Software, congratulations!

In a hackathon event in celebration with International Arduino Day 2019, a deep overview as seminar on B4X products and specifically utilizing B4R with famous micro controllers and technologies was organized.

Go to the full article



Click here to Donation and support BANano & ABMaterial

[B4X] BANano 1.21 Christmas gift!


BANano is a new B4J library to create one-page websites/webapps with (offline) Progressive Web App support. Unlike its big brother ABMaterial, BANano does not rely on any particular framework like Materialize CSS. You will have to write that part yourself, but on the other hand, you have the choice to pick which one.

Why a second framework? Well, from the start ABMaterial was build with a back server in mind. B4J has great support to setup a very powerful jServer to handle web requests. Which does mean all intelligence is at the server side and you have the full power of B4J to do whatever you want (secure database access, serial communication, cache control etc). With B4JS, some of this intelligence could be transferred to the browser side, but the app still needs internet/intranet access so this is as far as it could go.

BANano is a different animal. It can use a Service Worker to ‘install’ the web app in the browser, so it can also work when the user is offline. While ABMaterial builds the page from the server side, BANano builds it from the browser side. This means EVERYTHING you write in B4J is transpiled to JavaScript, HTML and CSS.

But with great power comes great responsibility! Unlike ABMaterial, knowledge of HTML, CSS and to some extend JavaScript is needed to build BANano apps. It makes excellent use of B4X’s SmartStrings to create the HTML part of the app. BANano gives you a set of tools to write your own wrapper around any framework (MiniCSS, Skeleton, Spectre, Bootstrap, …), which then can be easily used to quickly build webapps/websites.

v1.21+: Abstract Designer support:

It is a rather simple and elegant system I think:

1. You set BANanoDesignElement elements in the designer (Add View, Custom view).

Only these properties apply:

2. Each has a Build event where you can do your specific html stuff

3. You load a layout with BANano.LoadLayout. At this time, the bjl file is parsed (as B4J custom components do not support a different parent than main yet, I had to write an alogorithm to find the parent myself) and translated to _Build commands (you will see it in the DemoUI library file).

Sub Class_Globals
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize

End Sub

Sub Div_Build (el As BANanoDesignElement)
<div id="${el.Name.ToLowerCase}" class="${el.Classes}"></div>

End Sub

Sub Row_Build (el As BANanoDesignElement)$"
<div id="${el.Name.ToLowerCase}" class="${el.Classes}"></div>

End Sub

Sub Column_Build (el As BANanoDesignElement)$"
<div id="${el.Name.ToLowerCase}" class="${el.Classes}"></div>

End Sub

' extra: the level of h;the text
Sub H_Build (el As BANanoDesignElement)$"<h${el.Extra(0)} id="${el.Name.ToLowerCase}" class="${el.Classes}">${el.Extra(1)}</h${el.Extra(0)}>"$)
End Sub

Sub P_Build (el As BANanoDesignElement)$"

End Sub

Sub Button_Build (el As BANanoDesignElement)
   Dim btn() As BANanoElement =$"<button id="${el.Name.ToLowerCase}" class="${el.Classes}">${el.Extra(0)}</button>"$,"").Children("#" & el.Name.ToLowerCase)
   ' defining events is very simple. Note that it has to be run AFTER adding it to the HTML DOM!
   ' eventName must be lowercase!
   btn(0).HandleEvents("click", el.ModuleEventHandler, el.Name.ToLowerCase & "_clicked")
End Sub

' extra: image source;alt text
Sub Image_Build (el As BANanoDesignElement)$"<img id="${el.Name.ToLowerCase}" src="${el.Extra(0)}" alt="${el.Extra(1)}"/>"$)
End Sub

Using this in a real app is now very simple:

Sub Process_Globals
   Private BANano As BANano 'ignore
   Private Builder As BANanoMiniCSSBuilder '<-------- defining our BANano Library
End Sub

Sub AppStart (Form1 As Form, Args() As String)

   ' you can change some output params here
   BANano.Initialize("BANano", "BANanoMiniCSS",12)
   BANano.HTML_NAME = "banano.html"

   BANano.Header.Title="BANano MiniCSS"
   BANano.ExternalTestConnectionServer = ""

   ' start the build

End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
   Return True
End Sub

Sub BANano_Ready()
   Builder.Initialize '<------- initialize the library

   BANano.LoadLayout("#body", "Layout1", Builder, Me) '<--- load the layout
End Sub

Sub MyButton_Clicked(event As BANanoEvent)
   Log("Clicked on " & event.ID)    
   BANano.LoadLayout("#r3c2", "SubLayout1", Builder, Me) ' <---- load a sub layout
End Sub

Builder is the library (the one who will handle the Build() events)
Me (the one who will handle e.g. the MyButton_Clicked event: so like all other events except Build)

An example project using the MiniCSS javascript library is included in the zip (both the library and a demo project using it) in the DemoUi folder.

Couple of important notes:
1. Both the library and App must be a B4J UI project, not a console project
2. When you now run BuildAsLibrary, the assets in the Files folder will be zipped to, next to the .js and .dependsOn files.

I think this is cool! Very happy with it…

DOWNLOAD: FREE library and some basic demo projects

I wish you all a fantastic year-end end and a very productive and happy new 2019!


Click here to Donation and support BANano & ABMaterial

RB/Xojo: Goodbye, you old dinosaur…


And I mean this in an very friendly way, referring to one of their latest campaigns 🙂

I was doing some early spring cleaning on the dusty attic of this blog and came across some old projects I did.

Some of you long time followers of my blog may remember I wrote several posts programming in Xojo (previously RealStudio or even RealBasic before that).  When I first started this blog, I was a huge fan of RB.  The familiar VB6 syntax was what me attracted to it in the first place. I had a VB6 background, and with Microsoft abandoning it, RB was a nice alternative.  I really didn’t care much for it being able to cross compile back then as Windows was my thing.  But it was nice that it could.

Back then, many years ago, I used this place to write articles mainly on the Canvas (an 11 episode series!) and vintage games.

But also some frameworks like ABXVision that had OpenCV like capabilities (Augmented Reality in its early stages!) and a full blown physics engine ABPE.

The robotics series was a very fun project to do.  I was doing a course on Artificial Intelligence at the time and I could use this new knowledge in the tutorials.

But because of Xojos decision a couple of years ago to start using a new syntax framework, most of these projects won’t work anymore without a major overhaul.  So I feel it is time to let them go. I recently noticed Xojo had removed this blog from their resource list too, so they must’ve had the same feeling. Honestly, no hard feelings about that! I would too when a blog doesn’t write anything on me anymore.

But what is there currently to write about Xojo? The Web part hasn’t changed in many years and still looks like it is 1995. iOS still feels like it is only partly finished and is missing to many out-of-the-box features to be useful (will the new upcoming android suffer from the same problem?).  Should I write about the many bugs and workarounds one has to do?

It must be said many of this remarks have to do with Xojo being a small team, and some stuff (like 64bit or Apples decisions) has been forced upon them.  Luckily they have a small but enthusiastic community which is willing to take over the many shortcomings by writing frameworks like Aloe or iOSKit.

So, time to put those fond memories into a box and leave memory lane.  Back to the real harsh world ;-).

I will leave the RB/Xojo projects on this blog until the end of the month (March).  Maybe, one day, I will find the time to revamp them in Xojo or put them all up on GitHub and they will reappear.

Until then, this blog will mainly report on B4X and my own framework ABMaterial.

Godspeed old friend(s). Until we meet again…

UPDATE: I was planning to make a separate blog section for my old RB/Xojo projects, but I just can’t find the time to do so. I created a raw FTP dump of everything RB/Xojo related today that you can download from here. It is a bit messy so you will have to browse through it yourself. A lot of it will probably be outdated (the main reason I removed everything from my blog) and will need some re-work, but some of it may still be useful for someone.

Download RAW FTP Dump of RB/Xojo projects


Click here to Donation and support ABMaterial


B4X: ABMaterial 3.75 Public/4.00 Donators released


ABMaterial Dragonfly (4.00) for B4X is available. Yes, it has a new name! What started as version 3.81 got upgraded to a new major version, especially since it uses a new cache control system.

ABMaterial has always been one of the fastest RADs from its start, now over 2 years ago.  But with 4.00, we’ll take it to a whole new level!

Mindful and I have spend 5 days (and nights) checking out how we could cache ABMaterial to the extreme without losing any of its functionality.  The results are just ridiculous…

Finish times are less than 10% of the time on the second and next loads. So on 3G, on the users next visit(s), the WebApp is almost just as fast as on high speed cable!

And this system not only works with the same page. Once one page has been loaded, all the other pages can take gain of this system. Even when the user revisits your app much later.

Furthermore there is the new debug feature to check how your apps work on different device sizes.  See it at work here:

Add this snippet to you main module, AFTER starting the server:

' in debug mode, start the browser and open the app on all devices (DOES NOT WORK IF EDGE IS YOUR DEFAULT BROWSER!)
ABM.ViewerOpenAllDevices("http://localhost:" & port & "/" & ABMShared.AppName & "/", 100)

' or open a specific device as default (DOES NOT WORK IF EDGE IS YOUR DEFAULT BROWSER!)
'ABM.ViewerOpenDevice("http://localhost:" & port & "/" & ABMShared.AppName & "/", 300, ABM.VIEWER_TABLET)

' or just open de browser, no multiple devices (should work in Edge)
'ABM.ViewerOpen("http://localhost:" & port & "/" & ABMShared.AppName & "/")
#End If

Lots of new theme properties! Check out the demo on how to use  them in the new Dragonfly theme.  As winter is coming and days are getting shorter (at least here in the northern hemisphere), I went for a ‘Night’ theme this time.

ABMaterial DragonFly is now available on 750+ locations worldwide on CDN!  If you use the CDN, you do not need to upload the css/js/fonts folders to your own server anymore!

This means only your own assets (images etc) from the www folder have to be available on your server. De demo running on for example is working like this.


ABM.ActivateUseCDN("DONATORKEY", "")

The over 20 new fixes and fulfilled wishes make ABMaterial 4.00 very stable, just like its ‘parent’ programming language: B4X.  It is a real joy knowing one can depend on a strong, bug free environment.  Erel from Anywhere Software rulez!

Happy programming!


Click here to Donation and support ABMaterial

Windows October Update ODBC export Excel problems


Windows updates, you gotta love them! This October update has a lot of developers scratching their head.

Here at OneTwo, we became first aware of the problem when some clients called our support team with the same remark: “Exporting the data to Excel does not work!”  After going through the usual procedure following the directions of Roy Trenneman from the IT crowdhave you tried turning it on and off again?“, we quickly became aware there was something more going on…

Indeed, Microsoft had rolled out a new update.  “Drop everything, we have a KB hunt on our hands!”  A time consuming thing to do, and in the meantime a lot of worried users.  Google and the MSDN site had to do overtime too.


Quite some time later, we found the little buggers. Here is the list for anyone out there banging his head aginst the wall asking himself why his code, which has been running for years, suddenly stopped working:

  • Windows 7: KB4041681
  • Windows 8.1: KB40416393
  • Windows 10: KB4040724/KB4041676

Uninstall them and reboot. Hooray, code is working again!


It looks like Windows keeps insisting to run the update.  Here is a more permanent solution.

1. Find prior version (4.0.9801.0) of msexcl40.dll

2. Place in another directory. They suggest the application directory, but since in the next step you will modify registry to point to this older version, it can probably go anywhere.

3. Update registry key HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Excel\win32 to point to the location from step 2.

You don’t even have to restart your PC.

Have a great weekend, my fellow IT minions!


Click here to Donation and support ABMaterial

B4J: Printing/Reporting with upcoming ABMaterial 3.75

A sneak peek on a new feature of ABMaterial for B4J I’m working on: Printing/Reporting.

This is an example of a report in ABMaterial. You build it right into your other pages and just by setting a couple of parameters, you control what will be shown on screen and what will be printed.

The block your see above ‘INVOICE’ will not be printed, just my setting lbl.IsPrintable = false.  What is shown on screen you control by using the normal ABM.VISIBLE_ constants. For example there are some additional notes with a chart that you can’t see here on screen, but will be printed.

You can use almost every ABM component in your report. Good examples are the ABMChart, the ABMChronologyList or even like in this example you can let your client sign the document using an ABMSignaturePad and print it right out.

The ABM components avoid being split over two pages (e.g. an image will be printed on the next page if it does not fit). Browsers let you control very little on how things are printed, but I’ve added some things like ReportFooter.row(3).PrintPageBreak = ABM.PRINT_PAGEBREAK_BEFORE_ALWAYS to give you some control.

Note that the navigation bar is not printed either. All of this is taken care for you automatically by ABMaterial!

Some example pdf prints from the demo app (without making any modification to the source code!). Try printing the same pages with ABMaterial 3.50 or before and you’ll see the difference.

Making the above ‘invoice report’ is really simple and in the spirit of ABMaterial. I’ve created a new component ABMReport (and ABMReportBlock) which you can use just like you would make an ABMCustomComponent.

Relevant source code snippet of the above report (the Build event is where the magic happens, the rest are more helper methods):

Sub Class_Globals
   Dim ABM As ABMaterial
   Dim Report As ABMReport

   ' some CSS to format the 'body' of the report
   Dim ReportCSS As String = $"
   .repheader, .repfooter, .repheaderright, .repfooterright {
     background-color: lightgray;
     font-size: 1.8rem;
   .repheaderright, .repbodyright, .repfooterright {
     text-align: right;
   .repbody, .repbodyright {
     font-size: 1.5rem;

   @media only print {
     html { font-size: 60%}

   Dim mSQL As SQL 'ignore
   Dim mInvoiceID As Int 'ignore
End Sub

Public Sub Initialize(InternalPage As ABMPage, ID As String)
   Report.Initialize("Report", Me, InternalPage, ID, ReportCSS, "")
End Sub

Sub Report_Build(InternalPage As ABMPage, internalID As String)
   ' the report header
   Dim ReportHeader As ABMContainer = Report.Header.InitializeAsContainer(InternalPage, "reportheader", "", ABM.PRINT_PAGEBREAK_INSIDE_AVOID)
   ReportHeader.AddRows(1,False, "border").AddCells12(1,"")
   ReportHeader.AddRows(1,False, "").AddCellsOS(1,0,0,0,9,9,9,"").AddCellsOSMP(1,0,0,0,3,3,3,20,0,0,0,"right")
   ReportHeader.AddRows(1,False, "").AddCellsOS(1,0,0,0,7,7,7,"").AddCellsOS(1,0,0,0,5,5,5,"")

   ReportHeader.CellR(0,1).AddComponent(BuildLabel(InternalPage, "repTitle", "{B}I N V O I C E{/B}", ABM.SIZE_H4, "center", True, ABM.VISIBILITY_ALL))
   ReportHeader.CellR(1,1).AddComponent(BuildLabel(InternalPage, "repAddress", "Jonathan Neal{BR}{BR}101 E. Chapman Ave{BR}Orange, CA 92866{BR}{BR}(800) 555-1234",ABM.SIZE_H5, "", True, ABM.VISIBILITY_ALL))
   ReportHeader.CellR(0,2).AddComponent(BuildImage(InternalPage, "repImg", "../images/logo2.png", True, ABM.VISIBILITY_ALL))
   ReportHeader.CellR(1,1).AddComponent(BuildLabel(InternalPage, "repCompany", "{B}Some Company{/B}{BR}{B}c/o Some Guy{/B}", ABM.SIZE_H4, "", True, ABM.VISIBILITY_ALL))
   ReportHeader.CellR(0,2).AddComponent(Build3Block(InternalPage, "repInvoiceData", "{B}Invoice #{/B}", "101138", "{B}Date{/B}", "Januari 1, 2017","{B}Amount Due{/B}","$ 600.00", True, ABM.VISIBILITY_ALL)   )

   ' the report body
   Dim Body As ABMReport
   Body.Initialize("Body", Me, InternalPage, internalID & "body", "", ABM.PRINT_PAGEBREAK_INSIDE_AVOID)
   ' header of the body
   Body.Header.InitializeAsTexts(Array As String("Year(s) Overview", "Q1", "Q2", "Q3", "Q4"), Array As Int(40,15,15,15,15), Array As String("repheader","repheaderright","repheaderright","repheaderright","repheaderright"), "")

   ' detail lines: here you can e.g. run queries but for demo purposes let's do everything manual
   Dim sums(5) As Int
   For i = 1 To 9
     ' change the class of the last column on the second row
     Dim ColorClass As String = "repbodyright"
     If i = 2 Then
       ColorClass = "repbodyright red-text"
     End If

     ' create a text block
     Dim block As ABMReportBlock
     block.InitializeAsTexts(Array As String("Year 200" & i, 200*i, 300*i, 400*i, 500*i), Array As Int(40,15,15,15,15), Array As String("repbody","repbodyright",ColorClass, "repbodyright","repbodyright"), "")

     ' dirty way to make the sums
     For k = 1 To 4
       sums(k) = sums(k) + (20 + (k-1)*100) * i

   ' footer of the body
   Body.Footer.InitializeAsTexts(Array As String("{NBSP}", sums(1) , sums(2), "{B}" & sums(3) & "{/B}", sums(4)), Array As Int(40,15,15,15, 15), Array As String("repfooter", "repfooterright","repfooterright","repfooterright","repfooterright"), "")
   ' add the subreport 'body' to the body of the main report

   ' the report footer
   Dim ReportFooter As ABMContainer = Report.Footer.InitializeAsContainer(InternalPage, "reportfooter", "", "")

   ReportFooter.AddRows(1,False, "").AddCells12(1,"")
   ReportFooter.AddRows(1,False, "").AddCellsOS(1,0,0,0,2,2,2,"").AddCellsOSMP(1,0,0,0,5,5,5,0,0,10,40,"").AddCellsOS(1,0,0,0,5,5,5,"")
   ReportFooter.AddRows(1,False, "").AddCells12(1,"")
   ReportFooter.AddRows(1,False, "").AddCells12(1,"")
   ReportFooter.AddRows(1,False, "").AddCellsOSMP(1,4,4,4,4,4,4,0,0,0,0,"")
   ReportFooter.AddRows(2,False, "").AddCells12(1,"")

   ReportFooter.CellR(1,1).AddComponent(BuildLabel(InternalPage, "RepSignatureLbl", "Please sign this document", ABM.SIZE_H5, "", True, ABM.VISIBILITY_ALL))
   ReportFooter.CellR(0,2).AddComponent(BuildSignature(InternalPage, "repSignature", True, ABM.VISIBILITY_ALL))
   ReportFooter.CellR(0,3).AddComponent(Build3Block(InternalPage, "repTotalData", "{B}Total{/B}","$ 600.00","{B}Amount Paid{/B}","$ 0.00","{B}Balance Due{/B}","$ 600.00", True, ABM.VISIBILITY_ALL))

   ' avoid row 2 to be broken (can give weird results, depends on browser support!)
   ReportFooter.row(2).PrintPageBreak = ABM.PRINT_PAGEBREAK_INSIDE_AVOID

   ' alaways break before printing row 3
   ReportFooter.row(3).PrintPageBreak = ABM.PRINT_PAGEBREAK_BEFORE_ALWAYS

   ' all the rest is only visible on the print, not on the screen
   ReportFooter.CellR(1,1).AddComponent(BuildLabel(InternalPage, "AdditionalNotes", "{B}A D D I T I O N A L {NBSP}  N O T E S{/B}", ABM.SIZE_H4, "center", True, ABM.VISIBILITY_HIDE_ALL))
   ReportFooter.CellR(0,1).AddComponent(BuildDivider(InternalPage, "divider", True, ABM.VISIBILITY_HIDE_ALL))
   ReportFooter.CellR(0,1).AddComponent(BuildLabel(InternalPage, "note1", "Note 1: A finance charge of 1.5% will be made on unpaid balances after 30 days.", ABM.SIZE_H6, "", True, ABM.VISIBILITY_HIDE_ALL))
   ReportFooter.CellR(1,1).AddComponent(BuildLabel(InternalPage, "note2", "Note 2: Your current purchase chart.", ABM.SIZE_H6, "", True, ABM.VISIBILITY_HIDE_ALL))

   ' create a pie chart
   Dim chart5 As ABMChart
   chart5.Initialize(InternalPage, "chart5", ABM.CHART_TYPEPIE, ABM.CHART_RATIO_SQUARE, "chart5theme")
   chart5.Visibility = ABM.VISIBILITY_HIDE_ALL
   ' Something special, Label interpolation.  the value will transformed into a percentage format (This is Javascript!)
   Dim SumValues As Int = 30+50+70+80+100+140+170
   chart5.OptionsPie.LabelInterpolation = "Math.round(value / " & SumValues  & " * 100) + '%'"
   ' add ONE serie
   Dim Serie5A As ABMChartSerie
   Serie5A.SetValues(Array As Int(30,50,70,80,100,140,170))
   ' add the chart to the cell
End Sub

' Helper Methods
Sub BuildLabel(internalPage As ABMPage, ID As String, Text As String, Size As String, theme As String, isPrintable As Boolean, Visibility As String) As ABMLabel
   Dim tmpLbl As ABMLabel
   tmpLbl.Initialize(internalPage, ID, Text, Size, False, theme)
   tmpLbl.IsPrintable = isPrintable
   tmpLbl.Visibility = Visibility
   Return tmpLbl
End Sub

It will never be able to print everything of course (e.g. scrolling components), but I’m pretty happy with the things it will be able to do.  Browser support for report printing is still in its infancy I’m afraid and it will take some time before all browsers are lined up supporting all HTML printing features.

But, together with the new ABMreport component, you will already be able to create reports with very little effort using ABMaterial and B4J!

ABMaterial 3.75 will be available for donators in a couple of weeks.


Click here to Donation and support ABMaterial

B4J: IMPORTANT change in ABMaterial for B4J 5.80+

As B4J 5.80 has been updated to Jetty 9.4.6 (which contains an important change in the internal Session framework), you will need to update some code in StartServer() and StartServerHTTP2() in the ABMApplication module.

In pre B4J 5.80 with Jetty 9.3.x it was:

Dim joServer As JavaObject = srvr
joServer.GetFieldJO("server").RunMethod("stop", Null)
joServer.GetFieldJO("context").RunMethodJO("getSessionHandler", Null).RunMethodJO("getSessionManager", Null).RunMethodJO("getSessionCookieConfig", Null).RunMethod("setMaxAge", Array(31536000)) ' 1 year

'NEW FEATURE! Each App has its own Session Cookie
joServer.GetFieldJO("context").RunMethodJO("getSessionHandler", Null).RunMethodJO("getSessionManager", Null).RunMethodJO("getSessionCookieConfig", Null).RunMethod("setName", Array(ABMShared.AppName.ToUpperCase))
joServer.GetFieldJO("server").RunMethod("start", Null)

must be changed to this in B4J 5.80+ with Jetty 9.4.6:

Dim joServer As JavaObject = srvr
joServer.GetFieldJO("server").RunMethod("stop", Null)
joServer.GetFieldJO("context").RunMethodJO("getSessionHandler", Null).RunMethodJO("getSessionCookieConfig", Null).RunMethod("setMaxAge", Array(31536000)) ' 1 year

' NEW FEATURE! Each App has its own Session Cookie
joServer.GetFieldJO("context").RunMethodJO("getSessionHandler", Null).RunMethodJO("getSessionCookieConfig", Null).RunMethod("setName", Array(ABMShared.AppName.ToUpperCase))
joServer.GetFieldJO("server").RunMethod("start", Null)

' + This setting is with reservation until confirmation
Dim secs As Long = ABMShared.CacheScavengePeriodSeconds ' must be defined as a long, else you get a 'java.lang.RuntimeException: Method: setIntervalSec not matched.' error
joServer.GetFieldJO("context").RunMethodJO("getSessionHandler", Null).RunMethodJO("getSessionIdManager", Null).RunMethodJO("getSessionHouseKeeper", Null).RunMethod("setIntervalSec", Array As Object(secs))

This will be corrected in the next upcoming release 3.75 of ABMaterial.


Click here to Donation and support ABMaterial

B4J: ABMaterial 3.20 Public/3.50 Donators Released!

ABMB4JABMaterial 3.50 for B4J introduces Drag & Drop of ABMContainers between Cells! This new feature took a couple of weeks to implement, but I’m proud of the result.
It opens up a whole new range of possibilities for Web Apps.

Not many bug fixing needed in this release. Proves ABMaterial is really stable and truly production ready! (Happy face)

ABMGoogleMap also adds the possibility to use marker clusters, which cleans up your google map if you have many markers in one map.


Head to the ABMaterial section on this blog to get your free copy of 3.20, or make a small donation to support the development and get the latest 3.50 version + 9 extra libraries and tools to use in your own projects!

Have a great summer!


Click here to Donation and support ABMaterial


B4X: ABMaterial 3.03 Public/3.20 Donators released

A lot of internal changes were made in the ABMaterial 3.20 ‘Chipmunk’ release.  For example, ABMContainer has been rewritten from the ground-up, but with minimal impact to your existing projects.  It allows adding them as array components, and has much shorter ID tags in the generated HTML.

Mindful and Stanmiller had another go on the cache issues.  They came up with a very nice solution (I had tears in my eyes) and both have done extensive testing on this subject. A big thanks again!  ABM 3.20 is backwards compatible with the previous 3.0.3 Cache System, but I would advice you to make the changes whenever you have the chance.

A nice new feature for mobile devices is the New Debug feature using a modified version of Conzole!

New Debug at work:

Using this new feature is very simple in B4J:

First, you have to enable the console in BuildPage():

' params are: open on load, width
page.DebugConsoleEnable(True, 300)

Two methods can be used to show or hide the console programmaticaly. Can be handy as a buid-in tool in your apps where the user enters a code on his device and you can then check the console.


Now you can start doing some cool stuff 🙂 Some examples:

Show some text, or a server value (note: strings must be between single quotes!)

page.DebugConsoleLog("'Server click at: " & DateTime.Time(DateTime.Now) & "'") ' shows the text

Now I generated an error on purpose, so the demo can show it catches the error:

page.DebugConsoleLog("'value: ' + $('#pi002-r2c1').html();") ' generates an error, the ; at the end is wrong

Same code, but with the correct javascript syntax, showing the html() value of the tag:

page.DebugConsoleLog("'value: ' + $('#pi002-r2c1').html()") ' generates the html value of the pi002-r2c1 tag

It works also on the desktop, although you probably will use the Chrome console as you can do more.

But there is more. You can also redirect all browser console message directly into the B4J log window!  You can use the following commands anywhere in your own code to start/stop receiving the browser console messages.


This is a very powerful feature if you develop Webapps for mobile devices.  It can be done otherwise, but it is a pain in the a$$ to set it up. Now, you can easily debug it on your iPhone, iPad, Android or any other device.

ABMaterial 3.20 has over 20 new features and bug fixes.  Following the same philosophy as B4X, the quick release cycle has proven to work very well for ABMaterial and its many users.  Donators will receive their download mail shortly.  The public version 3.03 can be downloaded from this blog too.

I’m also glad that with these releases, now everyone can work with ‘Chipmunk‘, and this does also mean the development cycle for ‘Butterfly‘  has ended.

I would like to take this opportunity to thank everyone for the support, hourless testing and inventive ideas you came up with in the last few years. You’ve made ABMaterial one hell of a WebApp Development Tool!


But we are not at the end! Far from it as I already have big ideas for the next releases.

Until then, happy programming!


Click here to Donation and support ABMaterial

B4A: ABFlicB4A library for Flic buttons


You probably have seen these nifty little IoT Flic buttons around. They are a fun and relative cheap BLE button that allows you to do something when the button is clicked, doubleclicked or hold.

I decided to write a wrapper for the Android SDK to use with B4A.

How to use:
1. Install the Flic app from the Google Play.
2. On their developer page, create a new app: you get a key and a secret.
3. Copy the ABFlicB4A library jar and xml to your library folder and select it in B4A

Here is a small video demonstrating the library.  You can the use the full power of B4A to do about, well, everything…

Example usage code:

Sub Process_Globals

End Sub

Sub Globals
   Private flic As ABFlic
   Private Button2 As Button
   Private Button3 As Button
   Private Button4 As Button
   Private Label1 As Label
   Private Button1 As Button

   Private MyFlicID As String

   Private FlicResults As List
End Sub

Sub Activity_Create(FirstTime As Boolean)
End Sub

Sub Activity_Resume
   ' your key and secret
End Sub

Sub Button1_Click
End Sub

Sub Button2_Click
End Sub

Sub Button3_Click
End Sub

Sub Button4_Click
End Sub

Sub flic_Added(buttonID As String, Name As String)
   MyFlicID = buttonID
   Log("Added: " & buttonID)
   Label1.Text = "Added: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Clicked(buttonID As String, wasQueued As Boolean, timeDiff As Int)
   MyFlicID = buttonID
   Log("Clicked: " & buttonID)
   Label1.Text = "Clicked: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_DoubleClicked(buttonID As String, wasQueued As Boolean, timeDiff As Int)
   MyFlicID = buttonID
   Log("DoubleClicked: " & buttonID)
   Label1.Text = "DoubleClicked: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Holded(buttonID As String, wasQueued As Boolean, timeDiff As Int)
   MyFlicID = buttonID
   Log("Holded: " & buttonID)
   Label1.Text = "Holded: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Removed(buttonID As String)
   MyFlicID = ""
   Log("Removed: " & buttonID)
   Label1.Text = "Removed: " & buttonID & CRLF & Label1.Text
End Sub

Sub flic_Error(err As Int)
   Log("Error: " & err)
   Label1.Text = "Error: " & err & CRLF & Label1.Text
End Sub

I’m currently working on a Desktop/Raspberry Pi version of this library, which I will share in the B4J forum later.

The library can be found at the B4A forum.

Happy programming!


B4J: New ABMChat component for ABMaterial 2.50


ABMChat is a new cool looking ABMaterial component to create a Web based chat program. The inner workings are very much like Erels ChatRoom, but with a slick interface. This can be a useful control if for example you want to give chat-like support within you own B4J webapp.

Some features:
– Balloon/Bubble-like chat
– Support for some ASCII emoji
– IsTyping ballon

Coding this with B4J and ABMaterial is very easy:

Code ChatShared module:

Sub Process_Globals
   Public AvoidDuplicates As Map
   Private connections As Map
   Public LastMessages As List
   Private IsTypingMap As Map
End Sub

public Sub Init
   AvoidDuplicates = Main.srvr.CreateThreadSafeMap
End Sub

public Sub NewConnection(page As ChatPage, pageID As String)
   DateTime.TimeFormat = "HH:mm"

   Dim IdentifyBubble As ABMChatBubble
   IdentifyBubble.Initialize("Server", page.ChatName & " has joined the chat...", "Server " & DateTime.Time(DateTime.Now), "server", "server")
   JoinLeftMessage(pageID, IdentifyBubble)
   connections.Put(pageID, page)
   CallSubDelayed2(page, "CurrentConversation", LastMessages)
End Sub

public Sub NewMessage(pageID As String, Message As ABMChatBubble)
   For Each page As ChatPage In connections.Values
     CallSubDelayed2(page, "NewMessage", Message)
End Sub

public Sub JoinLeftMessage(pageID As String, Message As ABMChatBubble)
   For Each page As ChatPage In connections.Values
     CallSubDelayed2(page, "NewMessage", Message)
End Sub

public Sub IsTyping(pageID As String, Value As String)
   Dim typeBool As Boolean
   If Value = "" Then
     IsTypingMap.put(pageID.ToLowerCase, "true")
   End If
   If IsTypingMap.Size > 0 Then
     typeBool = True
   End If
   For Each page As ChatPage In connections.Values
     CallSubDelayed3(page, "IsTyping", pageID, typeBool)
End Sub

public Sub Disconnected(page As ChatPage, pageID As String)
   If connections.ContainsKey(pageID) = False Or connections.Get(pageID) <> page Then Return
   Dim LeaveBubble As ABMChatBubble
   LeaveBubble.Initialize("Server", page.ChatName & " has left the chat...", "Server " & DateTime.Time(DateTime.Now), "server","server")
   JoinLeftMessage(pageID, LeaveBubble)
End Sub

Public Sub HasIdentified(pageID As String) As Boolean
   Return connections.ContainsKey(pageID)
End Sub

Relevant Code ChatPage class:

Private Sub WebSocket_Disconnected
   If ABMPageId <> "" Then CallSubDelayed3(ChatShared, "Disconnected", Me, ABMPageId)
End Sub

public Sub BuildTheme()
   ' start with the base theme defined in ABMShared

   ' add additional themes specific for this page
   theme.Chat("myChat").Bubble("server").Color = ABM.COLOR_BLACK
   theme.Chat("myChat").Bubble("server").TextColor = ABM.COLOR_WHITE

   theme.Chat("myChat").Bubble("me").Color = ABM.COLOR_LIGHTBLUE
   theme.Chat("myChat").Bubble("me").TextColor = ABM.COLOR_WHITE

   theme.Chat("myChat").Bubble("them").Color = ABM.COLOR_GREY
   theme.Chat("myChat").Bubble("them").ColorIntensity = ABM.INTENSITY_LIGHTEN2
   theme.Chat("myChat").Bubble("them").TextColor = ABM.COLOR_BLACK
End Sub

public Sub ConnectPage()
'   connecting the navigation bar    

'   init all your own variables (like a List, Map) and add your components
   Dim chat As ABMChat
   chat.Initialize(page, "conversation",600, 450, 255, "mychat")
   chat.AddBubble("Server", "I'm Server, what is your name?", "The Server", "server", "server")


   Dim ChatInput As ABMInput
   ChatInput.Initialize(page, "ChatInput", ABM.INPUT_TEXT, "", False, "")
   ChatInput.PlaceHolderText = "Type your message here...."
   ChatInput.RaiseChangedEvent = True

   ' refresh the page
   ' Tell the browser we finished loading
   ' restoring the navigation bar position
End Sub

Sub ChatInput_Changed(value As String)
   If ChatShared.HasIdentified(ABMPageId) Then
     CallSubDelayed3(ChatShared, "IsTyping", ABMPageId, value)
   End If
End Sub

Sub ChatInput_EnterPressed(value As String)
   DateTime.TimeFormat = "HH:mm"

   If ChatShared.HasIdentified(ABMPageId) Then
     Dim bubble As ABMChatBubble
     bubble.Initialize(ChatName, value, ChatName & " " & DateTime.Time(DateTime.Now), "me", "them")
     CallSubDelayed3(ChatShared, "NewMessage", ABMPageId, bubble)
     CallSubDelayed3(ChatShared, "IsTyping", ABMPageId, "")
     If value = "" Then Return
     If ChatShared.AvoidDuplicates.ContainsKey(value.ToLowerCase) Then
       Dim chat As ABMChat = page.Component("conversation")
       chat.AddBubble("Server", "Sorry, but " & value & " is already taken!", "The Server", "server", "server")
       ChatName = value
       ChatShared.AvoidDuplicates.Put(value.ToLowerCase, value)
       Dim chat As ABMChat = page.Component("conversation")
       chat.AddBubble("Server", "Welcome to ABMChat " & ChatName & "!", "The Server", "server", "server")
       CallSubDelayed3(ChatShared, "NewConnection", Me, ABMPageId)
     End If
   End If

   Dim ChatInput As ABMInput = page.Component("ChatInput")
   ChatInput.Text = ""
End Sub

public Sub NewMessage(bubble As ABMChatBubble)
   Dim chat As ABMChat = page.Component("conversation")
   chat.ScrollToBottom   ' scroll to the end of the chat
End Sub

public Sub IsTyping(pageID As String, typeBool As Boolean)
   Dim chat As ABMChat = page.Component("conversation")
   If pageID <> ABMPageId Then
     If typeBool = False Then
       chat.ThemAreTyping(False, "") 'hide the 'is typing' bubble
       chat.ThemAreTyping(True, "") ' show the 'is typing' bubble if not yet shown
     End If
     chat.ScrollToBottom   ' scroll to the end of the chat
   End If
End Sub

public Sub CurrentConversation(LastMessages As List)
   If LastMessages.Size > 0 Then
     Dim chat As ABMChat = page.Component("conversation")
     chat.ScrollToBottom   ' scroll to the end of the chat
   End If
End Sub

So, there you have it. A complete modern looking multichat webapp that runs on all platforms in just about 150 lines of code!


Click here to Donation and support ABMaterial

B4J: ABMaterial Public 1.22/Donators 2.00 now released

It has been a long night to get everything ready, but I’m happy to release the new version(s) of ABMaterial for B4J!

2.00 is a major release.  Lots of new stuff and some changes that were really needed in preparation of the upcoming (ABMaterial Abstract Desinger) ABMAD tool.

Highlights of the releases:

1.22: New component ABMPatternLock

ABMPatternLock is yet another authentication method you can use based on the popular Pattern Lock you see in e.g. Android.


1.22: ABMContainer can collapse

ABMContainer can be initialized as a collapsable component.  As a collapsable has a header and a body and clicking on the header will collapse/expand the body.  This can be used as an alternative for an ABMCard so you can build your own.

1.22: Support for Font-Awesome icons

If you set: page.UseFontAwesome = true then you can, next to the material icons, also use the Font Awesome Icon library (634 icons in used version Font Awesome 4.6.3)
See for a list of icons.


2.00: New component ABMChronologylist

The ABMChronologyList is a vertical timeline component. Useful to give an overview of a limited period. It is device aware so e.g. on a phone, all items will be one under each other.


2.00: New helper ABMSideBar

In ABMaterial 2.00, you will be able to define multiple side bars (sliding in from the right). I’ve tried to mimic the usage of ABMSideBar as much of the existing Side Navigation menu. The tricky part was making it work well with the NavigationBar, on all screensizes.

Check out the online demo or download your free copy from the B4J website.  Make sure you read the included README.TXT files.  It contains some important info and shows some tips and tricks.

That’s it for now.  Next big release will be all about ABMAD. Until next time!


Click here to Donation if you like my work

B4J: ABMaterial Public 1.12/Donators 1.20 now released

So, what happened to 1.09, 1.10 and 1.11?
Version 1.09 does not exist. I’ve changed it to 1.10 so I can use the major number as the main release update and the minor number for maintenance releases. e.g. maintenance releases for 1.10 are 1.11,1.12, etc… The next big release is 1.20.

Highlights of the releases:

All components are fully dynamic

In a ‘static’ page, all the components are written in the .html file. In a ‘dynamic’ page they are not. Only when you connect as a user, the components are inserted in their browser.

This seems trivial, but this actually means we can ‘write’ components (html, css and javascript) at run-time, depending on e.g. the user that logged in. Some user is allowed to see one chart, another user another chart. Or one may be able to delete a record from your database, another is not. Or showing a certain modal sheet depending on the user without having to add all possibilities in the HTML. Or show the page in different languages depending on who logged in!

New component ABMTimeLine

ABMTimeline is a component to present a time line of events. Using the ABMTimeLineElement you can create events, with some assets like images.


New component ABMFlexWall

ABMFlexWall is a simple galarie component for images.  Together with the IsMaterialBoxed=true setting, it creates an easy to use image wall.


Speed, the need for speed…

Following all the guidelines of Google, ABMaterial is one of the fastest framesworks around.  Not only in time of development, but this is certainly the case for the user experience. And all done in the background for you!


Firebase Auth and Storage support (1.20)

ABMaterial is always on top of new technologies.  Latest in line is support of Googles Firebase API. You can use Firebase Auth to login to your ABMaterial (1.20) WebApp and with Storage, you can upload/download files with ease. Together with B4X Firebase support, you can build the most powerful apps ever.

New components ABMSVGSurface, ABMFileInput, ABMTableMutable and ABMPatternLock (1.20)

Always on the move, new components are introduced with every release.  Donators can find more info on these new components in their mail.  More on this blog when 1.20 is released to the public.

So check out the online demo or download your free copy from the B4J website

Until next time!


Click here to Donation if you like my work


B4J: ABTelegram bots library

Bots are the next hot thing in 2016! So in my spare-spare time I’ve been working on a wrapper for the Telegram API v2.0. It has a rather unconventional API but I’m reworking it to make it very easy to write bots in B4J.

Bots could be very useful as yet another way to ‘talk’ with IoT devices. You can control LEDs, temperatures, ask for stats etc right from within the Telegram Chat App (which runs on about every kind of platform, being the desktop, a browser, iOS, Android, etc…). Or you can, like I did to test the wrapper, write a little game:


Note: this library is in very early stages so the wrapper is not available for download yet. Full source code of the game will also be available when released.

Some sample code to show you how easy it is to write a bot in B4J (this is not the game code, just some tests):

Code to initialize the library:

Sub Process_Globals
   Dim ABT As ABTelegram
End Sub

Sub AppStart (Args() As String)
   Dim b As MyBot

End Sub

Code for the Bot:

'Class module
Sub Class_Globals
Dim ABT As ABTelegram
Public Bot As ABTLongPollingBot
Private botToken As String = &quot;207189xxxx:yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy&quot;
Private botUserName As String = &quot;zzzzzzzzzBot&quot;
'Private callbackCounter As Int
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
Bot.Initialize(&quot;Bot&quot;, Me, botToken, botUserName)
Dim upds As List = Bot.botgetUpdates
For i = 0 To upds.Size - 1
Dim upd As ABTUpdate = upds.Get(i)
Log(&quot;Go update: &quot; &amp; upd.UpdateId)
End Sub

Sub Bot_UpdateReceived(update As ABTUpdate)
Log(&quot;Got an update&quot;)
If update.hasMessage Then
Dim msg As ABTMessage = update.GetMessage
Log(&quot;Message: &quot; &amp; msg.Text)

'        Dim userPhotos As ABTUserProfilePhotos = Bot.BotGetUserProfilePhotos(
'        Log(&quot;photos: &quot; &amp; userPhotos.TotalCount)
'        Dim Photos As List = userPhotos.Photos
'        For i = 0 To Photos.Size - 1
'            Dim photoSizes As ABTPhotoSizes = Photos.Get(i)
'            For j = 0 To photoSizes.Sizes.Size - 1
'                Dim photoSize As ABTPhotoSize = photoSizes.Sizes.Get(j)
'                Dim photoFile As ABTFile = Bot.BotGetFile(photoSize.FileId)
'                Log(photoFile.FilePath)
'                Dim job1 As HttpJob
'                job1.Initialize(&quot;Job&quot; &amp; j, Me)
'                job1.Tag = photoFile.FilePath.Replace(&quot;photo/&quot;, &quot;&quot;)
'                Dim url As String = &quot;; &amp; botToken &amp; &quot;/&quot; &amp; photoFile.FilePath
'                   job1.Download(url)
'               Next
'        Next

'        callbackCounter = callbackCounter + 1
'        Bot.BotSendMessageAsync(callbackCounter, msg.ChatId, &quot;Alweer hallo &quot; &amp; msg.Chat.FirstName)

Bot.BotSendMessage(msg.ChatId, &quot;Using an Emoji &quot; &amp; &quot;:grinning: in the message!&quot;) ' see for a list of emojis

'        Bot.BotSendPhoto(True, msg.ChatId, File.DirApp &amp; &quot;/&quot; &amp; &quot;telegram.png&quot;)

'        callbackCounter = callbackCounter + 1
'        Bot.BotSendDocumentAsync(callbackCounter, True, msg.ChatId, File.DirApp &amp; &quot;/&quot; &amp; &quot;mydocument.pdf&quot;, &quot;mydocument.pdf&quot;)

'        Bot.BotSendDocument(True, msg.ChatId, File.DirApp &amp; &quot;/&quot; &amp; &quot;mydocument.pdf&quot;, &quot;mydocument.pdf&quot;)

Bot.BotSendAudio(True, msg.ChatId, File.DirApp &amp; &quot;/&quot; &amp; &quot;myaudio.mp3&quot;)

'        Bot.BotSendVideo(True, msg.ChatId, File.DirApp &amp; &quot;/&quot; &amp; &quot;myvideo.mp4&quot;)

'        Bot.BotSendSticker(True, msg.ChatId, File.DirApp &amp; &quot;/&quot; &amp; &quot;mysticker.webp&quot;)

'        Bot.BotSendContact(msg.ChatId, &quot;+32496000000&quot;, &quot;Alain&quot;)

'        Bot.BotSendChatAction(msg.ChatId, ABT.CHATACTIONTYPE_TYPING)

'        Bot.BotSendLocation(msg.ChatId, 50.8492, 2.8779)

'        Bot.BotSendVenue(msg.ChatId, 50.8492, 2.8779, &quot;my venue&quot;, &quot;Grote markt 1&quot;)

Bot.BotSendVoice(True, msg.ChatId, File.DirApp &amp; &quot;/&quot; &amp; &quot;telegram.ogg&quot;)

'        Dim keyb As ABTReplyKeyboard
'        Dim rows As List
'        rows.Initialize
'        Dim tmpRow As ABTInlineKeyboardRow
'        tmpRow.Initialize
'        tmpRow.AddButton(&quot;test button&quot;, &quot;;, &quot;&quot;, &quot;&quot;)
'        rows.Add(tmpRow)
'        keyb.InitializeAsInlineKeyboardMarkup(rows)
'        Bot.BotEditMessageTextEx(msg.ChatId, msg.MessageId, 0, &quot;Extended test&quot;, ABT.PARSEMODE_HTML, False, keyb)

Dim rkeyb As ABTReplyKeyboard
Bot.BotSendMessageEx(msg.ChatId, &quot;some test: reply please&quot;, ABT.PARSEMODE_HTML, False, False, 0, rkeyb)

'        Dim rkeyb2 As ABTReplyKeyboard
'        Dim rows2 As List
'        rows2.Initialize
'        For i = 1 To 100
'            Dim tmpRow2 As ABTKeyboardRow
'            tmpRow2.Initialize
'            tmpRow2.AddButton(&quot;Press me&quot;)
'            rows2.Add(tmpRow2)
'        Next
'        rkeyb2.InitializeAsReplyKeyboardMarkup(rows2,False, False, False)
'        Bot.BotSendMessageEx(msg.ChatId, &quot;some test: press the button&quot;, ABT.PARSEMODE_HTML, False, False, 0, rkeyb2)

'        Dim rkeyb3 As ABTReplyKeyboard
'        Dim rows3 As List
'        rows3.Initialize
'        Dim tmpRow3 As ABTInlineKeyboardRow
'        tmpRow3.Initialize
'        tmpRow3.AddButton(&quot;Show image&quot;, &quot;&quot;, &quot;showimage&quot;, &quot;&quot;)
'        rows3.Add(tmpRow3)
'        rkeyb3.InitializeAsInlineKeyboardMarkup(rows3)
'        Bot.BotSendMessageEx(msg.ChatId, &quot;some test: press the button&quot;, ABT.PARSEMODE_HTML, False, False, 0, rkeyb3)
End If
If update.hasCallbackQuery Then
Dim cquery As ABTCallbackQuery = update.GetCallbackQuery
Log(&quot;CallbackQuery: &quot; &amp;
Select Case cquery.Data
Case &quot;showimage&quot;
Dim msg As ABTMessage = cquery.Message

Bot.BotSendPhotoEx(True, msg.ChatId , File.DirApp &amp; &quot;/&quot; &amp; &quot;myphoto.jpg&quot;, &quot;A new photo of darth vader!&quot;,False, 0, Null )
Bot.BotSendLocation(msg.ChatId, 50.8492, 2.8779)
Bot.BotEditMessageText(msg.ChatId, msg.MessageId, &quot;&quot;, &quot;Shown&quot;)
End Select
End If
If update.hasInlineQuery Then
Dim ciquery As ABTInlineQuery = update.GetInlineQuery
Log(&quot;InlineQuery: &quot; &amp; ciquery.Query)
If ciquery.Query = &quot;loc&quot; Then
Dim lstResults As List
Dim myanswer As ABTInlineQueryResult
myanswer.InitializeAsLocation(&quot;1&quot;, 50.8492, 2.8779, &quot;Your location&quot;)
Bot.BotAnswerInlineQuery(ciquery.Id, lstResults)
End If
End If
If update.hasChosenInlineResult Then
Dim ccresult As ABTChosenInlineResult = update.GetChosenInlineResult
Log(&quot;ChosenInlineResult: &quot; &amp; ccresult.Query)
End If
End Sub

Sub Bot_AsyncSendReceived(methodType As String, callbackId As String, success As Boolean, asyncObject As ABTObject)
Log(&quot;Async method: &quot; &amp; callbackId &amp; &quot; &quot; &amp; methodType &amp; &quot; &quot; &amp; success)
If success And asyncObject &amp;lt;&amp;gt; Null Then
If asyncObject.objectType=&quot;ABTMessage&quot; Then
Dim message As ABTMessage = asyncObject
Log(&quot;Async callback: &quot; &amp; message.MessageId)
End If
End If
End Sub

Sub JobDone (Job As HttpJob)
Log(&quot;JobName = &quot; &amp; Job.JobName &amp; &quot;, Success = &quot; &amp; Job.Success)
If Job.Success = True Then
Dim fSave As OutputStream = File.OpenOutput(File.DirApp, Job.tag, False)
File.Copy2(Job.GetInputStream, fSave)
Log(&quot;Error: &quot; &amp; Job.ErrorMessage)
End If
End Sub


Click here to Donation if you like my work


B4J: ABMaterial Public 1.07/Donators 1.08 now released

ABMaterial public version 1.07 is now available from the B4J website!

What’s new:

ABMGenerator object: allows generating CRUD and messagebox modal sheets fast

Given a set of parameters in a couple of lines of code, ABMGenerator can generate several hundreds of lines of B4J code that only need to be tuned by the programmer to its specific wishes.

Refer to this post for more info.

Infinite Scrolling pages (e.g. like Twitter or Facebook)

With just a couple of lines code, you can create Infinite Scrolling Pages with ABMaterial.

See this post for more info and a demo.

Support for Google Analytics

more info and a tutorial, check out this previous article.

New component ABMSocialShare



New component ABMEditor


Read the README1.07.TXT for the full release notes.

Download ABMaterial Public version 1.07

Version 1.08 is going to be all about speed! But I’ll post a seperate article on my experiences here later on this. A couple of new components off course and some new functionalities in the ABMNavigationBar. Donators should have received this version by now. (mail me if you didn’t).


Click here to Donation if you like my work


B4R (Basic4Arduino) is coming!

Excellent news from Erel (CEO of Anywhere Software).  The excellent B4X suite will support yet another platform: Arduino!  Next to support for all desktop platforms, webapps, Raspberry Pi, Android and iOS this new addition is another great step from Anywhere Software towards the most simple framework to make IoT applications.

Unlike the other platforms which generate Java, B4R will generate native C.  Users will be able to write their own libraries or use inline C for specific functionalities.  More on this later, but make sure you check out the video!



B4i: Official release at special introductory price!

B4I logo
Great news from Anywhere Software! B4i (a development tool for native iOS applications) is released today.

I had good hopes we would have an early Christmas this year from Erel, but it looks like he has outdone himself (again!).

From its beta release only a couple of weeks ago, B4i looked very stable and already feature rich. Knowing how the B4A (Basic4Android) community quickly has grown very solid, with many contributors creating all kind of great libraries, I have no doubt B4i will be any different. Congratulations Erel with another state-of-the-art development tool!

But let’s give the master himself the stand now (from the official site):

Erel: B4i follows the same concepts of B4A and B4J and provides a simple yet powerful rapid application development tool for iOS applications.


– Apple developer account (costs $99 per year).
– An iOS device running iOS 7+.

The compilation process requires a Mac computer. You can either use a local Mac computer or use our Hosted Mac Builder service (currently costs $25 per year).


– Tutorials:
You should start with the following three tutorials:
Creating a certificate and provisioning profile
Installing B4i-Bridge and debugging first app
Developers who use a local Mac: Local Mac Builder Installation

– Formal documentation:


B4i can be purchased from the Anywhere Software Store for just $59!
B4i includes two years of free upgrades.

Hosted Mac Builder

The builder service allows you to develop iOS applications without a Mac computer.
All of the development steps can be done with the builder service except of the final step which is uploading the application to Apple App Store. This step requires a Mac or a service such as MacInCloud.
Note that the builder is currently limited to projects of up to 15mb.

Looking forward to play with this!

B4i: First B4i app in Apple App Store

First B4i App in the store!
Breaking News! Erel has put up the first B4i app on the Apple App Store. I have a feeling we won’t have to wait much longer until we can build iOS apps in this wonderful tool.

While Xojo keeps saying ‘it’s ready when it’s ready’ (it’s getting old Xojo…), B4i is going to take the world by storm! Tools by Anywhere Software have proven to be very stable and production ready by its first releases, so you better start thinking what your first app written in B4i will be like. I know I am…

You can download the app from the store here.

Realy looking forward for this one! I may even buy my first iPhone just to be able to play with it #ChuckleByMyFriends