TweetFollow Us on Twitter

Beginning REALbasic: Inside the Application

Volume Number: 24 (2008)
Issue Number: 09
Column Tag: REALBasic

Beginning REALbasic: Inside the Application

by Norman Palardy

REALbasic is a Rapid Application Development (RAD) tool from REALSoftware. In the last column we started designing the application we're working on in this getting started series. Since the last issue REALbasic 2008r3 has been released and we'll move up to using that as here are a number of bug fixes and improvements in it.

Making the Database

In this installment we're continuing to build the application for tracking the prices of stocks. Last time we laid out the basic interface and also looked at how listboxes work. We still have a lot of work to do though.

One of those things is making sure that we have a place to store the data we get long term so we can look at it again. For that we're going to use a database. REALbasic comes with a built in database and we can make great use of it. The built in database is based on SQLite.

One of the tricky things with databases is that when you deal with them, you use their language, usually Structured Query Language (SQL), to do many things. Finding data, or selecting data, is done using SQL. Creating the places to store data is done using SQL, and even deleting data is often done using SQL.

So when you deal with a database one thing to keep in mind is that REALbasic has no clue about SQL. It does not read it, write it or interpret it in any way. As far as REALbasic is concerned there's no practical difference between these two bits of code:

dim s1 as string = "Hello World"
dim s2 as string = "create table test ( column1 varchar(100) ) "

Both are strings that have contents. REALbasic makes no distinction about what the contents are. The thing to remember is if you have trouble getting something for the database to work, try it manually, which we'll discuss a little later. If that works make sure the string you create in REALbasic does exactly what you did manually.

First, start REALbasic and load up the project from last time so we can work with it

As we saw last time this default project is a fully functioning program. You could immediately run it by pressing the green Run button.

Let's consider the data that we'll want to gather to make this program work the way we want.

We'll want a list of stocks we're interested in.

We'll have the quotes that we grab each time for each stock of interest

We'll need to keep track of the source(s) we're going to read data from

Please note that the screen shots here use REALbasic Professional. If you are using REALbasic Standard, screens may appear differently in your version.

Let's add a database. For the purposes of creating it quickly and simply we'll use the menu Project > Add > Database > New REAL SQL Database. Name it Stocks.rsd - the rsd extension is the default for REAL SQL databases.

Create the database file in the same directory as the REALbasic project (so it's easy to locate).

This will let us use the built in database tools to edit the database and browse the date. However, as recommended by REAL Software in http://forums.realsoftware.com/viewtopic.php?t=4342 everything else will be done in REALbasic code. This is not only more flexible but it ultimately gives you more control. Your project should now look like the one in Figure 1.


Figure 1: After adding the database

Now let's add the tables we'll require. Double click on the database icon and you should see the database editor as in Figure 2.


Figure 2: The database editor

In an SQL database, data are stored in "tables" - rows and columns of data much like you might see in a spreadsheet. Each row in a table is one complete "record". While that's technically not the right term it's so commonly used that we'll use it as well (The correct term is actually "tuple" but it's not frequently used). Each record in a table has every column that exists in the table. However, in an SQL database, a column for a particular record can have a value, say "Socks", or not have had a value assigned. This special "no value is assigned value" is called Null. There are special rules in SQL about NULL and how it is handled. You can find more about this as http://www.sqlite.org.

Just keep in mind that a string that is set to "" is NOT the same as NULL. The string has a value, but the value is empty and NULL means "no value at all".

Onwards!

The first thing we'll do is create the table for the stocks we want to track. The only things we'll need in this table are the full name of the stock, and its trading symbol.

Add the table by clicking "Add Table". Change the name of it to "StocksOfInterest".

We'll also add the two columns, Name and Symbol. You'll notice that when you click Add Column that there are also several properties that can be added to each column.


Figure 3: Adding a column in the database editor

The Type property sets the kind of data that this column can hold. Strings should go in varchar or text columns as those are the same "types" in REALbasic and the database. If you click the Type you'll see there are several others as well. Integers in REALbasic should go in integer columns in the database, floating point values from REALbasic (single or double) should go in float or double columns, and so on.

The Primary Key check box indicates whether this column is what is known as the primary key for the table. This means that the value in this column will always be required (ie it cannot be NULL) and it will be unique (no duplicates). For what we're doing we don't need to set this.

The Mandatory check box means this value, when you add a new row, MUST be provided and the addition of the row will fail if you do not provide it. In reality it means the column cannot be NULL (see? this NULL thing is really important!).

The Index check box specifies whether or not an "index" should be created. An index is a special data structure that a database uses to make access to data quicker. Often, primary keys are indexed and there may be reasons to index other columns; especially if you use them a lot to get data from the table. They can make a significant difference on very large tables. Again, for what we're doing, we can just ignore this.

The Default Value item is just that, the default that gets set if nothing is inserted for the column. It can be handy to make sure that a column always has at least some value.

The Length item usually only applies to the varchar or text types as they can be set to hold only X many characters (a length limit) or they can be set to hold an unlimited amount (up to the database limits) For what we're doing we'll leave this empty as well.

Now we have a table that can hold the stocks that we'll want to watch.

Click save to make sure your changes to the database design get saved. If you made a mistake, you can delete it and start over.

You'll also need to add a StockQuote table with the following columns: Symbol (type text), Price (type double) and quoteDateTime (type timestamp).

So now lets look at how we connect to this database, and insert rows to it and how we can use that to populate the listbox on our window.

In order to use the database in the program, we need to find the file that holds the database and connect to the database. We'll need a variable to refer to the database from anywhere in our program. There are lots of possible ways we could do these things. I'm going to show you one way you can use.

Close the Database editor window and open the App class in the project.

First, let's add a public property to the App class. Click on Add Property or use the Project > Add > Property menu item. Change the name to DB, and make the type REALSQLDatabase.

It should appear like the image in Figure 4


Figure 4: Adding a property to the App class

Now all we have to do is make it so this database variable points to the database file we just created. Again there are many ways to do this and I'm just going to illustrate one.

When an application starts up one of the first events that the application responds to is the "Open" event. This is the "Hey! I'm starting up" notification and the first opportunity you have as a programmer to do something.

Click on the "Event Handlers" disclosure triangle and you'll see there are other events as well.


Figure 5: The various events in the App class

Select the Open event and we'll add the following code to it:

dim fileTypeInst as FileType   
// create an instance of the Class
fileTypeInst = new FileType
// set up the "filter for what kind of file to select by 
fileTypeInst.Extensions = "rsd" 
// give it a name
fileTypeInst.Name = "REALSQLDatabase" 
// the Mac type and creator (only for OS X)
fileTypeInst.MacType = "RSdb" 
fileTypeInst.MacCreator = "RBv2"
  
// create a new instance of REALSQLDatabase Class
app.db = new REALSQLDatabase
// ask the user to select the database file
app.db.DatabaseFile = GetOpenFolderItem(fileTypeInst)   

There's no shortage of things going on in this little snippet. First we need to make it possible for use to ONLY select database files. So we set up a filter, known as a FileType.

The fist thing to do is create an "instance" of the class called "FileType".

In Object Oriented Programming (OOP) there are "Classes", which are a way of describing how something should work. Just like you say "Oh a car works like this by ... " and proceeding how internal combustion engines work, and how that eventually propels the car, a "Class" in OOP is a description of how things are supposed to work.

But your description of a car is not a car, just a description of one.

In order to get a car someone has to manufacture one and you get a NEW car.

In OOP programming you get a new instance using the New keyword.

So the first two lines:

dim fileTypeInst as FileType   
// create an instance of the Class
fileTypeInst = new FileType

say, "I'm going to create a thing and it's going to be of the type FileType. Now, create a new FileType thing and hold on to a reference to it in the variable I set aside for this purpose called fileTypeInst."

You'll notice a few things.

you create "instances"

you "refer" to instances

fileTypeInst is a reference to the instance created

yes it can be confusing :)

Suffice to say that we have created a new instance that we can set up to use as a filter for selecting the right file.

In order to complete the set up, we have to tell the filter what things to allow. Since OS X has adopted the use of extensions much like Windows, we set the extension AND the Mac Type and Creator. This filter will now only allow us to select REAL SQL Database files.

Then, because we are going to need a way to hold on to the reference to the database once we select it we need to create a new instance of the REALSQLDatabase class.

// create a new instance REASQLDatabase Class
app.db = new REALSQLDatabase

This does not create a new database. Rather, this creates a variable to hang on to the user's choice of database as long as the program runs. Now, we use the filter to ask the user to select the database that was created earlier. You did take my advice and put it next to the REAL basic project so you could find it, right?

// ask the user to select the database file
app.db.DatabaseFile = GetOpenFolderItem(fileTypeInst)

This will cause a dialog to be shown where the user can select the database file. There are, as I mentioned, other means to do this in REALbasic and this is only one of them. We still have not actually opened the database though.

One of things to realize is that in the dialog that gets shown as user could press "Cancel" and not select a file. In that case the DatabaseFile property would be set to Nil - this is a lot like NULL in a database.

So we'll need to test for this case and do something appropriate. If it is NIL then we should do nothing and if it is not NIL then we can try opening the database so we can use it else where in the application.

But, how will the rest of the application know that we did or did not open the database?

We don't want to have to check to see if app.Db.DatabaseFile is nil all over. That is one way but maybe there's a better way? What if we just set the app.db back to nil (remember this means "no value assigned") when a person does not select a database file? This actually will end up being "better" as it will immediately cause obvious errors if we try to use it when it is this way.

You might think it's odd to WANT errors, but in this case it is because of one unique feature that the REAL SQL database has. You don't actually need a file for it to connect to. In this case it will create an in-memory database that will behave exactly like one on disk except that when your program quits everything is lost. That can be very useful for some things, but not for what we're doing - at least not at the moment.

So let's add the following to the very end of the open event

if app.db.DatabaseFile is Nil then
  app.db = nil
else
end if

So this will set app.db, our global property for referring to the database, to nil if the user does not select a file.

In the event they do select a file, we should try and connect and see if that succeeds. If not maybe we should set the global property to nil for the same reason.

Alter the code so it reads

if app.db.DatabaseFile is Nil then
  app.db = nil
else
  if app.db.Connect() <> true then
    app.db = nil
  end if
end if

This will connect to a database and hold on to the reference or leave the reference as NIL (and we can check for that in other places). Thus far, we've created the database, connected to it and now, how to put it to use?

Let's hand code in adding the data we had for Apple last time so we can see how that is done and also eventually how to get it back into the list box. What we'll do is make sure the table is empty and then add in the data for Apple, then we'll extract that data from the database and populate the listbox with that data.

In the App.open event let's add in the cleaning out of the database, but in a way that it's easy enough to remove later on (we will want to remove it later on). The altered code in the Open event should now look like this:

if app.db.DatabaseFile is Nil then
  app.db = nil
else
  if app.db.Connect() <> true then
    app.db = nil
  else
    CleanOutDB()
  end if
end if

If you try to run at this point the compiler will complain about CleanOutDB as it does not exist yet.

Add a global method to the App class called CleanOutDatabase using either the Add Method button or Project > Add > Method. Make its name CleanOutDB. It does not need to do anything just yet.

Save everything then choose run and give things a try. You should see the dialog we created. Select the database file. Quit and run again and try to select a different file. Run it once again and press cancel so no file is selected.

You won't see much obvious happen yet. However, all of the code you have added has really been doing what is intended. But how to tell?

Well, you can see things run and it does what we discussed. Don't trust me? OK, there is a better way. REALbasic has a built in debugger. This is very handy to help you see what is going on in your program as it runs.

In the Open event if you look at the editor to the very left of the lines of the program you should see small dashes. If you click on one it should turn into a red dot like that in figure 6. This little red dot indicates that you have a "break point" on this line.


Figure 6: Setting a break point in the program

When you run your program in the IDE, and the program reaches this line of code, it will stop, and show you that it is about to run the line like in Figure 7.


Figure 7: Encountering a break point in the program

Now you can see where you are in your program, you can look at the value of variables and slowly advance through the program using the various Step buttons. You can actually see what's going on and control it at your leisure.

There is a whole section on using the debugger in the documentation from REAL. Learn how to use it well and it can be a great asset to you in your programming adventures.

If you're still looking at the screen shown in Figure 7, choose Resume and the program will proceed normally.

Let's open the CleanOutDB method we just added.

In this method we're going to remove all the data from the one table that exists currently.

First we should check to see if the database was connected to at all.

We can accomplish that with this line:

if app.db is nil then return

Recall that we set the app.db variable to nil if the user did not select a database or if the database could not be connected to. What this line does is check to see if there is a usable database, and if not leaves this routine immediately.

If the database was connected to we have to write the correct SQL to remove all the data from each table. The SQL command "delete" will delete things from a table. In its simplest form you simply use "delete from (tablename)". In our case this would be "delete from StocksOfInterest".

So lets write the REALbasic code that passes this command to the database.

dim sqlCmd as string = "delete from StocksOfInterest"

Recall that in REALbasic this is just a string and it means nothing special. It only has meaning when we tell the database to use it as a command. We do that by asking the database to "execute" it:

app.db.SqlExecute(sqlCmd)

This tells the database that we are connected to "run the SQL command that is in the variable sqlCMD".

How do we tell if things worked OK? Every database has several properties: error, errorCode and errorMessage. These properties can be checked to see if the previous operation succeeded. If everything worked properly, the error property will be false. If there was an error, the error property will be true.

If app.db.Error then
   msgbox "an error occurred " + format(app.db.ErrorCode,"-#") +_
          " " + app.db.ErrorMessage
end if

This displays a message box will the details of the error if things did not work, and does nothing if they did work.

Now we will want a way to add the data we have for Apple from last time. Since we will probably want to add data for quotes frequently we should make this a different method.

Create a new method called "AddDataForStock" that takes the stock symbol as one parameter, the stock price as another, and the date and time for the quote as the last one. Mine looks like that shown in Figure 8.


Figure 8: Definition of AddDataForStock

This method will be one that we'll use to add a quote for a given stock at a given date and time.

In the last installment, we just put the data directly into the listbox. This time, we'll alter that so the quote data goes into the database and then we retrieve it from the database to insert into the listbox.

For the moment, lets just pretend we are actually getting the quote from a service like Yahoo Finance or some other service and see how to get the data into the database.

In REALbasic there are at least two different ways you could add data to a database.

One is using raw SQL INSERT statements. While this gives you a great deal of control, it also means you have to take care of everything. Most SQL databases require you to double up quotes that are contained in values, and adding certain types of large binary chunks of data may be difficult using this method. You have to know what the specific database conventions are.

The second is using REALbasic's built-in DatabaseRecord class. This is substantially easier and only requires you to know how to use it and the specific database plugin does the rest of the grunt work; we'll use this second way for now.

First, you need to create a new instance of a DatabaseRecord. Then you add the specific values to it and then you add this record to the database. That code will look like:

  dim dbRec as DatabaseRecord   
  dbRec = new DatabaseRecord // create a databae record instance
  // add the data to it
  dbRec.Column("Symbol") = stockSymbol
  dbRec.DoubleColumn("Price") = stockPrice
  dbRec.DateColumn("quoteDateTime") = dateAndTimeForQuote
  // add the record to the database  
  db.InsertRecord("StockQuote", dbRec)
  
  // check for any errors
  if db.Error then
    msgbox "an error happened inserting the quote " + db.ErrorMessage
  end if 

This creates a new DatabaseRecord and sets the values. One thing to notice is that the addition of the values uses the names of the columns in the database table. The line:

dbRec.Column("Symbol") = stockSymbol  

can be interpreted as, "when you save this record the column called "Symbol" should be set to the value that is in stockSymbol. But this does not happen until you actually call InsertRecord.

At the end of the App.Open event, add in one line to add one quote for a stock like this:

  AddDataForStock "AAPL" , 169.73,  new Date

This will use the newly written method and pass in the symbol ("AAPL"), the stock price (169.73) and a date for the quote that is the current date and time.

Lets now see how to get this data out of the database and into our user interface. If you open the wStocks window and look in the Open event for the list box on that window you'll see:

  me.ColumnCount = 3
  me.HasHeading = true
  me.Heading(0) = "Symbol"
  me.Heading(1) = "Time"
  me.Heading(2) = "$"
  
  me.AddRow "AAPL" // add one symbol we're interested in watching
  dim newDate as new Date
  me.cell(me.LastIndex,1) = newDate.ShortDate + " " + newDate.ShortTime
  me.cell(me.LastIndex,2) = format(169.73,"$,#.00")

We're going to remove the last 4 lines and replace them with code that gets the data from the database. So lets first remove them and see what the new code will be to replace them:

dim rs as RecordSet 
// use SQL to get the data
rs = app.db.SQLSelect("select Symbol,  Price, quoteDateTime from stockquote")
  
// go through any and all rows we get back and put them in the list
while rs <> nil and rs.eof = false
    me.AddRow ""
    me.Cell(me.LastIndex,0) = rs.Field("Symbol").StringValue
    me.Cell(me.LastIndex,1) = rs.Field("quoteDateTime").DateValue.SQLDateTime
    me.Cell(me.LastIndex,2) = rs.Field("Price").StringValue
    
    rs.MoveNext
  wend

So what does all this do? First, we declare a variable to refer to a recordset. A recordset is what a database query returns to us. They can have lots of data (rows), or none. Only if the query has an error do you get a recordset that is NIL.

After declaring the variable, we then use a SQL SELECT query to get the set of data back that we want. In this case it's all rows and columns from the table called StockQuote. However SQL is very powerful and can be used to bring back data from one or more tables, sums and all kinds of other information. A full discussion of SQL is well beyond the scope of these articles.

Once we run the query, if there were no errors we will have a non-NIL recordset. I prefer to use a while loop to traverse all the data. For every row in the data set we get back from the query, we want to add a row to the list box. And then we want to set the columns in the listbox to the various values in each of the columns of the data set.

Each row in a recordset has many fields and each of those fields can be referred to by name, as it is in the database, or by a numeric index. I prefer to use names as they are easier to follow. Note that the query asks for "Symbol, Price, quoteDateTime" and the code just uses those names. Each of the lines in the loop grabs the string value of the field and puts it in the cell of the specific row of the listbox, then it moves to the next row. This continues until all the rows are loaded into the list box.

Now, run your application a few times and see what happens!

Next time we'll see how to grab the quotes from a service like Yahoo and add them to the database.


Norman Palardy has worked with SQL databases since 1992, and has programmed in C, C++, Java, REALbasic and other languages on a wide variety of platforms. In his 15+ years of IT experience, Norman has developed innovative and award-winning applications for TransCanada Pipelines, Minerva Technologies (now XWave), Zymeta Corporation, and the dining and entertainment industry. He holds a BSc from the University of Calgary in Alberta. He's also a founder of the Association of REALbasic Professionals (http://www.arbp.org/) and currently works for REAL Software.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

How to be a star in Britney Spears: Amer...
If you've ever wanted to be a star, baby, then you've probably already checked out Britney Spears: American Dream and are happily making your way up the charts. But fame doesn't come easy, and everyone needs a helping hand sometimes. So we've got... | Read more »
AppSpy is hiring a part time Staff Write...
| Read more »
How to save lives in ER Surgery Simulato...
A serious earthquake has struck a nearby town in ER Surgery Simulator - Emergency Doctor, and it’s up to you to save the victims. [Read more] | Read more »
Tips and tricks to get a high score in G...
Ketchapp Games loves the endless runner genre. And its newest game, Gravity Switch, is no exception. Gravity Switch takes a fresh approach, though, as you move a block, suspended in zero gravity, safely through a maze of shifting pillars. If the... | Read more »
Tips and tricks to get a high score in S...
Smash Fu is a high-paced tile-tapping game that requires quick reflexes and some practice. You’ll have to smash bricks with the skill of a seasoned black belt to get a high score. To raise the stakes a bit, you’ll also have to avoid tapping any... | Read more »
How to keep the ball rolling in Dropple
If you're new to the minimalist puzzler Dropple, you may find yourself struggling to make it beyond the first couple of steps before your ball falls into the endless abyss below. [Read more] | Read more »
How not to die in Traffic Rider
Traffic Rider, an Out Run-esque game in which your ride a motorcycle recklessly into trffic, might not seem particularly complicated. [Read more] | Read more »
How to adjust your chess game for Regici...
At first glance you might likenWarhammer 40,000: Regicide to Chess - and you'd be right. Regicideputs its own spin on the classic board game though, so some of your tried and true methods may not work quite so well here. [Read more] | Read more »
Rush Rally 2 (Games)
Rush Rally 2 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: -- Rush Rally 2 is the most authentic and thrilling rally simulation on your mobile, all running at an astounding 60fps. Console... | Read more »
Warhammer 40000: Regicide (Games)
Warhammer 40000: Regicide 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: ++NOTE: Optimized for with iPad Air, iPad mini 2, iPhone 5 and up. ++ "“This game has no right to be as good as it... | Read more »

Price Scanner via MacPrices.net

Textkraft Professional Becomes A Mobile Produ...
The new update 4.1 of Textkraft Professional for the iPad comes with many new and updated features that will be particularly of interest to self-publishers of e-books. Highlights include import and... Read more
SnipNotes 2.0 – Intelligent note-taking for i...
Indie software developer Felix Lisczyk has announced the release and immediate availability of SnipNotes 2.0, the next major version of his productivity app for iOS devices and Apple Watch.... Read more
Pitch Clock – The Entrepreneur’s Wingman Laun...
Grand Rapids, Michigan based Skunk Tank has announced the release and immediate availability of Pitch Clock – The Entrepreneur’s Wingman 1.1, the company’s new business app available exclusively on... Read more
13-inch 2.9GHz Retina MacBook Pro on sale for...
B&H Photo has the 13″ 2.9GHz Retina MacBook Pro (model #MF841LL/A) on sale for $1599 including free shipping plus NY tax only. Their price is $200 off MSRP. Amazon also has the 13″ 3.9GHz Retina... Read more
Apple price trackers, updated continuously
Scan our Apple Price Trackers for the latest information on sales, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. We update the trackers continuously: - 15″... Read more
Clearance 12-inch Retina MacBooks available s...
B&H Photo has dropped prices on leftover 2015 12″ Retina MacBooks with models now available starting at $999. Shipping is free, and B&H charges NY tax only: - 12″ 1.1GHz Gray Retina MacBook... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
New 2016 13-inch 256GB MacBook Air on sale fo...
B&H Photo has the new 13″ 1.6GHz/256GB MacBook Air (model MMGG2LL/A) on sale for $1149 including free shipping plus NY sales tax only. Their price is $50 off MSRP. Amazon has the 13″ 1.6GHz/256GB... Read more
Apple refurbished iPad Air 2s available start...
Apple has Certified Refurbished iPad Air 2 available starting at $339. Apple’s one-year warranty is included with each model, and shipping is free: - 128GB Wi-Fi iPad Air 2: $499 - 64GB Wi-Fi iPad... Read more
Accenture and Vatican Opera Romana Pellegrina...
Accenture has announced that the official mobile application for the Extraordinary Jubilee Year of Mercy declared by Pope Francis has been built and launched by Accenture Mobility, part of Accenture... Read more

Jobs Board

ISCS *Apple* ID Site Support Engineer - APP...
…position, we are looking for an individual who has experience supporting customers with Apple ID issues and enjoys this area of support. This person should be Read more
Automotive Sales Consultant - Apple Ford Linc...
…you. The best candidates are smart, technologically savvy and are customer focused. Apple Ford Lincoln Apple Valley is different, because: $30,000 annual salary Read more
*Apple* Support Technician II - Worldventure...
…global, fast growing member based travel company, is currently sourcing for an Apple Support Technician II to be based in our Plano headquarters. WorldVentures is Read more
Restaurant Manager (Neighborhood Captain) - A...
…in every aspect of daily operation. WHY YOU'LL LIKE IT: You'll be the Big Apple . You'll solve problems. You'll get to show your ability to handle the stress and Read more
Editor, *Apple* News - APPLE (United States...
Job Summary The Apple News team is looking for a passionate...a news organization. Description * Program Top Stories in Apple News * Post on Apple News Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.