My experience converting FF/PB to PureBasic

Started by David Chisholm, April 23, 2015, 11:03:45 PM

Previous topic - Next topic

David Chisholm

Folks,

I finally bit the bullet and converted one of my larger, data-intensive, applications from FF/PB to PureBasic.  It was bit of an adventure and learning curve.

The forms designer with PureBasic is pretty basic and don't try to put any additional code within the generated form code as it will be deleted when you compile the code!

The variable typing is a pain "Dim abc As Long" becomes "Define abc.l"

Procedures have to appear before the main code or be declared above the main code or you will get syntax errors.

The Structure notation is a bit different in that you use a "\" instead of "." to select the component with the structure.

Strings within the structures do not have to be pre-sized (a good thing!).

I really liked the integrated debugger which works quite well.

I basically cut and pasted my code from FF/PB and edited to meet the new syntax and order.

The result was a slightly larger executable 179 KB versus 161 KB but there was no need to provide any additional library files (just the executable).

In terms of performance, the new code ran 175% faster than the FF/PB code.

The code involved loading a large flat file (500 MB), doing 4 quick sorts on it and then outputting it into a smaller set of 79 output files based upon the sort criteria and some other flags found within the data.

There is a free book called "Purebasic - A Beginner's Guide to Computer Programming" by Gary Willoughby that I found very helpful (http://www.purearea.net/pb/download/PureBasicBook.pdf).

/Dave
/Dave Chisholm

Paul Squires

Hi David,

Thanks for sharing your PureBasic experience :)

I have not used PureBasic. I think that I feel comfortable enough now with FreeBasic that I will stick with that language. I know many PowerBasic'ers who have switched to PureBasic and I think they are enjoying the experience.

Paul Squires
PlanetSquires Software

Israel Vega Alvarez

I'm fascinated using PureBasic...It has many benefits ... and is cross platform.
To handle images (PNG, JPG etc.),   using database SQLITE 3.    It's a beauty. 

It would be great to have a version of FireFly for PureBasic.


This code is for make a application:

XIncludeFile "C:\PUREBASIC5\CSGRID\CSGRID.pbi"
XIncludeFile "MENU.pbf"

IncludeFile "C:\PUREBASIC5\buttonscool\buttonscool.pbi"

;Agrega Control Grid
WindowID = #Window_0 ; NEW !!! - This must be defined for CS-Grid, as it can now be on several windows.


UsePNGImageDecoder()



OpenWindow_0()

;If #Window_0
;  MessageRequester("dd","EEE",0)
 
  UseGadgetList(WindowID(WindowID))
 
  TEST = CSGridGadget(#PB_Any,10,10,620,200,10,100) ; Creates a CS-Grid-Gadget
  ;MessageRequester("DDD",Str(TEST),0)
  CSGridGadget_SetAutoRedraw(TEST,1)             ; Turns off Auto-Redraw for Grid 1 for faster setup
  CSGridGadget_SetColCaptionVisibility(TEST,0)    ; Shows a column header (default empty caption)

  CSGridGadget_SetColCaptionVisibility(TEST,0)    ; Shows a column header (default empty caption)
  CSGridGadget_SetColCaption(TEST,0,"String")     ; Defines custom header Labels for all Columns
  CSGridGadget_SetColCaption(TEST,1,"Long")       ; Defines custom header Labels for all Columns
  CSGridGadget_SetColCaption(TEST,2,"Float")      ; Defines custom header Labels for all Columns
  CSGridGadget_SetColCaption(TEST,3,"Formatted")  ; Defines custom header Labels for all Columns
  CSGridGadget_SetColCaption(TEST,4,"Percentage") ; Defines custom header Labels for all Columns
  CSGridGadget_SetColCaption(TEST,5,"US Dollars") ; Defines custom header Labels for all Columns
  CSGridGadget_SetColCaption(TEST,6,"User Fmt")   ; Defines custom header Labels for all Columns

  CSGridGadget_SetRowCaptionVisibility(TEST,1)    ; Shows a row header (default numbered caption)

  CSGridGadget_SetColWidth(TEST,2,100)            ; Defines Column-Width for Column 2
  CSGridGadget_SetColWidth(TEST,3,100)            ; Defines Column-Width for Column 3
  CSGridGadget_SetColWidth(TEST,5,100)            ; Defines Column-Width for Column 5
  CSGridGadget_SetColWidth(TEST,6,100)            ; Defines Column-Width for Column 6

  CSGridGadget_SetColDataType(TEST,0,0)           ; Defines Output-Type to Text for Column 0
  CSGridGadget_SetCellValue(TEST,0,0,"testING")   ; Defines new Content for Cell C:0 R:0
  CSGridGadget_SetColInputType(TEST,0,32)         ; Defines Input via Rollup (values-list) for Column 0
  CSGridGadget_SetColInputRessource(TEST,0,"Input 1"+Chr(13)+Chr(10)+"Input 2"+Chr(13)+Chr(10)+"Input 3") ; Defines a values list with 3 values (separated with CHR(13)+CHR(10)) for Column 0
 
  CSGridGadget_SetColDataType(TEST,1,1)           ; Defines Output-Type to Long Integer for Column 1
  CSGridGadget_SetCellValue(TEST,1,0,"654924")    ; Defines new Content for Cell C:1 R:0 
 
  CSGridGadget_SetColDataType(TEST,2,16)          ; Defines Output-Type to Float for Column 2
  CSGridGadget_SetCellValue(TEST,2,0,"139.6548")  ; Defines new Content for Cell C:2 R:0 
  CSGridGadget_SetColSummary(TEST,2,1)                   ; Defines Column-Summary

  CSGridGadget_SetColDataType(TEST,3,17)          ; Defines Output-Type to Formatted Fload, 2 decimals places
  CSGridGadget_SetCellValue(TEST,3,0,"1221.105")   ; Defines new Content for Cell C:3 R:0 
 
  CSGridGadget_SetColDataType(TEST,4,64)          ; Defines Output-Type to Percentage, 4 decimals places
  CSGridGadget_SetCellValue(TEST,4,0,"0.456789")  ; Defines new Content for Cell C:3 R:0 

  CSGridGadget_SetFormatComma(TEST,".")           ; Enables support for US/UK-style comma-symbol
  CSGridGadget_SetColDataType(TEST,5,33)          ; Defines Output-Type to US Dollars, 2 decimals places
  CSGridGadget_SetCellValue(TEST,5,0,"150286")  ; Defines new Content for Cell C:3 R:0 

  CSGridGadget_SetColDataType(TEST,6,127)          ; User defined Output-Type
  CSGridGadget_SetColUserNumberFormat(TEST,6,"#######0.00") ; Defines User-Output-Type for Column 3
  CSGridGadget_SetCellValue(TEST,6,0,"1502.86")  ; Defines new Content for Cell C:3 R:0 

  CSGridGadget_SetColDataType(TEST,7,2)          ; Boolean
; CSGridGadget_SetCellLockStatus(TEST,7,2,-16)    ; Locks Cell C:2 R:2 for access (and input)

  CSGridGadget_SetCellValue(TEST,2,1,"No Access") ; Defines new Content for Cell C:2 R:1
 
; CSGridGadget_SetCellLockStatus(TEST,2,2,-16)    ; Locks Cell C:2 R:2 for access (and input)

  CSGridGadget_SetCellValue(TEST,3,3,"No Edit")   ; Defines new Content for Cell C:3 R:3

  ;CSGridGadget_SetCellLockStatus(TEST,3,3,-1)     ; Locks Cell C:3 R:3 for input
  CSGridGadget_SetColsUserSort(TEST,1)                   ; Activates user sorting via double-click on column headder
 
  CSGridGadget_SetAutoRedraw(TEST,1)              ; Turns on Auto-Redraw for Grid 1 for faster setup
CSGridGadget_SetColCaptionVisibility(TEST,1)    ; Shows a column header (default empty caption)   
 
;EndIf


SetGadgetText(text_0,"VALOR:")

       If Not(is_jelly_button(BTN_IMG_ACTUALIZARCATALOGO))
           Add_Some_Jelly(BTN_IMG_ACTUALIZARCATALOGO, 10)
            set_jelly_text_color(BTN_IMG_ACTUALIZARCATALOGO, #Blue)
            set_jelly_shadow_color(BTN_IMG_ACTUALIZARCATALOGO, #Green )
            Spread_Jelly(BTN_IMG_ACTUALIZARCATALOGO, RGB(255,155,255))
          EndIf
         
       If Not(is_jelly_button(TEXT_0))
           Add_Some_Jelly(TEXT_0,100)
            set_jelly_text_color(TEXT_0, #Blue)
            set_jelly_shadow_color(TEXT_0, -2)
            Spread_Jelly(TEXT_0, -2)
       EndIf
         



      If Not(is_jelly_button(ButtonIMAGE_1))
           Add_Some_Jelly(ButtonIMAGE_1, 10)
            set_jelly_text_color(ButtonIMAGE_1, #Blue)
            set_jelly_shadow_color(ButtonIMAGE_1, #Green )
            Spread_Jelly(ButtonIMAGE_1, RGB(0,155,255))
       EndIf
           
         
     If Not(is_jelly_button(BTN_IMG_SALIR))
           Add_Some_Jelly(BTN_IMG_SALIR, 10)
            set_jelly_text_color(BTN_IMG_SALIR, #Red)
            set_jelly_shadow_color(BTN_IMG_SALIR, #Black) 
            Spread_Jelly(BTN_IMG_SALIR, RGB(100,155,255))
      EndIf

     
     
     
     
   Repeat
   
   
   Event = WaitWindowEvent()
   
         CSGridGadget_EventHandling(Event); Processes all Grid-Gadget events (for all CS-Grid-Gadgets)                                   
         Window_0_Events(Event) ; This procedure name is always window name followed by '_Events'
   Select Event
       
   Case #Window_0
     ;Window_0_Events(Event) ; This procedure name is always window name followed by '_Events'
       
     Case #PB_Event_Gadget
       
       Select EventGadget()
         
             Case Window_0
               Select EventType()
                 Case #PB_EventType_LeftClick        : Debug "Click with left mouse button"
                 Case #PB_EventType_RightClick       : Debug "Click with right mouse button"
                 Case #PB_EventType_LeftDoubleClick  : Debug "Double-click with left mouse button"
                 Case #PB_EventType_RightDoubleClick : Debug "Double-click with right mouse button"
               EndSelect
               
               
             Case TEST
               Select EventType()
                 Case #PB_EventType_LeftClick        : Debug "Click with left mouse button"
                 Case #PB_EventType_RightClick       : Debug "Click with right mouse button"
                 Case #PB_EventType_LeftDoubleClick  : Debug "Double-click with left mouse button"
                 Case #PB_EventType_RightDoubleClick : Debug "Double-click with right mouse button"
               EndSelect
               
               
             Case BTN_IMG_ACTUALIZARCATALOGO
               Select EventType()
                 Case #PB_EventType_LeftClick        : Debug "Click with left mouse button"
                 Case #PB_EventType_RightClick       : Debug "Click with right mouse button"
                 Case #PB_EventType_LeftDoubleClick  : Debug "Double-click with left mouse button"
                 Case #PB_EventType_RightDoubleClick : Debug "Double-click with right mouse button"
               EndSelect
               
             Case BTN_IMG_SALIR
               Select EventType()
                 Case #PB_EventType_LeftClick        : Break ;Debug "Click with left mouse button"
                 Case #PB_EventType_RightClick       : Debug "Click with right mouse button"
                 Case #PB_EventType_LeftDoubleClick  : Debug "Double-click with left mouse button"
                 Case #PB_EventType_RightDoubleClick : Debug "Double-click with right mouse button"
               EndSelect
               
               
               
           EndSelect   
               
               
       
       
       
    EndSelect
   
  Until Event = #PB_Event_CloseWindow ; Quit on any window close
  CSGridGadget_FreeGadget(TEST)
     
 



This code is for use SQLITE 3


UseSQLiteDatabase()

Procedure CheckDatabaseUpdate(Database, Query$)
   Result = DatabaseUpdate(Database, Query$)
   If Result = 0
      Debug DatabaseError()
   EndIf
   
   ProcedureReturn Result
EndProcedure

DatabaseFile$ = GetCurrentDirectory()+"TARCAL.DAT"

If CreateFile(0, DatabaseFile$)
   CloseFile(0)
   
   If OpenDatabase(0, DatabaseFile$, "", "")
   
      CheckDatabaseUpdate(0, "CREATE TABLE TARJETAS(CODIGO VARCHAR(10),NOMBRE VARCHAR(80),FECHAREC CHAR(10),FECHAENT CHAR(10))")

      For X=1 To 100000
        CheckDatabaseUpdate(0, "INSERT INTO TARJETAS(CODIGO, NOMBRE, FECHAREC, FECHAENT) VALUES ('"+Str(X)+"', 'NOMBRE"+Str(X)+"','2015-01-01','2015-01-02')")
      Next X

           
      If DatabaseQuery(0, "SELECT * FROM TARJETAS")
        ;FirstDatabaseRow(0)
     
         While NextDatabaseRow(0)
            Debug GetDatabaseString(0, 1)
         Wend
     
         FinishDatabaseQuery(0)
      EndIf
     
      CloseDatabase(0)
   Else
      Debug "Can't open database !"
   EndIf
Else
   Debug "Can't create the database file !"
EndIf


Israel Vega Alvarez

And for open a database of MS Access with this simple code:


EnableExplicit

#ODBC_ADD_DSN = 1
#ODBC_CONFIG_DSN = 2
#ODBC_REMOVE_DSN = 3
#ODBC_ADD_SYS_DSN = 4
#ODBC_CONFIG_SYS_DSN = 5
#ODBC_REMOVE_SYS_DSN = 6
#ODBC_REMOVE_DEFAULT_DSN = 7

Procedure AddConnection(Driver$,ConnectString$)
   ProcedureReturn SQLConfigDataSource_(0,#ODBC_ADD_DSN,Driver$,ConnectString$)
EndProcedure

Procedure RemoveConnection(Driver$,DSN$)
   ProcedureReturn SQLConfigDataSource_(0,#ODBC_REMOVE_DSN,Driver$,"DSN=" + DSN$)
EndProcedure

UseODBCDatabase()

Define Result
Define DSN$ = "MYACCESSDB"
Define Database$ = "C:\RADBUILDER\APFONACOT\APFONACOT.mdb"  ; folder+name of your Access file
Define UserID$ = ""
Define Password$ = ""
Define Table$ = "CEDULA"
Define Column$ = "NOMBRE"

Result = AddConnection("Microsoft Access Driver (*.mdb, *.accdb)","Server=127.0.0.1;Description=My ODBC Access;DSN=" + DSN$ + ";DBQ=" + Database$ + ";UID=" + UserID$ + ";PWD=" + Password$ + ";")

If Result
   Result = OpenDatabase(0,DSN$,"","")
   
   If Result
      If DatabaseQuery(0,"SELECT " + Column$ + " FROM " + Table$)
       
         While NextDatabaseRow(0)
            Debug GetDatabaseString(0, 0)
         Wend
     
         FinishDatabaseQuery(0)
      EndIf

      CloseDatabase(0)
   EndIf
EndIf

RemoveConnection("Microsoft Access Driver (*.mdb, *.accdb)",DSN$)


PureBasic is very good...but It does not have a good visual designer how Firefly.

José Roca

SQLConfigDataSource is not something privative to PureBasic. It is an API function of the ODBC driver that you can call with any compiler.

Bob Houle

Yes, that's true Jose, but the nice thing is that this is a "complete" compile-able example with no 'Include' file necessary.

PureBasic has built-in the Win API definitions... so all you have to do is add an '_' after
the actual API command (SQLConfigDataSource_) in order to use it... becoming an ordinary PureBasic command.

Bottom line is that you can do a lot more without all the verbose typing in other languages.
I find that a big plus, and... the code becomes very readable because of this.  :)

José Roca

What about his?


#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "CODBC.INC"

' ========================================================================================
' Main
' ========================================================================================
FUNCTION PBMAIN

   ' // Create an instance of the class
   LOCAL pOdbc AS IOdbc
   pOdbc = NewOdbc(%SQL_OV_ODBC3_80)
   IF ISNOTHING(pOdbc) THEN EXIT FUNCTION

   TRY
      ' // Create a connection object
      LOCAL pCon AS IOdbcConnection
      pCon = pOdbc.Connection("Connection1")
      ' // Open the database
      pCon.OpenDatabase("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=biblio.mdb;UID=;PWD=;")
      ' // Allocate an statement object
      LOCAL pStmt AS IOdbcStatement
      pStmt = pCon.Statement("Statement1")
      ' // Cursor type
      pStmt.SetMultiuserKeysetCursor
      ' // Generate a result set
      pStmt.ExecDirect ("SELECT TOP 20 * FROM Authors ORDER BY Author")
      ' // Parse the result set
      LOCAL strOutput AS STRING
      DO
         ' // Fetch the record
         IF ISFALSE pStmt.Fetch THEN EXIT DO
         ' // Get the values of the columns and display them
         strOutput = ""
         strOutput += pStmt.GetDataString(1) & " "
         strOutput += pStmt.GetDataString(2) & " "
         strOutput += pStmt.GetDataString(3)
         ? strOutput
         ' // Note: Instead of retrieving the data by ordinal,
         ' // you can also do it by column name.
'         strOutput = ""
'         strOutput += pStmt.GetDataString("Au_ID") & " "
'         strOutput += pStmt.GetDataString("Author") & " "
'         strOutput += pStmt.GetDataString("Year Born")
'         ? strOutput
      LOOP
   CATCH
      ' // Display error information
      ? OdbcOleErrorInfo(OBJRESULT)
   END TRY

   ' // Destroy the class
   pOdbc = NOTHING

   #IF %DEF(%PB_CC32)
      WAITKEY$
   #ENDIF

END FUNCTION
' ========================================================================================


José Roca

Or this?


#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "CSQLite.INC"

' ========================================================================================
' Main
' ========================================================================================
FUNCTION PBMAIN

   ' // Create an instance of the class
   LOCAL pSQL AS ISQLite
   pSQL = CLASS "CSQLite"
   IF ISNOTHING(pSQL) THEN EXIT FUNCTION

   ' // Create a connection object
   LOCAL pDbc AS ISQLiteConnection
   pDbc = pSQL.Connection
   IF ISNOTHING(pDbc) THEN EXIT FUNCTION

   TRY
      ' // Delete our test database if it exists
      IF ISFILE(EXE.PATH$ & "Test.sdb") THEN KILL EXE.PATH$ & "Test.sdb"
      ' // Create a new database
      pDbc.OpenDatabase(EXE.PATH$ & "Test.sdb")
      ' // Create a table
      pDbc.Exec("CREATE TABLE t (xyz text)")
      ' // Insert rows
      pDbc.Exec("INSERT INTO t (xyz) VALUES ('fruit')")
      pDbc.Exec("INSERT INTO t (xyz) VALUES ('fish')")
'      ' // Prepare a query
      LOCAL pStmt AS ISQLiteStatement
      pStmt = pDbc.Prepare("SELECT * FROM t")
      ? "Column count:" & STR$(pStmt.ColumnCount)
      ' // Read the column names and values
      LOCAL i AS LONG
      DO
         ' // Fetch rows of the result set
         IF pStmt.Step = %SQLITE_DONE THEN EXIT DO
         ' // Read the columns and values
         FOR i = 0 TO pStmt.ColumnCount- 1
            ? pStmt.ColumnName(i)
'            ? pStmt.ColumnText(i)
            ? pStmt.ColumnText("xyz")
         NEXT
      LOOP
   CATCH
     ' // Display error information
      ? pSql.OleErrorInfo
   END TRY

   ' // Cleanup
   pStmt = NOTHING   ' // Deletes the prepared statement
   pDbc = NOTHING    ' // Closes the database
   pSQL = NOTHING

   #IF %DEF(%PB_CC32)
      WAITKEY$
   #ENDIF

END FUNCTION
' ========================================================================================


Israel Vega Alvarez

#8
PowerBASIC es great and I love this compiler and I would like to continue using PowerBASIC, but I believe that no more updates...no 64 bits. 

PowerBASIC not have built-in Database or Images...but thanks to your great working (Jose Roca Includes) we can do a wide thinks how ADO, SQLite, GDI...).

By example in PureBasic with this code (built-in) I can set background a form:


UseJPEGImageDecoder()
DataSection
    Img_fondo:
    IncludeBinary "FONDO.JPG"       
EndDataSection

IMAGEN_FONDO = CatchImage(#PB_Any, ?img_fondo)
SetBackgroundImage(#window_0, IMAGEN_FONDO)