Introduction To Programming With Xojo PDF
Introduction To Programming With Xojo PDF
!
!
Introduction to
Programming
with Xojo
!
BY BRAD RHINE
Table of Contents
!
FOREWORD
11
ACKNOWLEDGEMENTS
13
CONVENTIONS
14
17
17
18
22
25
31
36
36
37
41
54
62
68
72
72
73
83
85
3.5 Do...Loop
90
3.6 While...Wend
92
93
95
103
103
106
4.3 Parameters
108
112
4.5 Comments
113
115
4.7 Scope
117
118
118
120
125
126
129
131
136
142
142
144
6.3 Windows
145
6.4 Input
149
6.5 Buttons
154
6.6 Pickers
159
168
173
173
7.2 ListBox
174
7.3 Decor
178
7.4 Organizers
181
7.5 Indicators
184
187
CHAPTER 8: DO IT YOURSELF
192
192
193
8.3 Classes
194
8.4 Variants
201
204
8.6 Modules
209
211
211
213
214
217
222
230
232
241
241
242
245
10.4 Printing
260
263
267
267
269
272
275
278
283
285
285
286
289
299
304
310
311
311
312
319
324
324
325
328
332
335
339
343
343
344
347
348
350
352
355
357
359
AFTERWORD
361
362
363
Foreword
When you finish this book, you wont be an expert developer (unless you
already were when you started!), but you should have a solid grasp on the
basic building blocks of writing your own apps. My hope is that reading
Introduction to Programming with Xojo, youll be motivated to learn more
about Xojo or any other programming language.
The hardest programming language to learn is the first one you learn.
Thats why this book focuses on Xojo - because its easier to learn than
many other languages. Once youve learned one language, though, the
others become much easier, because youve already learned the basic
concepts involved. For example, once you know to write code in Xojo,
learning Java becomes much easier, not only because the languages are
Foreword!
Page 11 of 363
similar, but because you already know about arrays, loops, variables,
classes, debugging, and more. After all, a loop is a loop in any language.
So while this book does focus on Xojo, the concepts that are introduced
are applicable to many dierent programming languages. Where possible,
some commonalities and dierences are pointed out in notes.
Before you get started, youll probably need to download and install Xojo
to your computer. To do so, simply visit http://www.xojo.com and click on
the download link. Xojo is free to download, install, and run - you only
need to pay if you need to compile your apps so that they can run on other
peoples computers. This makes it very easy to start writing your own apps
without a big investment up front.
Foreword!
Page 12 of 363
Acknowledgements
While my name is on the cover, writing this book was not something I
accomplished on my own.
Thanks to Geo Perlman of Xojo, Inc., for suggesting the idea, for his
tireless eort in helping to edit and refine the text and examples, and for
his constant collaboration.
Acknowledgements!
Page 13 of 363
Conventions
Because Xojo can run on dierent operating systems and build apps for
dierent operating systems, some of the screenshots in this book were
taken on Windows 7 and some were taken on OS X 10.8. One of the
sample apps is web-based, so youll see that its screenshots were taken in
a web browser.
As you read this book, you also will notice dierent formats of text.
Conventions!
Page 14 of 363
Dim x As Integer!
Dim y As Integer!
Dim z As Integer!
x = 23!
y = 45!
z = y * x!
MsgBox Str(z)!
You will sometimes see the symbol in a code example. The symbol
indicates a line wrap. That doesnt mean you need to hit return and start a
new line; it just means that the margins of a book dont provide as much
space as your computer screen, so we had to wrap the line to fit the text
on the page. So when you see the symbol, dont type it in; just keep
typing whats indented on the next line. So if you see code like this:
+ EndOfLine!
Another format you will see is steps. A step looks like this:
1)
Conventions!
Page 15 of 363
This is a note. The text in the note isnt absolutely essential, but it might
provide some background information on the current topic.
Conventions!
Page 16 of 363
Page 17 of 363
This chapter will introduce the IDE. You will learn how to navigate the IDE,
how to customize it, how to organize your projects, and how to run and
build your own applications. Some of the concepts introduced in this
chapter may not make much sense at the moment, but they will be
explained in more detail in later chapters.
As you can see from the screenshot, Xojo can build many dierent types
of applications, including web-based applications and console (or
command line) applications.
Page 18 of 363
After you choose a template, Xojo will create an empty project based on
that template. The project is the file that stores all of the source code, user
interface designs, and information about the application you are
developing. The default empty project looks like this.
By default, you should see a window with two distinct areas. The larger
area, known as the pasteboard, holds an empty window. This is where you
can begin to design the user interface for your application. The left pane,
known as the Navigator, holds a list of items in your project. By default,
you probably wont see anything there other than App, Window1, and
MainMenuBar. Beneath the Contents you should see some options for
Build Settings. Build Settings allow you to change the settings of the
application you will be creating, such as its name, version number, and
icon.
Page 19 of 363
Above the pasteboard is the toolbar. The two rightmost buttons will toggle
the Library and the Inspector. The Library is a list of controls that you can
add to your interface (simply by dragging and dropping), while the
Inspector allows you to modify the properties of whatever you have
selected in the pasteboard. For example, if you add a button to your
interface, you may select that button and use the Inspector to change its
caption or physical size. Take a few moments now to browse the Library
and Inspector.
This view is called the Layout View. In Layout View, you visually design the
look and feel of your application. Another important view is Code View.
This is where you will enter the Xojo source code that controls the
behavior and functionality of your application. The easiest way to get
started in Code View is to use the Insert Menu to insert an Event Handler.
Events will be discussed in much greater detail in a later chapter, but for
now, you need to know that events allow your application to react to
actions taken by your applications end users as well as actions that the
computer or operating system may cause while your application is
running. Select Event Handler from the Insert Menu and choose Open in
the list of events that appears.
Page 20 of 363
As you add components to your projects, you will see them in the
Contents Pane, whether you are in Layout View or Code View. You may
double click on an item in this list to open it for editing. You may also drag
and drop these items to arrange them in the order you desire. The order in
which you arrange these items will have no bearing on the performance or
functionality of your built application; it is up to you to organize your
project in a way that makes sense to you. You may even add folders and
subfolders if you wish to organize your project in such a way. To add a
folder, go to the Insert Menu and choose Folder. You can then drag and
drop other project items into the folder.
The Insert Menu is one that you will be using often as you build more and
more complex applications. In addition to folders, you will use it to add
classes, windows, and other components to your projects. Once again,
these concepts will be explained in later chapters.
Page 21 of 363
You will be presented with a blank window. While this may not seem
impressive, quite a lot has already been accomplished. First, your project
has been converted from a Xojo project file into an application that can be
run on your computer. In addition, your application can respond to menu
commands and keyboard shortcuts and react accordingly. For example, if
Page 22 of 363
Running your application in this way allows you to access the Xojo
debugger, which will be covered later in this chapter. What it does not give
you, however, is an application that you can share with other people. The
application produced by running is temporary and is only intended to be
used for testing and debugging.
If you build your project now, you will have an application that can be run,
but it will have a few issues, such as a rather generic name and icon and
the fact that it does not do much of interest at this point.
Page 23 of 363
Some of these problems are simple to solve. In the Contents Pane, locate
the App item in the list and select it. This item, called a class, allows you to
set properties that will apply to your application as a whole. With the App
class selected, click on the Inspector button in the toolbar.
The Inspector is broken into several sets of properties. Not all of these sets
will be covered at this time. Notice that there is a separate group of build
settings for each platform for which your project can be built: Windows,
Linux, and Mac. Find the setting appropriate for your platform and change
the App Name property (if you are using Windows, be sure that the App
Name ends in .exe).
Click on Shared Settings in the Contents Pane. You will see more groups
of settings, including one called Version Info. For a blank application such
as this one, this is not important, but as you build more complex
applications and upgrade those applications, you will need to keep those
Chapter 1: Hello, World!!
Page 24 of 363
The other problem with your project at this point, though, is that it does
nothing of interest or value. This will be remedied in the next section.
Page 25 of 363
In the Contents Pane, find the item called Window1. Window1 represents
the default view that your application will provide to the end user (but this
can be changed, as will be seen in later chapters). Click on Window1 to
open it in Layout View. This is the view that you will use to design the user
interface for your projects.
As noted above, there are three main areas that you will see in Layout
View. The largest area, found in the center, is called the pasteboard. Within
the pasteboard, you will see an empty window. On the left side of the
window is the Contents Pane, which contains the items in your project. On
the right is either the Inspector or the Library. The Library contains
interface elements that you may add to your window (or position
elsewhere on the pasteboard).
Page 26 of 363
1)
Find the PushButton in the controls list and drag it onto the window
in the pasteboard.
First, turn your attention to the Library. As you scan up and down the list, you will see
various interface elements, some of which should look familiar, such as the CheckBox,
the PushButton, and the ScrollBar. The usefulness of other controls, such as the
Canvas, the PagePanel, and the Timer, may not be immediately apparent. These
controls and others will be covered in Chapter Six. For the Hello World application, the
only control required is the PushButton. Find the PushButton in the controls list and
drag it onto the window in the pasteboard. Dragging controls onto windows is a task
that you will perform repeatedly as you build a Xojo application. Once you drop the
control onto the window, you may drag it to change its position, and you may also use
the properties pane to modify it.
2)
3)
4)
Page 27 of 363
5)
Page 28 of 363
6)
7)
8)
With the Action event highlighted, the time has come to enter your
first line of Xojo code:
MsgBox "Hello, World!"!
Page 29 of 363
As you enter code into the Code Editor, you may notice that Xojo helpfully
autocompletes as you type. Xojos autocomplete is a great way to learn more about the
language, since you can begin typing a few letters to see what suggestions appear. In
addition, help appears at the bottom of the window, oering information about the
method or function to which the mouse is currently pointing. This is another great way
to learn more about the Xojo language.
As for what you actually typed in, you entered two things: a method and a parameter.
These terms will be explained in detail in Chapter Three, but for now, just know that a
method in Xojo is simply a way of telling the computer to do something. A parameter for
that method gives the computer additional details about what you want. In essence, the
method is what you want to do, and the parameters are how to do it.
The method youre running is MsgBox, which you can think of as shorthand for
Message Box. MsgBox takes a piece of text and displays it to the end user of your app.
The piece of text in question in this example is Hello, World!.
9)
Page 30 of 363
10)
If you are familiar with other programming languages, you may notice
some differences from some of them. First of all, many languages require a
semicolon at the end of a line, rather than relying on white space and/or
line breaks to indicate the end of a line. Xojo code should never end with a
semicolon - Xojo will actually use the help area at the bottom of the window
to warn you if you type a semicolon out of habit.
First, the intentional way: back in the Code Editor, find the place you
entered the MsgBox line earlier (if your Hello World application is still
running, you will need to quit or exit from it). Change the code in
HelloButtons action event to look like this:
Break!
The Break keyword causes your application to pause, but not stop, and
launches Xojos debugger. With the Break keyword in place, run your
Chapter 1: Hello, World!!
Page 31 of 363
project. When you click HelloButton, you will see a screen similar to the
one below:
This is Xojos debugger. With your current project, there is not much to
see, but as your projects become more involved, the debugger can
provide you with a wealth of information about your application while it is
running. In the screenshot above, note that the currently executing line is
highlighted (the Break keyword). The pane in the lower right portion of the
window provides you with a hierarchical view of your applications
variables and properties.
Press the Stop button on the Editor Toolbar to stop execution of your
application and return to Xojo.
Now that you have seen one way to access the debugger intentionally,
lets look at an accidental way. This example is, admittedly, contrived, but
it should show you an important aspect of using the debugger.
Change the code in HelloButtons action event to the two lines below:
Dim p As PushButton!
p.Push!
Page 32 of 363
For now, you need not worry about what the above code is even
attempting to do. Simply run your project again and press HelloButton.
The debugger should appear again, but with a slightly dierent look:
The red bug icon indicates where the error has occurred. A glance at the
variables pane shows that P, the PushButton, is Nil. The meaning of this
will become clear in later chapters, but in essence, you have attempted to
access something that simply does not exist yet.
Page 33 of 363
Bugs? You may wonder why programming errors are called bugs. In the
early days of computing, computers relied heavily on vacuum tubes for
their operating. These computers often filled an entire room. Vacuum tubes
generate both heat and light, and they would often attract moths, which
would interfere with the computers operation. At that point, someone
would have to go in and debug the computer.
Page 34 of 363
an attempt to access an object that does not exist. Writing defensive code
to prevent exceptions is a major part of software development, as you will
see throughout this book.
!
!
Page 35 of 363
Chapter 2: Introduce
Yourself
!
Page 36 of 363
For example, you may have a variable named MyAge. Its type could be
integer, or a whole number, and its value might be 16.
A variables data type could be almost anything. This chapter will discuss
some of the more common data types and how to use them in your code.
It will also discuss some best practices for naming your variables, as well
as how to assign values to them. Finally, you will build a small application
called Introduce Yourself. This application will ask the end user a few
questions and provide some information back to the user.
Page 37 of 363
Bear in mind that these are simply conventions. Each person needs to
develop a naming convention that best fits his or her coding style.
First, pick variable names that are specific and descriptive. For example,
the sample project you will build later in this chapter will have a variable
that needs to store the end users first and last name, so that variable is
called fullName. If you needed to dierentiate between dierent peoples
names, you may have variables called employeeFullName and
supervisorFullName. Dont worry about using long names for your
variables, since Xojos autocomplete can help with the typing later on.
Avoid generic names. Working under a deadline, you may be tempted to
use a single letter for a variable name. While this may be appropriate for
certain counting and looping functions (as well see in later chapters), in
general, specific names are more practical. A variable name should
indicate its purpose to you at a glance.
Page 38 of 363
Third, some developers prefer to use the variable name to indicate its type,
although this is admittedly far from universal. Examples would include
nameString, birthDate, and favoriteColor. This is not part of the convention
we will be following in this book, but you are free to follow it in your own
code and projects.
Finally, note that as you expand your knowledge of Xojo, you will be able
to apply these same guidelines and conventions to other aspects of your
code, such as function names and custom classes.
Now that you have some ideas on variable naming, its time to take a look
at how you can tell Xojo about these names. To do that, you will use the
Dim keyword.
To use an example from above, you may have a variable called FullName
that you will use to store someones name. Its data type will be string
(which will be explained in Section 2.3). To create this variable, enter this
line into Xojo:
Page 39 of 363
Dim is actually short for dimension, and refers to the early days of
computers when developers had to set aside memory and reserve it for use
Telling Xojo which data type you will be using is critical. Xojo is a strongly
typed language. This means that every variable has a certain type, and
that you as the developer are expected to treat each variable as its type
warrants. For example, you may perform mathematical operations on
numerical data, but not on text. Xojo will oer suggestions and warnings if
you attempt to use a variable that is not supported by its data type.
Most data types need to be instantiated. While using the Dim keyword
sets aside space for your variable, the New keyword instantiates, or
creates an instance of, your variable. Consider the following lines:
With that line, you have set aside space in memory for your variable, you
have named it (today), and you have told Xojo what kind of data you will
be working with (a date value). What you have not done, however, is create
the date object itself. So if you attempt to access one of Todays
properties, such as its ShortDate property, before continuing, you will
encounter a NilObjectException such as the one demonstrated at the end
of Chapter One.
Page 40 of 363
Once your variable is instantiated, you may freely access or modify its data
and properties. A more complete example of creating a variable and
accessing its properties follows:
!
Dim today As Date!
today = New Date!
MsgBox today.ShortDate!
In this brief example, you have created your variable, you have instantiated
it, and you have given the end user a message box containing todays date
in a human readable format.
STRINGS
One of the most common data types you will encounter is the string. A
string is simply a piece of text. It can be of any length (the maximum size
of a string is limited only by the computers memory) and can contain any
Chapter 2: Introduce Yourself!
Page 41 of 363
data that can be represented by letters (of any language), numbers, and
punctuation. To create a string in Xojo, simply use the Dim keyword:
Strings are one of a small set of data types that do not need to be
instantiated. As soon as the line of code containing the Dim keyword is
executed, the string is created in memory, although it is empty.
Whenever you enter string data into Xojo, it must be surrounded by double
quotes:
If you have a string that already contains double quotes, you must
escape the quotes by doubling them:
Page 42 of 363
A doubled double quote may look odd, but the extra double quote tells
Xojo that it is part of your string data and does not denote the end of your
string.
myAge = "18"!
myNumericAge = CDbl(myAge)!
Page 43 of 363
Most modern computers are 64-bit. A 64-bit computer can hold an integer
as low as -2^63 and as high as one below 2^63.
There are several ways to declare an integer variable. The first and most
simple way:
Page 44 of 363
!
If you are on a 32-bit computer, that will give you a 32-bit integer.
Appropriately enough, if you are on a 64-bit computer, that will give you a
64-bit integer.
If you wish to be more specific about the type of integer you need, you
may do so:
The two lines above will give you one 32-bit integer and one 64-bit integer.
Unless you have a specific need to do otherwise, the simplest course of
action is to declare your variables as Integer.
To store a more precise number, you may use the Double data type. A
Double is a floating point number, also known as a double precision
number. A Double may have a decimal point, and may have any number of
significant digits beyond the decimal point.
The range of a double precision number is quite large. Its range is so large
that you will probably never need to worry about exceeding it.
Since both integers and doubles are numeric data types, you may use
them in mathematical operations without issue:
Page 45 of 363
Which method you should use depends on your own preferences and on
which way seems more readable to you.
Page 46 of 363
BOOLEANS
A boolean is a data type that is used to store a truth value. Its value may
be true or false. To create a boolean, use the Dim keyword:
thisIsAwesome = True!
Page 47 of 363
!
If, later on, you need to change a boolean back to false, you may do so:
thisIsAwesome = False!
DATES
Dates can be a trickier data type to work with in Xojo. A date object can
store all relevant details about a particular date and time. To create a date
object, use the Dim keyword and instantiate the variable (unlike the data
types that have been covered so far, a date does need to be instantiated
with the New keyword):
Page 48 of 363
When you instantiate your date, it will be assigned a value equal to the
current date and time. Each element of the current date and time can be
accessed or modified using its properties. For example, if you have
instantiated a date object to the current date and time, but you wish to
change its month to December (without aecting its year, day, or time), you
may modify its Month property:
someDay.Month = 12!
There are six individual properties that make up the dates total value: Year,
Month, Day, Hour, Minute, and Second. Each of these is an integer. You
may modify any of these at any time:
dDay.Day = 6!
So far you have seen how to set these properties, but you may also
retrieve them from the date object:
thisMonth = today.Month!
Page 49 of 363
With the above code, you now have an integer called ThisMonth, which
contains a numeric representation of the current month (January = 1,
February = 2, etc.).
A date object has other properties that may be read but not modified (in
programming terms, you may get them but not set them). DayOfWeek
is an integer that represents the days position in the week (1 = Sunday, 7
= Saturday). DayOfYear is, similarly, an integer that represents the days
position within the year (a date object representing February 1 would have
a DayOfYear value of 32). There is also a WeekOfYear property.
There are also some string properties that can be accessed. These are
very useful for displaying dates to your end users. They include
AbbreviatedDate, ShortDate, ShortTime, LongDate, and LongTime. These
strings will vary based on the settings and locale of the end users
computer.
Page 50 of 363
One last property of the date object that will be discussed in this chapter
is TotalSeconds. TotalSeconds is a double, and it represents the number of
seconds passed between midnight on January 1, 1904, and the date
objects value. TotalSeconds may be set manually if you know the right
value. This makes TotalSeconds an easy way to set all information the
date in one line of code.
COLORS
You may change a color in your code or by asking the user to select a
color. You will see both methods.
Page 51 of 363
To change your color in code, you must understand a few basics about
how Xojo stores colors. A color has three properties that will be discussed
here: Red, Green, and Blue. Each of these is an integer that may be
anywhere from zero to 255. The higher the value, the more that shade is
present in the color. For reference, the color black would have zero for
each property, while white would have 255 for each property. Pure red
would have 255 for Red, zero for Green, and zero for Blue. Purple would
have 255 for Red, zero for Green, and 255 for Blue.
To set these properties in code, you may simply enter a value for each,
using the RGB method:
thisIsPurple = RGB(255,0,255)!
Page 52 of 363
Or you may want to ask your end user to choose a color, using the
SelectColor function:
End If!
If you are familiar with HTML or CSS, or if you have experience working
with hexadecimal colors (where red, green, and blue run from 00 to FF),
you may also set a color using &c (known as a literal):
Dim ThisIsBlue As Color
ThisIsBlue = &c0000FF
If you are not familiar with hexadecimal math, you may want to stick with
the RGB method to get started.
Page 53 of 363
For the most part, to set a variables value, use the equal sign. Depending
on the data type, you may or may not need to use quotation marks. They
are required for string data, but should be omitted for numeric data types
and booleans.
thisIsEasy = True!
As mentioned above, dates and colors are a dierent story. A dates value
cannot be set directly (unless you have another date object already in
existence, in which case you still have the issue of the original date
needing a value to begin with). To set a dates value, you may set each of
its properties (year, month, day, hour, minute, second):
dDay.Day = 6!
Page 54 of 363
You may also set its TotalSeconds property (474,736,043 seconds after
January 1, 1901, is January 16, 1919):
prohibitionDate.TotalSeconds = 474736043!
If you know the date values, you may assign them when you instantiate
the date with this syntax:
Page 55 of 363
!
Dim logoBackgroundColor As Color!
logoBackgroundColor = RGB(255,0,255)!
When you see a line of code that starts with //, that line is a comment. A
comment is there for the developers reference and will not be part of the
finished application.
Page 56 of 363
!
Dim theAnswer As Integer!
theAnswer = 25 + 35!
//theAnswer is now 60!
theAnswer = theAnswer + 10!
With the backslash, Xojo performs integer division, which does not
account for fractional values:
//roundedAnswer is now 2!
Page 57 of 363
Mod can also be useful for determining whether an integer is even or odd.
If your integer Mod 2 is equal to 1, the number is odd. If the answer is
zero, the number is even.
In the example above, note the space that is added between the first and
last name. Omitting this space is a common error in string concatenation.
MsgBox theGreeting!
Page 58 of 363
Numeric variables are slightly trickier, since the MsgBox function cannot
take an integer or double directly. Xojo provides several ways to convert
numeric data to strings: Str and Format.
Str is the simpler of the two ways. It takes one parameter, which can be an
integer or a double, and it displays the string value of that number:
MsgBox myAgeAsAString!
The code above stores the value of the integer in a string and then
displays that string to the user in a message box.
One downside of using Str is that it gives you as the developer no control
over how your data will be formatted. For example, a large number may be
displayed in scientific notation, or you may wish to limit the number of
decimal places that are displayed. In such cases, the Format function is
useful.
myPercent = Format(.25,"#%")!
Page 59 of 363
At first glance, that may look like nonsense, but there are just a few simple
rules for the format specification. First, the pound (or hash) sign (#)
represents the number you wish to format. In the example above, the
percentage sign (%) tells Xojo to display the number as a percentage, so
that the number is multiplied by 100 and displayed with the percentage
sign following it.
The chart below lists some of the possibilities for the format specification.
Character
Description
E or e
Page 60 of 363
numbers, and the third part is for zero. If only one format is specified, it will
be used for all numbers.
Format
Number
Formatted String
#.##
1.786
1.79
#.0000
1.3
1.3
0000
0005
#%
0.25
25%
###,###.##
145678.5
145,678.5
#.##e
145678.5
1.46e+05
-#.##
-3.7
-3.7
+#.##
3.7
+3.7
MsgBox stickerPrice!
So far you have seen a few ways to convert numbers into strings for
display, but you can also convert strings into numbers to use in
calculations. As mentioned earlier in the chapter, the best way to
accomplish this is by using the CDbl function:
Page 61 of 363
myNumericAge = CDbl(myAge)!
myAgeInTenYears = myNumericAge + 10!
Now that you have learned some things about variables, as well as getting
and setting their values, its time to build this chapters sample project,
called Introduce Yourself.
1)
In Chapter One, you used the Inspector to set the properties of a button on a window.
You may also use the Inspector to set the properties of the window itself. With no
objects on the window selected, the Inspector will modify the windows properties. You
are going to set three of the windows properties: title, width, and height.
2)
Page 62 of 363
3)
4)
Set the Labels text property to First Name: and its name to
FirstNameLabel.
5)
6)
7)
Add two more Labels, two more TextFields, and one PushButton to
the window, using the properties in the table below.
Control
8)
Name
Text
Caption
Label
LastNameLabel
Last Name:
N/A
TextField
LastNameField
N/A
N/A
Label
BirthYearLabel
Birth Year:
N/A
TextField
BirthYearField
N/A
N/A
PushButton
IntroduceButton
N/A
Introduce
9)
Page 63 of 363
Now that your interface is complete, you will need to write some code to
make your application functional. To add code, double click on
IntroduceButton and choose the Action event to open the Code Editor.
At the beginning of the chapter, you learned what this application will do.
As a reminder, it will calculate the end users full name and his or her age
at the end of the current year and then display this information to the user.
You will need four variables to make this happen.
1)
FullName is the string you will use to store the users concatenated first and last names.
CurrentAge will store the users age in years. Today will hold the current date (note that
the code above has already instantiated it, so it already contains data about the current
date). Finally, theMessage is a string that will put everything together to display to the
end user.
2)
Page 64 of 363
This code concatenates your users first and last names. To do this, you will access the
Text properties of your TextFields. The Text property holds whatever is visible in the
TextField. It is accessed using what is known as dot notation, which you have already
used when getting and settings properties for dates and colors. Dot notation is a way of
accessing properties by using the objects name, followed by a dot, followed in turn by
the name of the property, such as FirstNameField.Text. This should be familiar to you
from looking at string concatenation earlier in this chapter.
3)
Note: for the purposes of this project, you will ignore the month of birth and simply
calculate the age in years at the end of the current year; taking months into
consideration is not dicult, but it involves some skills that have not yet been covered.
You will retrieve the data entered by the user into BirthYearField. Remember, however,
that BirthYearField.Text will give you a string, which you will need to convert into
numeric data, using CDbl. You will subtract that number from the current year to
determine the users current age in years:
4)
theMessage =
You now have all of the data that you need to display to the end user. The next step is
to assemble it into a message to display to the end user. You will again do this through
string concatenation. To make your message more pleasing to the eye, you will also
add a line break after the users full name. This is accomplished using the EndOfLine
class.
Page 65 of 363
For historical reasons, OS X, UNIX, and Windows all denote line endings in
different ways. To account for this, Xojos EndOfLine class will
automatically use the correct line ending for the current platform, although
a platform-specific line ending can also be used when necessary. For the
most part, simply use EndOfLine and you should be fine.
5)
At this point, theMessage now contains Your name is , followed by the users full
name, which you have already calculated, followed by a line break. These lines of code
will build the rest of theMessage, including the users age.
6)
MsgBox theMessage!
Page 66 of 363
MsgBox theMessage!
7)
8)
9)
Page 67 of 363
This will tell Xojo to stop running your application before the CurrentAge
line is executed. To demonstrate, run your project now and fill in your
Chapter 2: Introduce Yourself!
Page 68 of 363
name and birth year. When you press IntroduceButton, you will see the
debugger:
As you saw in Chapter One, the current line of code is highlighted in gray
and the lower left pane provides us with a list of variables. Heres a closer
view of your variables:
Page 69 of 363
has not yet been executed. When you set breakpoints, be careful about
the location, or you may see unexpected results.
In the debugger toolbar, locate the Step button (see the screenshot
below).
Click on that button to step to the next line of code. The next line will now
be highlighted in gray and the variables pane will change to show the
calculated value of currentAge. You may continue to press the Step button
to walk through your code. If you are ready to return to your running
application, press the Resume button in the debugger toolbar.
If something has gone wrong enough that you need to return to your code,
press the Stop button.
Page 70 of 363
Page 71 of 363
Chapter 3: Where Do We
Go Now?
!
Page 72 of 363
For this chapters project, you will build a custom font previewer. By
default, it will list all fonts installed on the end users computer. When a
font is selected, your application will show a preview of that font. Your
application will also allow us to search for specific fonts as well. A
screenshot is provided below.
Page 73 of 363
different syntax, but the end result is the same. Once you learn how to use
If...Then in Xojo, you will be well on your way to using it in any other
language.
To use an example from above, imagine that you needed to check whether
a boolean was true or false:
End If!
Note that the If statement follows a certain structure. The line always
begins with If, followed by the expression to evaluate, followed by Then.
The next section of code is always automatically indented by Xojo, and it
will execute only if the expression evaluates to true. Following that code is
the final line: End If.
Page 74 of 363
Note that if you are checking the value of a boolean, you can omit the =
True or = False part of the expression:
End If!
If you have worked with any C-based languages in the past, you may notice
something interesting about Xojo. In most C-based languages, you must
use a double equal sign to compare data (If MyVar1 == MyVar2), whereas
here you are using only one equal sign. Xojo overloads its equal sign
operator so that it can be used for comparison or for setting values. In fact,
if you enter == into Xojo, it will issue a warning.
Else!
!
End If!
Page 75 of 363
You are, of course, not limited to checking only boolean values. If you
needed to check an integer, you may certainly do so:
Else!
!
End If!
In the above example, you are using the greater than symbol instead of the
equal sign. When using greater than or less than, remember that they are
not inclusive of the number you are comparing against. In other words, in
this example, if myAge were equal to 17, the message box would read,
You are not old enough to vote.
If you want your comparisons to be inclusive, you may use operators for
greater than or equal to and less than or equal to in your expressions:
Else!
!
End If!
You may use any data type with If. Here is an example using strings:
Page 76 of 363
Else!
!
End If!
Else!
!
End If!
Page 77 of 363
Often, youll need to determine whether one string contains another string.
For example, you may need to check if some data entered by the user
contains a particular keyword. This can be accomplished with the InStr
function. InStr takes two or three parameters and returns an integer. The
first parameter is an integer, and it is optional. It indicates the position
within the string to be searched that Xojo should begin searching. It
defaults to zero, and will be zero if unspecified. The second parameter is
the string to be searched (sometimes referred to as the haystack). The
third parameter is the string to search for (sometimes referred to as the
needle). The value returned by InStr is an integer that indicates where in
the source string the found string occurs. If it is not found within the
source string, InStr will return zero. Any non-zero result indicates that the
string has been found.
Page 78 of 363
haystack = "abcdefghijklmnopqrstuvwxyz"!
needle = "def"!
location = InStr(haystack,needle)!
//The needle was found and location = 4!
needle = "foo"!
location = InStr(haystack,needle)!
For example, assume that you have asked the end user for a short
paragraph about his or her background and that you need to issue an error
message if the user includes the word ninja anywhere in his or her bio.
Your applications interface would likely contain a TextField called BioField,
where the user would be expected to enter his or her biographical data.
Else!
!
End If!
If you remember back to the Introduce Yourself project that you built in
Chapter Two, you may recall that you asked your end user to enter his or
her birth year into a TextField. You then took that value and converted it to
an integer. What you did not do, however, is verify that the data could, in
fact, be numeric. Xojo has a function called IsNumeric that will check to
see if a strings value can be converted to numeric data. Its usage is fairly
simple:
Page 79 of 363
Else!
!
End If!
numberText = "Marbles"!
If IsNumeric(numberText) Then!
!
Else!
End If!
If you need to compare date values, the best way is to compare their
TotalSeconds properties:
End If!
You may use any other date properties for comparison as well, such as
year, month, day, etc. Or if you need to check a date to see if it is part of a
given year:
//Be cautious.!
End If!
Page 80 of 363
Whats all this about the end of the world? Some people believed that an
ancient Mayan prophecy predicted that the world would end in December
of 2012. Obviously, it didnt.
End If!
End If!
Page 81 of 363
There will be times when you will need to check for multiple conditions
and react accordingly. For example, a few paragraphs above, you checked
for ninjas. What if your code also needed to be aware of pirates, zombies,
and robots? In between the If and the End If, you may add an ElseIf. Or
you may add several ElseIf statements:
Else!
!
End If!
Page 82 of 363
Note that Xojo will jump to the end of the If statement as soon as one of
the conditions is met. In other words, if the code above encounters a
robot, the users bio will not be checked for references to pirates and
zombies. If you need to have a separate check for each, you must use a
separate If statement for each.
The ElseIf statement adds quite a bit of flexibility to Xojos logic. But once
you have added more than a few ElseIfs, your code can become unwieldy
fairly quickly. Fortunately, there is an easier way.
Case 2!
!
Case 3!
!
Case 4!
!
Case 5!
Chapter 3: Where Do We Go Now?!
Page 83 of 363
Case 6!
!
Case 7!
!
Case 8!
!
Case 9!
!
Case 10!
!
Case 11!
!
Case 12!
!
Else!
!
End Select!
You may also specify a default action by using Else, as seen in the above
example. Note that in a well written application, whatever action is
specified under Else should never happen, but your code should be
prepared to handle it either way.
Each Case statement may have a range of values as well. You may specify
a range by providing a comma separate list or using the To keyword. Here
is an example using both methods:
Case 4,5,6!
!
Page 84 of 363
Case 7 To 9!
!
Case 10 To 12!
!
Else!
!
End Select!
select case for such comparisons. Aside from that minor word change,
the functionality is identical.
MsgBox Str(counter)!
Next!
Chapter 3: Where Do We Go Now?!
Page 85 of 363
!
Next, run your project. You should see 10 message boxes, for number 1
through number 10. After dismissing all 10 message boxes, quit the
application.
You are not limited to using the counter alone. Change your code to the
following:
Next!
MsgBox Str(counter)!
Next!
Your counter may also skip numbers, using the Step keyword:
MsgBox Str(counter)!
Next!
Nearly every time that you use a For...Next loop, your code will do
something much more interesting than simply pop up a message box.
Chapter 3: Where Do We Go Now?!
Page 86 of 363
There are many times when you will have a group of similar objects. You
will often store these in an array. You will learn about arrays in depth in
Chapter Five, but for now, just think of an array as a numbered list of
similar objects or variables. This section and the next few sections will
cover how to step through groups of objects, but rather than get into the
details of how arrays work at this point, you will use an easy to access
array that is built into your computer: your fonts. Xojo has a built in
function called FontCount, which returns the number of fonts you have
installed. You will be using that function to gather your group of objects,
which in this case will be a list of fonts.
1)
2)
Open up Layout View for Window1 and add a TextArea control to the
window.
Size it so it takes up almost all of the window:
Page 87 of 363
3)
4)
Next!
This loop will continue to add font names to MyFontList. When the list is complete, you
will display it in the TextArea.
Dont worry about how Font(Counter) works. That will become clear in Chapter Five. For
now, just know that it gives you the name of the next font. The font name is followed by
a line break.
5)
Me.Text = myFontList!
All together, the code in your TextAreas Open event should look like this:
Next!
!
Me.Text = myFontList!
Chapter 3: Where Do We Go Now?!
Page 88 of 363
!
6)
7)
Remember that FontCount is a function built into Xojo. One thing to keep
in mind is that every time this loop runs, that function will also be run. If
you have a fast computer or few fonts, you may not notice the speed hit,
but there is a way to optimize this code. Add a new variable:
myFontCount = FontCount - 1!
You may wonder why you are subtracting one from FontCount. This is
because your computers fonts are stored in an array, and arrays in Xojo
are zero-based, as in most programming languages. That explanation may
not help much now, but it will become clearer in Chapter Five.
Page 89 of 363
8)
Now your loop will refer to the cached value instead of running the FontCount function
every time it runs. Your new code should look like this:
myFontCount = FontCount - 1!
!
For counter = 0 To myFontCount!
!
Next!
!
Me.Text = myFontList!
9)
Run your project, and you should see the same results.
You will likely not notice a speed dierence in this example, but as your projects grow
more complex, this type of optimization is good to know about.
10)
3.5 Do...Loop
Another kind of loop that is available in Xojo is the Do...Loop. A Do...Loop
is useful when you need to check for a certain condition each time the
loop runs. The Do...Loop has two forms, one of which does not guarantee
Page 90 of 363
that the loop will be run at least once, and one that does make such a
guarantee.
Here is an example of a Do...Loop (as with all of the exercises in this book,
feel free to create a new desktop project in Xojo and enter this code in
Window1s open event to try it out):
Dim x As Integer!
x = 1!
Do Until x > 100!
x = x * 2!
MsgBox Str(x)!
Loop!
If you run this project, you will see a series of message boxes, each a
number twice as large as the preceding number: 2, 4, 8, 16, 32, 64, 128.
After you reach 128, the loop stops, because you told the loop to end
once x is greater than 100. Now lets try a slightly dierent version of this
loop. Set x to 101:
Dim x As Integer!
x = 101!
Do Until x > 100!
x = x * 2!
MsgBox Str(x)!
Loop!
Run the project again, and no message boxes will appear. This is because
the condition (x > 100) has already been met, so the loop exits. However, if
you change the loop again, you should see a dierent result:
Dim x As Integer!
Chapter 3: Where Do We Go Now?!
Page 91 of 363
x = 101!
Do!
x = x * 2!
MsgBox Str(x)!
This time, one message box will appear containing the number 202. When
the Until keyword is at the end of the loop, your loop is guaranteed to run
at least once. If the Until keyword is at the beginning of the loop, the loop
may not run at all, depending on whether the condition is already met.
3.6 While...Wend
A third type of loop that you will learn about in this chapter is the
While...Wend loop (Wend is shorthand for While End). This is similar to the
Do...Loop. Here is a code example:
Dim x As Integer!
While x < 100!
!
x = x + 1!
Wend!
MsgBox Str(x)!
When run, this code will display a message box containing the number
100. The While...Wend loop is particularly useful when dealing with
databases, as you will see in Chapter Twelve.
Page 92 of 363
Exit!
End If!
You will add this code just inside the For...Next loop, so that your
completed code looks like this:
myFontCount = FontCount - 1!
!
For counter = 0 To myFontCount!
!
End If!
Exit!
Next!
!
Me.Text = myFontList!
Page 93 of 363
If you run this project, the TextArea that used to contain your full font list
will now only list fonts up to (and excluding) Courier New. If you want
Courier New to be included in the list, you would move your If...Then
statement to after the line that builds your list of fonts:
Exit!
End If!
Using the Exit statement to break out of a loop is another good way to
optimize your code so that your end user spends less time waiting.
Another way to modify the behavior of your loops is with the Continue
statement. Suppose that you had a loop such as this (this is pseudo-code
and is not meant to be run):
Dim x As Integer!
For x = 1 To 100!
DoMyFunction(x)!
DoAnotherFunction(x)!
DoAThirdFunction(x)!
Next!
Dim x As Integer!
For x = 1 To 100!
!
DoMyFunction(x)!
Page 94 of 363
If x = 72 Then!
End If!
DoAnotherFunction(x)!
DoAThirdFunction(x)!
Continue!
Next!
The Continue statement tells Xojo to stop that iteration of the loop and go
back to the start. Here is a way to run only the first function for even
numbers, while odd numbers would have all three functions executed:
Dim x As Integer!
For x = 1 To 100!
DoMyFunction(x)!
If x Mod 2 = 0 Then!
End If!
DoAnotherFunction(x)!
DoAThirdFunction(x)!
Continue!
Next!
Page 95 of 363
1)
2)
3)
Name
TextField
SearchField
TextArea
PreviewField
ListBox
FontListBox
Design your interface as you see fit, using your own creativity. You may want to use this
interface as a guide:
4)
Page 96 of 363
With the controls added, your window may look like this:
Your interface is now complete. This project will have much more code than the
previous chapters project, but it will also do a lot more. The ListBox, which was named
FontListBox, will display a list of all of the fonts installed on the computer. Clicking on
the name of one of those fonts will update PreviewField and change the font to the
selected one. The small TextField above FontListBox, which was named SearchField,
will allow the end user to search for fonts on the computer. The user will be able to
enter all or part of a fonts name, at which point FontListBox will be updated to show
only those fonts that match.
With that in mind, the first thing you need to do is build your font list. You will be dealing
with more controls and events than you have learned about so far, but dont be
concerned with the technical details at this point. These issues will be covered in depth
in Chapter Six. To build your font list, double click on FontListBox to open it in the Code
Editor.
5)
Page 97 of 363
Me.AddRow(Font(counter))!
Next!
Most of that code should look familiar. You are using the FontCount function to
determine the number of fonts on the computer and looping through them with a
For...Next loop. On each iteration of the loop, you add a new row to FontListBox. Note
that in any of a controls events, using Me refers to the control. So this line:
Me.AddRow(Font(counter))!
FontListBox.AddRow(Font(counter))!
Using Me instead of the controls name is simply shorthand, although it can come in
very handy if you ever change the controls name later on.
6)
PreviewField.TextFont = Me.List(Me.ListIndex)!
End If!
The Change event occurs when the user selects or deselects a row in the ListBox.
Because the user could be deselecting, you need to check whether or not a row is
selected. Again, dont worry too much about how the code works. It will become clear
in later chapters.
7)
Page 98 of 363
8)
9)
This event occurs whenever the text inside the TextField is modified, whether by typing,
deleting, or pasting. The code in this event will be similar to the code in FontListBoxs
Open event, but you will need to do some checking. This code starts by declaring your
variables.
You have your SearchString, plus two integers: Counter and MyFontCount, which
should be familiar from the above examples.
10)
myFontCount = FontCount!
This optimization is even more important here, since this code will run every time a
letter is typed or deleted in SearchField. Because it will run so often, you need to make
it as fast as possible.
11)
End If!
This checks if your SearchField contains any text. If it does, youll loop through your
fonts and display any matching items. If not, youll display the full font list.
There are two paths that this code can take. First, if SearchField is not empty, you will
loop through your fonts and display only those whose names contain the SearchString.
The following code will accomplish that:
Page 99 of 363
searchString = Me.Text!
For counter = 0 To myFontCount -1!
End If!
FontListBox.AddRow(Font(counter))!
Next!
On the other hand, if SearchField is empty, you should assume that the end user wants
to see all of the fonts installed on the computer. Here is the code for that (note that it is
very similar to the way you originally filled up FontListBox):
FontListBox.AddRow(Font(counter))!
Next!
12)
FontListBox.DeleteAllRows!
You will learn about this step in greater detail in Chapter Six.
When all is assembled SearchFields TextChange event should look like this:
!
myFontCount = FontCount!
!
If Me.Text <> "" Then!
!
searchString = Me.Text!
FontListBox.DeleteAllRows!
End If!
FontListBox.AddRow(Font(counter))!
Next!
Else!
!
FontListBox.DeleteAllRows!
Next!
FontListBox.AddRow(Font(counter))!
End If!
13)
Choosing any font from the list should cause PreviewField to be updated with that font.
Entering some text into SearchField should cause FontListBox to display only those
fonts that match. As a bonus, you can change the text used for the preview to anything
you like.
14)
!
For counter = 0 To myFontCount -1!
!
Me.AddRow(Font(counter))!
Next!
You had some very similar code in the SearchFields TextChange event:
FontListBox.AddRow(Font(counter))!
Next!
The code isnt quite identical, but its very close. In fact, if you replaced
Me.AddRow with FontListBox.AddRow inside your If statement, the code
would be completely identical and would still function exactly the same.
To illustrate, lets look at a real world example. Imagine that I asked you to
make me some spaghetti. If you didnt know how to make it, I could tell
you (in very general terms):
1)
2)
3)
4)
5)
6)
If I asked you for spaghetti again next week, you would know how to make
it, whether from memory or from writing down the steps. In other words,
you would have a method for preparing spaghetti.
CookSpaghetti!
In this chapter, you will learn about methods and functions, and you will
make some changes to your Font Previewer project to streamline your
code using methods and functions.
First is the Method Name. Call your method FillFontListBox. For now,
Parameters and Return Type should be left blank. In the Code Editor
below Return Type, enter the following code:
FontListBox.DeleteAllRows!
For counter = 0 To MyFontCount -1!
!
FontListBox.AddRow(Font(counter))!
Next!
This code should look familiar; its the code you used to list your fonts in
FontListBox. Now, navigate to FontListBoxs Open event. Delete all of the
code there and enter this:
FillFontListBox!
Run your project. Its behavior should be identical, because when the
computer reaches the line of code that says FillFontListBox, it refers
back to your method and runs each line of it.
searchString = Me.Text!
FontListBox.DeleteAllRows!
End If!
Next!
FontListBox.AddRow(Font(counter))!
Else!
!
FillFontListBox!
End If!
Run your project again, and again, it should behave identically. Quit your
application.
If you look at the code in SearchFields TextChange event, you still have
some similarities there. The code to fill FontListBox with only matching
fonts certainly isnt identical to your other code, but it is definitely similar.
4.3 Parameters
Weve talked about spaghetti already. Some people, but not all, prefer
meatballs with their spaghetti. Your theoretical CookSpaghetti method can
handle the spaghetti, but how do you tell it to add meatballs, and only
some of the time at that?
Methods can take parameters. A parameter is a piece of data that you give
to a method; the method can either do something directly to that piece of
data or use it to determine how to function. Your CookSpaghetti method
might take a boolean called AddMeatballs as a parameter. If AddMeatballs
is true, CookSpaghetti would mix together some meat, spices, and bread
crumbs, and then add those to the meal.
FontListBox.AddRow(Font(counter))!
Next!
FontListBox.DeleteAllRows!
For counter = 0 To myFontCount -1!
End If!
FontListBox.AddRow(Font(counter))!
Next!
There are only two lines of code that are dierent: the If statement. Youre
going to add that code to the FillFontListBox method by giving it a
parameter.
1)
searchString As String!
Every parameter needs to have a name and a data type, just like a variable. In fact, you
can think of a parameter as a variable that can be used inside the method. If necessary,
toggle the disclosure triangle next to the line that says, Sub FillFontListBox at the top.
2)
Giving a method its parameter when you run it is called passing the parameter. You
need to pass a string to FillFontListBox in two places: in FontListBoxs Open event and
in SearchFields TextChange event.
3)
FillFontListBox("")!
You can do this because you have no font names to search for or match. In
SearchFields TextChange event, things will be a bit more complicated, because youre
going to move most of the logic into the FillFontListBox method. SearchFields
TextChange will now look like this:
FillFontListBox(Me.Text)!
You no longer need to check for a blank string or modify your codes behavior or even
declare any variables, because all of that will now happen in the FillFontListBox method
which you will now need to expand:
!
FontListBox.DeleteAllRows!
!
If searchString <> "" Then!
!
FontListBox.AddRow(Font(counter))!
Page 110 of 363
Next!
End If!
Else!
Next!
FontListBox.AddRow(Font(counter))!
End If!
All of the logic that was previously found in SearchFields TextChange event is now
contained in the FillFontListBox method. In changing the project this way, you have also
eliminated a lot of duplicate and near-duplicate code.
Returning to the spaghetti dinner, it is well known that many people enjoy
garlic bread with their spaghetti, whether or not they have meatballs. The
imaginary CookSpaghetti method will not accept multiple parameters, but
this is no problem. You can give it addMeatballs As Boolean and
includeGarlicBread As Boolean. To add multiple parameters to your
Chapter 4: Getting Things Done!
method declaration in Xojo, simply enter them into the Parameters field
and separate them with commas:
includeGarlicBread As Boolean!
Suppose now that the chef insisted that every patron should receive garlic
bread unless he or she specifically asks for it not to be included. You could
change the Parameters field to this:
What this line of code does is not only describe the parameter, but gives it
a default value. Of course, this is not limited to boolean values:
FillFontListBox("")!
Thats just two double quotes, or an empty string. That tells the method
that if you do not specify what the searchString should be, it should
assume that there isnt one. Now you can change the Open event of
FontListBox to this:
FillFontListBox!
Run your project. Once again, its functionality is identical to what it was
before, but youve streamlined and simplified your code.
4.5 Comments
You may have noticed that in a few of the examples used here, there have
been lines of code that start with two slashes followed by a note. These
Chapter 4: Getting Things Done!
A comment can be added in two ways: the double slash and the single
quote. They are interchangeable and can be added anywhere in your
code. You may choose to enter a full line of comments:
Or you may enter your comment part of the way through an existing line of
code:
Note that anything entered on a line after the comment marker will be
considered part of the comment.
There are times when it is helpful to turn lines of code into comments
temporarily. This is especially true when trying to track an error. You may
do this manually, by typing the double slash or the single quote in front of
each line. Xojo also has a feature that will comment/uncomment several
lines of code at one time. Highlight the code you wish to comment out,
and then choose Comment from the Edit menu. If the code is already
commented with single quotes, this command will uncomment it.
1)
This method will find out if a font has been selected in FontListBox and if so, return its
name to us.
currentFont = FontListBox.List(FontListBox.ListIndex)!
Else!
!
currentFont = ""!
End If!
Return currentFont!
Chapter 4: Getting Things Done!
!
Now the interface for your Font Previewer needs to be modified.
2)
3)
4)
5)
6)
7)
Now its time to simplify the code in FontButtons Action event. You have
accessed the return value of the GetSelectedFont method by using this
line of code:
fontName = GetSelectedFont!
!
Run your project again, and you should see identical behavior, but once
again, with simpler code.
4.7 Scope
With all of these methods, you have variables all over the place in your
code. And thats fine. But it is important to remember that these variables
are not accessible everywhere. This is because of something called scope.
In this chapter, you will use arrays and build on your knowledge from
previous chapters to build a to do list manager. One big dierence is that
this app will be a web app. Here is what youll be making (this copy of the
app is running in Firefox on a Mac, but it can run in any modern browser
on any operating system):
Many times, you will not know how many items are in an array. You can
ask Xojo how many items are in an array by using the Ubound function
(Ubound is short for upper bound). Ubound will return the number of the
arrays highest element:
myArrayCount = Ubound(myStringList)!
using strings up until now. For example, you can display a string to the
end user by using a message box:
MsgBox myString!
You cant display an array to the end user in the same way. However, you
can display one of the strings in your list. If you wanted to display the first
item in your list of strings, you could use this code:
MsgBox myStringList(0)!
Note that the first item in an array is item number zero. There are historical
reasons why this is the case, but its worth keeping in mind, because one
of the most common errors made when working with arrays is starting at
number one instead of number zero. This also means that the last (highest
numbered) item in the array is one less than the upper bound. If an array
has ten items, the highest numbered item (and its Ubound) is nine.
So you can treat myStringList(0) in the same way that you treat any other
string. If you want to assign a value to it, you can do so:
And you can do the same with myStringList(1), myStringList(2), and so on.
Each item in the list is just a normal variable. So in the case of an array of
strings, each item is just a regular string. If you had an array of integers,
each item would be a regular integer. To declare an array of integers, use a
syntax similar to what you used above:
Again, this would give us an empty list of integers. If you wanted to specify
the number of items in the list, do so as you did above:
That would give us a list with six items. As you can see, you create and
treat arrays the same regardless of what type of data they hold. In a similar
vein, you treat each item in an array as a normal variable of its data type.
Creating an array is one thing, but an array isnt valuable until it contains
some items. You refer to an item in an array as an element. To add an
element to an array (or to add an item to a list), you may use Append or
Insert.
When you Append data to an array, the item is added to the end of the
array, and the number of items in the array (as well as its Ubound) is
increased by one:
It may not always be the case that you want to add data to the end of the
array, though. If you need to insert data at a specific location, use the
Insert method. Where the Append method only takes one parameter (the
value you wish to add to the array), the Insert method takes two: first, an
integer that specifies the items location in the array, and then the item
itself. An items location in the array is known as its Index. Using the Insert
method will increase the number of elements in the array by one, and will
Chapter 5: Making A List!
also increase the index of each successive item by one. This is best
illustrated with a code example:
Index
Value
Larry
Curly
Moe
stooges.Insert(1, "Shemp")!
Ubound(stooges) is now equal to three, and the array itself looks like this:
Index
Value
Larry
Shemp
Curly
Moe
stooges.Remove(2)!
Ubound(stooges) is now equal to two, and the array itself looks like this:
Index
Value
Larry
Shemp
Moe
Removing one element at a time is certainly useful, but there will be many
occasions in which you need to remove all elements from an array at once.
While you could certainly use a For...Loop and remove each element
manually, that would be time consuming and error prone. Fortunately, Xojo
includes a ReDim keyword. It operates a similar way to the Dim keyword,
except that it only works on a variable thats already in existence:
ReDim stooges(-1)!
The stooges array is now empty and contains no elements. Its Ubound is
now negative one.
But you will encounter situations in which you want to reorder the
elements in your array. There are certainly brute force methods of doing
this, but Xojo includes two array functions that are very useful for
reordering arrays.
The most obvious way to reorder the elements in an array is to sort them.
To do so, simply use the Sort method:
contacts.Sort!
Index
Value
Abe
Mary
Zeke
cards.Shuffle!
The cards will now be in random order. Thats all there is to it. Shue
works on any type of data, and it is completely random. If you shue the
same array twice, you will most likely get dierent results each time (there
is a statistically insignificant chance that the computer could produce the
same exact set of random numbers twice in a row, but its so small that its
barely worth mentioning).
Now imagine that you needed to turn this string data into an array. You
could use the InStr function that you learned about in Chapter Three to
find all of the commas and parse the data yourself. Or you could use the
Split function. Split will take a string and separate it into an array, based on
the delimiter you give it. Returning to the tagging example above:
The array Tags would then contain one element for each piece of the string
that was separated by a comma. If the user entered Movies, Comedy,
90s as listed above, the Tags array would have three elements:
// tags(0) = "Movies"!
// tags(1) = "Comedy"!
// tags(2) = "90s"!
The Join function works in the opposite way. Join takes an array of string
and a delimiter, and builds one long string:
Index
Value
Abe
Mary
Zeke
Key
Value
Abe
Mary
Zeke
Xojo does not have associative arrays, but it does have a data type called
Dictionary that is similar to an associative array in many ways. It can be
used to store lists of data, but the order of the data is not maintained.
Also, instead of using a simple numeric index to track its position in the
Chapter 5: Making A List!
list, the Dictionary uses a Key/Value relationship, where both the Key and
the Value can be of any data type. The Dictionary is technically a class, so
it must be instantiated before it can be used (similar to the Date data type
you learned about in Chapter Two).
To create a Dictionary, use the Dim keyword, just as with other data types:
!
!
Notice that this example used the shorter method of instantiating your
variable by including the New operator on the same line as the Dim
keyword.
To add data to an array, you used the Append and Insert methods. The
Dictionary has no such method. Instead, you set a Value and provide a
Key:
settings.Value("Trainer") = "Kenobi"!
If you take a look at the code above, you may notice that you have used
strings, an integer, and a boolean as Values in your Dictionary. This is
perfectly fine; the Dictionary can use any data type as a Value, or as a Key,
unlike arrays, in which each element must be of the same data type.
Although it may not be obvious from the example, you have provided Keys
as well. Take this line of code for example:
The Key in this line is Dark Side and the Value is a boolean, which
happens to be true in this example. So in essence, you are storing data
very much like an array, but you are manually assigning the Key rather than
using a numeric index.
Why is this useful? Suppose you wanted to retrieve information from the
Dictionary, such as the Value you stored with the Title Key. Continuing
the code above:
theTitle = settings.Value("Title")!
// theTitle = "Sith Lord"!
MsgBox theTitle!
Because you can use anything for the Key, a common error is a
KeyNotFoundException, which occurs when you attempt to retrieve a
Value for a Key that doesnt exist. To avoid this error, name your Keys
carefully and logically so you can easily remember them.
If you encounter a situation where you know what the Key should be, but
are unsure if it exists or not, you may use the Lookup function. The Lookup
function takes two parameters: the first is what you believe the Key to be
and the second is a default value to use if the Key can not be found. In
your Dictionary above, you havent set a Value for a Lightsaber Color
Key, but can try to access it anyway:
Because the Lightsaber Color Key does not exist, the message box in
this case will display Red. If you use an existing key:
MsgBox settings.Lookup("Title","Pilot")!
... then youll see the Value from the Dictionary as expected.
!
To check for the existence of a specific Key, use the HasKey function.
HasKey takes the Key youre looking for as a parameter and returns a
boolean: true if the Key exists and false if it does not:
If settings.HasKey("Mentor") Then!
!
Else!
!
End If!
To remove an entry from the Dictionary, use the Remove method, which
takes the Key as its parameter:
settings.Remove("Dark Side")!
To remove all entries from the Dictionary at once, use the Clear method:
settings.Clear!
1)
If you havent already done so, launch Xojo and create a new Web
Application. Save it as ToDoList.
To start, youll build the interface, then add your code later. The following table lists the
types and names of controls you will need. As before, dont worry too much about
where each control should be positioned; use the screenshot at the beginning of the
chapter as a guide, but feel free to use your creativity as well.
Control
Name
Caption
WebTextField
ToDoField
N/A
WebButton
AddButton
Add
WebListBox
ToDoListBox
N/A
WebButton
ShuffleButton
Surprise Me
WebButton
SortButton
Sort
WebButton
CompleteButton
Complete
Your end user will enter To Do Items into ToDoField, then click AddButton to add them
to ToDoListBox. The data for ToDoListBox will be stored in an array behind the scenes.
2)
Control
Lock
ToDoField
AddButton
Top, Right
ToDoListBox
ShuffleButton
Left, Bottom
SortButton
Left, Bottom
CompleteButton
Right, Bottom
To lock a control, simply click the padlock under Locking in the Inspector. A
locked padlock indicates that that edge of the control is locked, while an
unlocked padlock, naturally, indicates the opposite.
3)
Add a property to WebPage1. Its type should be String and its Name
should be ToDoList().
In the last chapter, you learned a bit about scope, or where a variable can be accessed.
Because every control on your window will need access to your array of To Do Items,
you cant simply declare it in a method. You need to make it a property of the web
page. Adding a property to a web page (or a window in a desktop app) means that it is
accessible from any code on that web page, whether its part of a method you create or
in a controls event.
4)
5)
For i = 0 To toDoCount!
!
ToDoListBox.AddRow(toDoList(i))!
Next!
6)
ToDoField.Text = ""!
This code provides a way for your end user to get data into the array. The data will
come from ToDoField, and ToDoButton will do the work of adding it to the array. It will
then run the UpdateToDoListBox method. Finally, it will clear the contents of ToDoField
so that your user doesnt accidentally add the same item multiple times.
As noted above, the first line adds your users text to the array. The second line updates
your display. And the third line clears out any existing text in ToDoField. If you run the
project now, you should be able to add items to the list.
7)
toDoList.Remove(ToDoListBox.ListIndex)!
UpdateToDoListBox!
End If!
Any good To Do List Manager should also allow you to mark items as complete. That
will be the job of CompleteButton. Its job will be more complex than it may appear.
First, it will need to determine if a To Do Item is selected. If one is selected, it will need
to determine its position in the array and then remove it. Finally, it will update your
display. You may recall from a previous chapter that you can find out which row in a
ListBox is selected by checking its ListIndex property. If the ListIndex equals negative
Chapter 5: Making A List!
one, nothing is selected. Otherwise the ListIndex will be the row number that is selected
(as with arrays, ListBoxes are zero-based, so the first row is number zero).
8)
UpdateToDoListBox!
9)
UpdateToDoListBox!
Finally, you want to allow your end users to sort and shue their To Do Items. The
previous two steps provide that functionality.
In reality, randomizing the order of your To Do Items probably has very little practical
value, but this is just an example that can be applied to other apps and concepts.
10)
11)
Events are just that: things that happen. An event can be triggered, or
fired, by the user clicking on a button or typing into a field. Or it could be
Chapter 6: May I Take Your Order?!
something initiated by the computer. In this chapter, you will learn about
some events that are commonly used.
For example, many controls have an event called Open. This event fires
when a control is first being created (or in technical terms, instantiated) on
a window. You may have a popup menu that needs to have a specific set
of items to choose. You can set up those items in the popup menus Open
event.
Your popup menu also has a Change event that fires when the user makes
a selection. You can use the Change event to respond to the users choice.
Events are not limited to controls. Your windows (note: the interface
element, not the operating system!) also have events. For that matter, your
application itself has events!
6.3 Windows
Remember, this is not the operating system, its the interface element on
your screen that contains other controls.
1)
2)
3)
Listbox1.AddRow("Open")!
Once your ListBox is in place, click on the window background, then go to the Insert
menu and choose Event Handler (its important to make sure the window itself is
selected, because Xojo will add the event handler to whatever control is selected). A list
of events will appear. Select the Open event and press the OK button. You will be taken
to Window1s Open event.
4)
5)
6)
Click away from your application and back to it. Drag the window
around. Click in the window outside the ListBox.
You should see the events being populated in your ListBox.
7)
This should give you a rough idea of how events happen. When you move
the window, switch applications, or click in the window, the events you
implemented are fired. Actually, the events are fired no matter what; its
simply a matter of how you choose to respond to them.
Another helpful event is the Close event. As implied by its name, this event
fires when the window is closing. This is a good event to use to store
things like the windows position so that you can present it to your user in
the same way the next time it is opened.
Windows have other events that wont be covered in this book. You are
encouraged to explore these events on your own. The ListBox method
above is an excellent way to learn what triggers dierent events.
Xojo is not the only language that uses events; many other languages use
them as well, such as Java, JavaScript, and C++.
A window also has several properties related to its size. The most obvious
are its width and height, which are expressed in pixels. Its important to
Chapter 6: May I Take Your Order?!
Thats not to say that users with larger displays wont be able to resize
your window to fit. Thats where two more window properties come into
play: MaxWidth and MaxHeight. These numbers indicate how large the
window is allowed to become. The default value for both properties is
32,000 pixels, which is so large that no user is likely to run into that
limitation. If you need to set a smaller maximum size, use these properties
to do so.
On the other hand, you may also need to define a minimum size for your
window using the MinWidth and MinHeight properties. These properties
determine how small a user can make the window. For example, you may
have certain interface elements that require a certain amount of space.
Using MinWidth and MinHeight, you can guarantee that the user will not
be able to resize your window to too small a size.
The maximum and minimum widths and heights assume that your
windows size is adjustable at all. You can set this using the Resizable
property. If Resizable is true, the user will be able to shrink or expand your
window using the operating systems native abilities. If it is false, the user
will be unable to do so (although you may still set the width and height in
code when necessary).
On most modern operating systems, windows have three buttons built into
the windows themselves: close, minimize, and maximize (sometimes
called zoom). You can decide whether you want these buttons to be active
or not by setting the CloseButton, MinimizeButton, and MaximizeButton
properties. Depending on what operating system your application is
running on, the buttons may still appear, but will be disabled.
6.4 Input
In earlier chapters, you used a TextField to get information into your
application. The TextField is one of several input controls that you may use
in your projects, the others being TextArea, PasswordField, and
ComboBox. In this section, you will learn about the events and properties
of each of these controls.
But first, all of these controls have some properties and events in
common. For example, all four input controls have properties to set their
size and position: Left, Top, Width, and Height. These are all measured in
pixels. Note that the Left and Top properties are relative to the window
thats holding the control and not the screen itself.
Also, all four of these controls have a Name property. Like a windows
Name property, this is the name by which you will refer to the control in
your code. Again, it is good practice to give your controls meaningful
names related to their purpose, such as FirstNameField or UsernameField.
firstName = FirstNameField.Text!
Sometimes your user will have some of the text selected. The TextField,
TextArea, and PasswordField have a property called SelText, which will
give you only the selected text. If you wanted to grab the selected text
from a TextField called FirstNameField, you could use the following code:
currentSelection = FirstNameField.SelText!
Other times, you may need information about the selected text, such as its
length or position, without needing to know exactly what the selected text
is. All four of the input controls have two properties called SelStart and
SelLength. SelStart will give you the position of the first selected character
and SelLength will give you the length of the selection text.
The TextField itself is a simple text box that allows the user to enter plain
text. It doesnt support inline styles like bold or italics or dierent fonts.
However, you can set the entire TextField to be bold or italic or a specific
font. Whatever style, font, and text size you choose will be applied to the
entire TextField.
This diers from the TextArea control, which has a Styled property. If the
Styled property is set to true, your TextArea can support multiple fonts,
text sizes, and styles. These styles can be a result of text thats pasted in
from an outside source or they can be set by your code. A few paragraphs
ago, you were introduced to the SelText, SelStart, and SelLength
properties. The TextArea, since it supports styled text, builds on these by
adding some style related selection properties: SelBold, SelItalic, SelFont,
Chapter 6: May I Take Your Order?!
BiographyField.SelBold = True!
Setting SelBold back to False turns o the bold style. Most style buttons
toggle a style on and o, which you could do with this code:
That code would toggle the bold style on or o without needing to know
the current state. The Not keyword in the above example indicates
opposite meaning, so that you can toggle the Bold property on or o
without needing to know its current state.
The SelFont property takes a string, the name of a font, rather than a
boolean. The SelTextSize property takes an integer, which sets the text
size in points.
Me.AddRow("6")!
Me.AddRow("7")!
Me.AddRow("8")!
Me.AddRow("9")!
Me.AddRow("10")!
Me.AddRow("11")!
Me.AddRow("12")!
The ComboBox allows the user to choose one of the options presented or
enter his or her own by treating it as a TextField.
The AddRow method used in the last code example allows you to add
choices to a ComboBox. You will see similar methods in other controls
later in this chapter. AddRow takes a string and adds a new row to the end
of the list of choices in a ComboBox. If you should need to add a new row
in a certain location, you can use the InsertRow method. InsertRow takes
an integer indicating where in the list youd like to insert the new row as its
first parameter, followed by a string with the text youd like to add (as with
arrays, the rows in a ComboBox are zero-based).
If you should need to clear out all of the rows from a ComboBox, it also
has a method called DeleteAllRows, which does exactly what its name
indicates.
While its not technically an input control, this is a good time to learn about
the Label, a control whose function is primarily decorative. Its purpose is
to serve as a label for other controls, such as TextFields, TextAreas, and
others. Because of this, its Caption is also very important. You used labels
in the sample project from Chapter Two. In a well designed application,
many of your controls will have corresponding Labels.
6.5 Buttons
In this section, you will learn about dierent types of buttons. You may
wonder why you would have more than one kind of button, but each
serves a slightly dierent purpose. Choosing the right interface element for
the right task is a fundamental part of user interface design.
Xojo oers several types of buttons, but you will only learn about three of
them in this section: PushButton, BevelButton, and SegmentedControl.
The most important commonality along these buttons is the Action event.
Simply put, the Action event is fired when the button is clicked.
As with the input controls discussed above, these buttons also have
properties related to their size and position: Left, Top, Width, and Height.
You will find this to be a common thread among all controls. Also, each of
these buttons has a Name property; again, the buttons Name is how you
refer to the button in your code. As with all controls, it is best to give your
buttons meaningful names that are related to their purpose, such as
CancelButton, SendEmailButton, etc.
The PushButton is the simplest of these controls, and is one of the most
common interface elements. In addition to its Name property, it also has a
Caption, which is the text that will be displayed on the button. You can
also change the font, size, and style of the text in your Caption, but unless
you have a compelling reason to do so, its always best to leave those
properties set to the default values; that way, the button will look and
behave as it should on any operating system.
Although most interactions with PushButtons are done with the mouse, it
also has two properties related to the keyboard: Default and Cancel. If
Default is set to True, the PushButton will respond to the enter key on your
keyboard. If Cancel is set to True, it will respond to the escape key.
The BevelButton, like the PushButton, also has a Caption. In fact, it can
almost be used as a PushButton. But there are some dierences. First, the
BevelButton does not have Default and Cancel properties, so it cant
respond to the keyboard in the same way as the PushButton. Second,
while you can make it behave like a PushButton, it doesnt look like a
PushButton, so you need to be careful about where you use them.
1)
2)
3)
4)
5)
6)
A common use for a BevelButton that toggles is to set styles for text.
7)
8)
9)
Add another BevelButton with the Caption Italic and the Name
ItalicButton.
10)
ItalicButton.Value = Me.SelItalic!
11)
StyleDemoField.SelBold = Me.Value!
12)
StyleDemoField.SelItalic = Me.Value!
13)
14)
15)
As you can see from this example, by using the events and properties of
your controls, you can begin to build some complicated interactions.
Based on this example, it wouldnt take much more work to add more
styles, as well as font choices and text sizes.
16)
By default, your SegmentedControl will have two items: One and Two. You can edit
these or add more using the Inspector, but for now, stay with the default.
17)
MsgBox theChoice.Title!
Before you run your project, lets examine the code. The first line creates a variable
called theChoice, with a data type of SegmentedControlItem. Remember from above
18)
19)
Switch back and forth between the segments. You should see a
message box with the item name on each change.
20)
6.6 Pickers
Another category of controls is known as pickers. These controls are used
to allow the end user to set options and make choices. In this section, you
will learn about CheckBox, RadioButtons, Sliders, UpDownArrows, and
PopupMenu. As with the other controls discussed in this chapter, these
controls have the usual group of properties related to size and position:
Left, Top, Width, and Height.
The CheckBox is best used when the end user needs to turn an option or
setting on or o. Youve most likely encountered these before in
applications or even in web forms. The CheckBox has a Name property,
which is how you refer to the CheckBox in code, and a Caption property,
which is the text label presented to the user.
The most important property of the CheckBox is its Value property. When
the CheckBox is checked, its Value property is True. When the CheckBox
is unchecked, its Value property is false.
The CheckBox also has an Action event, which is triggered when the user
checks or unchecks it.
1)
2)
3)
4)
Notice that when you select one RadioButton, the others are
deselected.
5)
Suppose you wanted two distinct sets of choices. Imagine you were
writing an application for taking sandwich orders, and each person
ordering could order one meat and one cheese. RadioButtons might be a
good way to design this interface.
6)
7)
8)
9)
Why are they called radio buttons anyway? On early car radios, you
were given five or six buttons, each of which you could assign to one of
your favorite radio stations (remember, this was before the age of iTunes,
Sirius, and Spotify). Because you could only listen to one station at a time,
when you pushed one button in, any previously selected buttons would pop
out and become unselected. Radio buttons on the computer work
similarly, in that they only allow you to have one selected option.
10)
11)
12)
13)
14)
15)
16)
Notice that the three RadioButtons inside the Canvas act as a group,
while the RadioButton outside the Canvas is unaected by their
selections.
17)
The Slider is a great way to allow your user to select a numeric value
within a certain range, for example, if you need the user to select a number
between 1 and 100. To set these limits, use the Sliders Minimum and
Maximum properties. In the Inspector, you may notice another property
listed between them, called Value. This is the numeric value that the Slider
will have as a default until the user changes it or until your code changes
it.
1)
2)
3)
4)
TextField1.Text = Str(Me.Value)!
5)
6)
Change the value of the Slider and watch as its Value is updated in
the TextField.
7)
In addition to responding to the user, you can set the Value of a Slider in
your code as well, using this syntax:
MySlider.Value = 50!
1)
2)
3)
4)
TextField1.Text = Str(i)!
5)
TextField1.Text = Str(i)!
6)
7)
8)
The final control in the pickers category that will be covered is the
PopupMenu. This is easily the most complicated of the group, but it is also
a powerful control. As with all other controls, it has a Name property that
you can set in the Inspector; this is the name you will use to refer to it in
your code.
Most of the other properties of the PopupMenu that you will use on a
regular basis will be accessed through code. The property you may use
most often is the ListIndex property. The ListIndex indicates which item in
the PopupMenu has been chosen (this list is zero-based).
But before you will have a ListIndex to work with, youll need to add some
items to your PopupMenu. This is done using the AddRow method.
1)
2)
3)
Me.AddRow("Window")!
4)
The Change event is triggered when the user makes a selection from the PopupMenu.
5)
6)
Choose an item from the menu. You should see a message box with
the item youve selected.
7)
As you can see in the example above, the AddRow method takes a string
as its parameter. This string is the text that will appear for that menu item.
AddRow will always add a menu item to the end of the list. If you need to
insert a menu item at a specific place, you can use the InsertRow method.
InsertRow takes two parameters: first, an integer indicating its position in
the list (again, this list is zero-based), and then a string that will appear for
that menu item.
When the user makes a choice, the PopupMenus ListIndex is set. The
ListIndex is an integer that indicates the number of the item that was
selected. To access the text associated with that item in the menu, use the
PopupMenus List property. List is an array, so youll often access the
selected item with syntax like this:
myChoice = MyPopupMenu.List(MyPopupMenu.ListIndex)!
For the record, you can also access the visible text on a PopupMenu by
using its Text property:
myChoice = MyPopupMenu.Text!
1)
2)
3)
Add a Label to Window1 and change its Text property to Main Dish:.
4)
5)
Me.AddRow("Pizza")!
If you want to get creative with the food options, feel free to do so!!
6)
Add another Label to Window1 and change its Text property to Side
Order:.
7)
8)
9)
10)
11)
12)
Add another Label to Window1 and change its Text property to Your
Order:.
13)
Add a TextArea near that Label and change its Name to OrderField.
14)
15)
16)
End If!
17)
NotesField.Text = ""!
18)
OrderField.Text = ""!
If FriesRadio.Value Then!
End If!
If PotatoRadio.Value Then!
End If!
If OnionRingRadio.Value Then!
End If!
If CheeseCheckBox.Value Then!
End If!
If BaconCheckBox.Value Then!
End If!
OrderField.Text = theOrder!
End If!
19)
CompileOrder!
20)
21)
22)
Obviously, this sample project wont place any real orders for actual food.
Its goal is to show you a combination of controls working together in one
interface. For extra practice, try refining the user interface of this project by
using GroupBoxes and SegmentedControls.
7.2 ListBox
One major control that has not yet been covered is the ListBox. The
ListBox is an extremely useful control with many events and properties.
This section will provide an introduction to it.
As with the other controls in this chapter, the ListBox features the usual set
of size and position properties. A quick glance at the Inspector, however,
reveals many more properties. Two important properties of the ListBox are
ColumnCount and HasHeading. ColumnCount is an integer indicating how
many columns the ListBox has. The columns themselves, are in a zerobased list, so a three column ListBox will have column 0, column 1, and
column 2. HasHeading is a boolean that determines whether the ListBox
will display a header row. A header row is visually dierent from the other
rows, and it also maintains its position at the top of the ListBox while the
other rows are scrolled.
The text thats contained in the header cells can be changed by using the
Inspector to the set the InitialValue property. Enter your headings
separated by tabs. If you enter text on a second line, new rows will be
added to the ListBox.
The ListBox also has some events and methods that may look familiar
from other controls. For example, you saw that the PopupMenu and the
ComboBox both have a method called AddRow. The ListBox has that
method as well. As with the other controls with this event, AddRow takes a
string as a parameter. That string will be added to the end of the ListBox,
in the first column.
This may lead you to wonder how you populate the other cells in that row.
Heres an example of the Open event of a three column ListBox:
Me.AddRow("Dylan")!
Me.Cell(Me.LastIndex,1) = "Bob"!
Me.Cell(Me.LastIndex,2) = "Musician"!
That code would add one row with three cells. Add a few more rows, and
it might look something like this:
Dylan
Bob
Musician
Bezos
Jeff
Businessman
Bolt
Usain
Athlete
Me.Cell(1,2) = myString!
You may notice in the code just above that you used a property called
LastIndex. The ListBoxs LastIndex property is the zero-based row number
of the last row that was added to the ListBox. So using LastIndex
Chapter 7: Just Browsing!
immediately after AddRow will always allow you to add data to cells
beyond the first column.
When the user selects a row in the ListBox, its Change event is triggered.
The Change event doesnt provide you with the currently selected row, but
as you saw in previous chapters, you can access this information using the
ListBoxs Index property. Index is zero-based, so the first row has an index
of zero. If no row is currently selected, the Index will be negative one.
The ListBox also has a DoubleClick event. In many applications that use a
ListBox, a single click (which triggers the Change event) selects a row,
while a double click will open a new window for editing or viewing its
contents (such as double clicking on an email message in your inbox or
double clicking a song in iTunes to have it start playing). The DoubleClick
event, like the Change event, does not provide you with the row that the
user clicked on, but you can use the ListBoxs ListIndex here as well.
This has been just a short introduction to the ListBox. You will learn more
about it in future chapters.
7.3 Decor
A glance at the Decor section of the controls list in Xojo will reveal quite a
few controls in this category. In this section, you will learn about the
GroupBox and the Canvas.
As far as code execution goes, the GroupBox doesnt actually do all that
much. In terms of design, its useful for containing other controls, as with
the RadioButton example above. It is capable of holding any other control
as well. Also important in the design of your application is setting the
GroupBoxs Caption property.
The Canvas is one of the most powerful controls oered by Xojo. In this
section, you will only scratch the surface of what it can do. You will learn
about some of its capabilities in Chapter Ten. In fact, in this section, you
will only look at one event in the Canvas: the Paint event.
The Paint event provides you with one parameter: G as Graphics. You will
learn much more about the Graphics class in Chapter Ten, but this will
provide a short introduction.
1)
2)
3)
4)
5)
6)
7)
8)
9)
g.DrawOval(60,60,60,60)!
10)
11)
7.4 Organizers
This section will cover the TabPanel and the PagePanel. These controls,
like the GroupBox, are useful for grouping other controls into logical units.
But they oer the advantage of hiding and showing these groups of
controls as well.
1)
2)
3)
4)
5)
6)
Back in the window editor, with the first tab of the TabPanel
highlighted, add some controls of your choosing.
7)
Switch to the second tab of the TabPanel and add a dierent group of
controls.
8)
9)
Switch back and forth between the tabs and notice how the controls
are swapped out.
10)
If you need to know which tab has been selected, the TabPanel does
provide a Change event. You can find out which tab is selected by
accessing the TabPanels TabIndex property.
There are several ways to design navigation for your PagePanel. The
easiest way is to have a PushButton or BevelButton outside the
PagePanel with code similar to this in its Action event:
MyPagePanel.Value = MyPagePanel.Value + 1!
MyPagePanel.Value = MyPagePanel.Value - 1!
A third way is to direct to the user to a specific page based on his or her
actions. For example, imagine you were building a wizard interface to
walk the user through setting up an account with a social network. You
might have the user choose between creating a new username and
password or using an outside authentication system like Google or
Facebook. If the user chooses to create a new account, you could set the
PagePanel to take them to a page with a sign up form. If they choose to
use outside authentication, the PagePanel can show them a page where
they can enter their credentials for that outside service.
7.5 Indicators
One of the most important aspects of a well designed user interface is
responsiveness. However, sometimes code simply takes a while to run. In
these cases, its best to provide your user with feedback to let him or her
know whats going on. Often, if an application provides no feedback for
more than a few seconds or doesnt seem to be doing anything, the user
will assume that the application has frozen or crashed. If your application
is processing a large data set, it can be very useful to display a
ProgressBar or ProgressWheel. This indicates to the user that the
application is still working.
The ProgressBar should be used when you can quantify the length of time
your application will take or the amount of items that need to be
processed. The ProgressBar has a Maximum property that should be set
Chapter 7: Just Browsing!
1)
2)
3)
4)
5)
ProgressBar1.Value = ProgressBar1.Value + 1!
6)
7)
When used in conjunction with Timers and Threads (both of which will be
covered in a later chapter), the ProgressBar can be invaluable in providing
your user with feedback about your applications current state.
Many times, however, you will not know how many items need to be
processed or how long a given task will take. For example, you may be
waiting for data to arrive from an outside server, and the speed will be
1)
2)
3)
4)
5)
6)
7)
8)
9)
1)
2)
3)
4)
5)
6)
Add a ProgressBar under MainViewer. Set its Maximum to 100 and its
Value to zero.
7)
8)
9)
Using the Inspector, make sure that the ProgressBar and the Label
are locked at the bottom and unlocked at the top.
Here is what your interface might look like in the Window Editor:
10)
MainViewer.LoadURL(AddressField.Text)!
11)
12)
By adding just seven lines of code to this project, you can make it much more
responsive and keep the user better informed.
13)
14)
ProgressWheel1.Visible = True!
15)
16)
Self.Title = NewTitle!
17)
StatusLabel.Text = ""!
18)
19)
20)
Self.Title = NewTitle!
When youre writing code in a control on a window, you can refer to the
window as Self (conversely, you can refer to the control whose code youre
editing as Me). So to change the windows Title property to the name of
the web page, set Self.Title to NewTitle.
reset the ProgressBars Value back to zero. And you set StatusLabels Text
property to an empty string.
Congratulations! Believe it or not, you just built a web browser. Sure, its
missing some fundamentals like bookmarks, error checking, and tabs, but
by implementing a few events in a few controls, you now have a workable,
usable web browser:
Chapter 8: Do It Yourself
Chapter 8: Do It Yourself!
idea. For example, you may have a class that represents a car (a real life
object) or a bank transaction (an abstract idea).
In this chapter, you will learn to create and use your own classes, and you
will also learn about modules, which provide you with a way to provide
global data and methods to the rest of your application.
Chapter 8: Do It Yourself!
Programming, it can help you create code that is more flexible and far
easier to maintain.
8.3 Classes
As mentioned above, a class is something that represents a real life object
(something you can touch or point to) or an abstract idea (a concept or
intangible idea). To illustrate a class that represents a real life object, you
will create a class called Student.
Before you start writing code, stop and think about the attributes of a
student. Some obvious things that come to mind are a first name, a last
name, a middle name, a birthdate, and a grade level. Next, think about the
data types that you will need to store this information. The first, last, and
middle names are all strings. The birthdate is a date. Grade level is an
integer (assume that this is a secondary or intermediate school without a
Kindergarten class).
Property
Data Type
First Name
String
Last Name
String
Chapter 8: Do It Yourself!
Property
Data Type
Middle Name
String
Birthdate
Date
Grade Level
Integer
You could continue to add properties, such as hair color, eye color, height,
weight, and on and on. For now, this list of properties will be sucient.
But property names are subject to the same rules as variable names (no
spaces or punctuation except for the underscore), so a cleaned up list of
properties would look like this:
Property
Data Type
FirstName
String
LastName
String
MiddleName
String
Birthdate
Date
GradeLevel
Integer
Property
Title
Chapter 8: Do It Yourself!
Data Type
String
Property
Data Type
Instructor
String
Room
String
Subject
String
Again, you could continue to add more properties, but this will do for now.
Some of the data types you learned about in previous chapters are
examples of classes that Xojo provides for you. Like those data types,
classes must be instantiated, or created, using the New keyword, like so:
Dim s As Student!
s = New Student!
Talking about classes in the abstract is all well and good, but theyre not
useful to your applications until you add them to your projects.
1)
2)
With the App item selected in the Contents pane, go to the Insert
menu and choose Class.
The class editor will appear. This is where you will enter a name for your class. Call this
class Student. The other fields (Super, Scope, and Interfaces) can be left blank for
now (youll learn more about these topics in Chapter Thirteen).
3)
!
Chapter 8: Do It Yourself!
4)
5)
Go back to the Insert menu and choose Class again. Name this class
Course.
6)
7)
In the Contents pane, select Window1 and choose Property from the
Insert menu.
This new property will allow you to add some Courses to your application so that you
have some data to work with. The propertys name should be MyCourses() and its type
should be Course. This will create an array of Courses that you can use. Notice that
Course autocompletes in the type field.
8)
9)
= "101"!
c.Subject = "Science"!
c.Title = "Biology"!
MyCourses.Append(c)!
c = New Course!
c.Instructor = "Mrs. Jones"!
c.Room
= "202"!
c.Subject = "Mathematics"!
c.Title = "Geometry"!
MyCourses.Append(c)!
c = New Course!
c.Instructor = "Ms. Jackson"!
Chapter 8: Do It Yourself!
c.Room
= "301"!
MyCourses.Append(c)!
This code will create some sample Courses. Typically, this would be done from a
database or other external data source, but for now, you can create them in code.
Feel free to add more Courses to the list if youd like. Note that each time you use the
line c = New Course, the old value is discarded and the variable is created anew. Also
note that the properties you added are available in Xojos dot notation and
autocomplete.
10)
11)
12)
Next!
This method will loop through your array of Courses (using a For...Each loop) and add
each title to the ListBox.!
13)
ListCourses!
Chapter 8: Do It Yourself!
14)
15)
It might be tempting at this point to think that the ListBox now contains
information about your Courses. In a very limited sense, it does, but it only
contains the title of each course. Given the title only, it would be dicult to
look up other information about the course, unless you looped through the
array looking for a match or moved the Course data from an array to a
dictionary. And even then, you would have to make sure that you have no
duplicate course titles.
The reason you dont have all of the information about your Courses in the
ListBox is because you have only used one of their properties. To have
access to all of the Course information, you need to use an object.
If you think of your class as a blueprint, you can think of an object as the
actual house.
Chapter 8: Do It Yourself!
CourseBox.DeleteAllRows!
For Each c as Course in MyCourses!
CourseBox.AddRow(c.Title)!
CourseBox.CellTag(CourseBox.LastIndex,0) = c!
Next!
Chapter 8: Do It Yourself!
8.4 Variants
The obvious question raised by the code change is: what is a CellTag? As
you saw earlier, Every ListBox has a two dimensional array of Cells. It also
has a two dimensional array of CellTags. You can think of a CellTag as a
secret compartment where you can store data.
While you can only store string data in a Cell, a CellTag stores a data type
called a Variant. A Variant is a flexible data type that can store a string, an
integer, a double, a date, a dictionary, or any other data type, even your
custom Course objects. So the code above assigns each Course object to
a CellTag in the ListBox. Because of the way the code is structured, each
Cell in your ListBox will contain a CellTag with related course data, stored
as a Variant.
This raises another question: how do you get data into and out of a
Variant? Assigning data to a Variant is straightforward, and it mirrors the
way its done with other data types.
1)
2)
MsgBox v!
3)
Chapter 8: Do It Yourself!
4)
5)
MsgBox v!
MsgBox third!
What should be displayed in the message box? You could argue that the
message box should display 123456 (if the string values of the Variants
are combined), but you could also make a case for 579 (if the integer
values are combined). Change the code in Window1s Open event to the
code above and try it for yourself. Were you surprised at the result?
This illustrates that while Variants are certainly powerful and useful, they
should be used with great care and only when necessary. Storing an
Chapter 8: Do It Yourself!
That care can be exercised by using the Variants properties to force your
code to treat the data as a certain type.
6)
MsgBox third!
The IntegerValue property of the Variant forces the computer to treat the data as
numeric instead of string. The Variant also has a StringValue property, as well as
BooleanValue, DataValue, and more.
Before you can use an object stored in a Variant, you must tell the computer what type
of object it is. Back to the StudentInformation example, you must tell the computer that
the Variant stored in the CellTag is a Course object. Before doing so, you should make
sure that the object is indeed a Course.
7)
c = Course(Me.CellTag(Me.ListIndex,0))!
MsgBox c.Instructor!
End If!
End If!
Chapter 8: Do It Yourself!
This code may look very confusing at first, but its simple when its broken down. First
you create a variable, C, which youll use to access your Course object. Second, you
verify that the user has selected a valid row in the ListBox by checking the ListIndex.
The next line uses the IsA function to check if the Variant (the CellTag in Column 0 of the
selected Row in the ListBox) is actually a Course object. IsA returns a boolean value:
true if the Variant is really of that data type and false if it is not.
Next, the code does a process called casting, which means its telling the computer for
certain that the CellTag in question should be treated as a Course object, stored in the
variable you called c.
After that line, c is a Course object that you can use as you see fit. In example above,
the Courses Instructor is displayed to the end user in a message box.
8)
9)
Chapter 8: Do It Yourself!
1)
2)
3)
MsgBox info!
This method will simply gather some information about the Course and display it to the
end user in a message box.
4)
MsgBox c.Instructor!
to this:
c.DisplayCourseInfo!
5)
6)
7)
function. The parameters they take can be of any data type, either a data
type built into Xojo or a custom data type, such as the Student class you
created earlier.
8)
9)
10)
!
11)
12)
13)
Me.LastName = LName!
Chapter 8: Do It Yourself!
Now you have a way to create Students and a way to add those Students to a Course.
There are two critical pieces remaining: first, a way to see which Students are enrolled
in a Course, and second, a mechanism for the user to add Students to a Course (the
method exists, but its not accessible to the user).
14)
15)
16)
17)
18)
19)
End If!
Chapter 8: Do It Yourself!
This code will display the Students in a Course. It creates a variable to hold the Course
object, gets the Course object from the CellTag, and then loops through the Courses
Students and lists them in StudentBox.
20)
LastNameField.Text)!
CourseBox.ListIndex,0))!
TheCourse.EnrollStudent(TheStudent)!
newRow = theStudent.LastName + ", "!
newRow = newRow + theStudent.FirstName!
StudentBox.AddRow(newRow)!
End If!
This code enrolls the Student in the Course. It also adds the Students name to
StudentBox. Pay special attention to the fourth line, which takes advantage of the
Constructor to create a new Student based on the first and last names.
21)
22)
23)
24)
Give your Student class a new method called FullName. It will take
no parameters and it will return a string. Its code follows:
Chapter 8: Do It Yourself!
There were several times in the above code where it was necessary to get a Students
LastName, followed by a comma, followed by the Students FirstName. Since that code
was needed more than once, thats a good candidate for a function.
25)
8.6 Modules
Right now, your project has an array of available Courses. This array is
stored in Window1. Theres nothing wrong with this approach, but there
will be times when it limits what you can do. For example, if your
applications interface required more windows, those new windows would
not have access to the list of Courses.
Those are the times when its appropriate to store information in a global
variable. A global variable is a variable that is always available to all
objects, windows, and methods.
1)
Chapter 8: Do It Yourself!
2)
3)
4)
5)
6)
7)
Next!
8)
Add a PushButton to Window1 and add this code to its Action event:
Window2.Show!
9)
10)
11)
Chapter 8: Do It Yourself!
In this chapter, you will build a styled text editor that open, edit, and save
files. Your app will also be able to change the font, size, style, and color of
the text. Your app may look something like this:
If youre wondering what this lorem ipsum nonsense is, its sometimes
called fake Latin. It doesnt mean much of anything, but it provides a
distribution of letters thats nearly identical to written English, so its useful
for gauging how a design will look without including any real text, which
could distract the viewer from the design itself. It is often used in
prototyping interfaces.
Almost every file has a type. A files type indicates what kind of data the
file contains. For example, a text file contains plain text data. A JPEG file
contains picture data. An MP3 file contains audio data. File types are fairly
specific: instead of a picture file type, there are JPEGs, PNGs, GIFs,
BMPs, and others. Each of these may contain a picture, even the same
picture, but your computer needs to open and read each one in a dierent
way. So a file type not only tells the computer what kind of data it will find
in the file, but also how to read it.
You can help your application to look for certain types of files by using a
File Type Set. To add a File Type Set to your project, choose File Type Set
from the Insert Menu. Give your File Type Set a meaningful name, such as
PictureTypes (or anything else that describes the files youre specifying).
Click the small Plus button at the top of the IDE to add a FileType to your
File Type Set. You should specify at least the Display Name (how it will be
presented to the end user), the Object Name (how you will refer to it in
your code), and the Extensions (the file name extension). For example, to
create a FileType for PNG files, you could enter PNG Files for the Display
Name, PNGFile for the Object Name, and png for the extension. For
Adobe Reader files, you might use Adobe Reader, Acrobat, and pdf
as your values.
You will see how to use a File Type Set to filter for certain file types in
section 9.4.
CreationDate (a date indicating the date the file came into existence), its
ModificationDate (a date indicating when the file was last changed),
IsWriteable (a boolean indicating whether you will be able to save changes
to the file), and its Length (an integer indicating the size of the file on disk,
in bytes). Most of these are fairly self explanatory, so you are encouraged
to experiment with these properties later.
The FolderItem also has some properties whose use and meaning may not
be as apparent. One such property is Directory. Directory is a boolean that
tells you whether or not the FolderItem is a folder (also called a directory).
This can be very useful to know: you dont want to try to open a folder
thinking its a picture!
Another property that may seem curious is the Exists property. This is a
property that, appropriately enough, tells you whether or not the
FolderItem exists. This may seem very odd. After all, how would you have
a FolderItem that points to a non-existent file? The short answer is that its
actually quite common. In fact, its the only way to create a new file or
folder that doesnt yet exist. This will become clear later in the chapter.
If the FolderItem that you are working with is a folder and not a file, the
Count property will tell you how many items it contains. This number will
include other folders, but not the items in those subfolders.
Related to the Count, the FolderItem has a function called Item. Item takes
an integer indicating the number of the contained item and returns it to
you as another FolderItem. If its less confusing, you can think of Item as
an array of FolderItems rather than a method.
Also note the Parent property. The Parent is the FolderItem containing your
FolderItem. So if you had a file called MyXojoProject and it was stored in a
folder called My Projects, the Parent property of MyXojoProject would give
you a FolderItem representing the My Projects folder.
But before you dig into dialogs, it might be good to explain what a dialog
is. In the simplest terms, a dialog is a minimal window that either retrieves
information from the user or provides information to the user.
You have almost certainly seen a dialog that retrieves information from the
user. A classic example is the print dialog, which asks you to specify a
printer and possibly choose some additional settings:
A dialog that provides information to the user may look something more
like this:
There are three special versions of the FolderItemDialog class that you will
use: OpenDialog, SaveAsDialog, and SelectFolderDialog. When you want
to prompt the user to open a file, use OpenDialog. When you want the
user to save a file, use SaveAsDialog. Finally, when you want the user to
choose a folder, use SelectFolderDialog.
(There are also ways for you to open and save specific files without the
users help. This will be covered later in this chapter.)
1)
2)
3)
4)
d = New SelectFolderDialog!
myFolder = d.ShowModal!
If myFolder <> Nil Then!
FileBox.AddRow("Name: " + myFolder.Name)!
FileBox.AddRow("Size: " + Str(myFolder.Length) !
!
+ " bytes")!
End If!
The first thing this code does is create two variables: one for the SelectFolderDialog
and one for the FolderItem. Since SelectFolderDialog is a class, it needs to be
instantiated with the New operator.
ShowModal is a function in all of the folder item dialog classes. It displays a modal
window to the user (a modal window is one that blocks the rest of your application until
it is dismissed by the user, whether by selecting an item or canceling the operation; this
is in contrast to a standard dialog, which still allows access to some or all of the
application). The function will return Nil if the user pressed the Cancel button, which is
how you check to see if myFolder is Nil before continuing, or it will return a FolderItem
representing the folder that the user selected.
Once the code verifies that the FolderItem is valid, it adds a few rows to FileBox to
show you some properties of the selected folder. Note the syntax used to show the
FolderItems Parents Name: myFolder.Parent.Name. Because the Parent is itself a
FolderItem, you can access its properties just as you can do with the FolderItem you
initially selected.
5)
6)
Notice the number of items the FolderItem contains. Now verify for yourself how many
items it has. The number listed in FileBox is one higher than the number you see in the
folder. This is because item number zero is the FolderItem itself. This can cause
confusion, so its something to remember and be aware of as you write code that deals
with folders.
7)
To open a file, use the OpenDialog class. You will add that to your Dialogs
project next.
8)
+ myFile.CreationDate.ShortDate)!
FileBox.AddRow("Last modified on: " !
+ myFile.ModificationDate.ShortDate)!
End If!
9)
10)
ShortDate property. You also eliminated the FolderItems Count property this time, since
it is not a folder.
11)
When opening files, you may want to prohibit your user from choosing
inappropriate file types. For example, if you are building an image editor,
you probably dont want the user opening a Word document or an XML
file. This is where File Type Sets come into play, using the Filter property of
the FolderItemDialog.
1)
2)
Create a File Type Set called ImageFiles (choose File Type Set from
the Insert Menu).
3)
Object Name
Extension
PNG Format
PNG
png
JPEG Format
JPG
jpg
GIF Format
GIF
gif
4)
MsgBox f.Name!
End If!
5)
6)
Click the PushButton and browse the computer for files to open.
Your application should allow you to choose only PNG, JPG, and GIF files.
7)
8)
MsgBox f.Name!
End If!
9)
10)
Click the PushButton and you should see a SaveAsDialog that allows
you to specify your new files data type as PNG, JPG, or GIF.
11)
MP3 file will be read much dierently from a plain text file, which in turn
will be read much dierently from a database file (which youll learn about
in Chapter Twelve). Nearly every application you can conceive of will have
to read data, write data, or both.
One common way to read a files data is the BinaryStream. You may be
familiar with streaming music services like Spotify, Rdio, or Pandora.
These services send part of the song to your computer, wait for a while,
then send some more of the song, instead of sending it all at once. The
BinaryStream, and in fact, all file streams, work in a very similar way. Once
a file has been chosen, BinaryStream is used to extract data from that file
in small chunks, each of which is processed as it is read into the
application. When all of the data has been read, it is then presented to the
end user.
1)
2)
3)
TextArea1.Text = b.Read(b.Length)!
End If!
This code allows the user to select a file and then display its contents in the TextArea
using a BinaryStream. The syntax for this is a bit dierent from what you may be used
to.
The first few lines of code should look familiar: creating a few variables, instantiating a
new OpenDialog, and choosing a file. But once the file is chosen, youll see this line:
b = BinaryStream.Open(myFile)!
Once the BinaryStream has been instantiated, it reads the data from myFile and
displays it in the TextArea. The BinaryStreams Read method brings a portion of the
files contents into your application. How large that portion needs to be is up to you.
The Read method takes an integer telling it how many bytes to read. In this case,
youve told it to read everything in one shot by specifying the Length of the
BinaryStream (a BinaryStreams Length is like a FolderItems Length).
4)
5)
6)
This project illustrates something very important about most of the files on
your computer: theyre not human-readable. A human-readable file is one
Chapter 9: In And Out!
that you can make sense of by looking at the raw contents. There are a
few exceptions, such as XML files, HTML files, or other plain text files, but
for the most part, the files on your computer can only be read by an app
that is designed to read that kind of file.
A custom file format is somewhat like a map or key that tells the computer
which data is stored at which place in the file.
Fortunately, Xojo includes some functions that make it easy for you to
open some common file types.
1)
2)
3)
End If!
The Picture class, as you saw with BinaryStream above, has a shared method called
Open, which takes a FolderItem as its parameter. Again, because it is a shared method,
you may use it at any time; you do not need to instantiate the object first.
The code then sets the Backdrop property of the Canvas. The Backdrop is a Picture in
the background of the Canvas. The next chapter will cover graphics, pictures, and the
Canvas in greater depth.
Before setting the Backdrop property, however, you must first check to make sure the
Picture isnt Nil, just as with the FolderItem.
4)
5)
Click the PushButton and select a picture file from your computer.
If it is a valid picture, the Canvas should display it.
6)
Many times, the files you will need to open will only contain text. These are
easy to open and read using the TextInputStream class. The
TextInputStream allows you to read all of the text in a file at one time
(using the ReadAll function), read it line by line (using the ReadLine
function), or read a certain number of characters at a time (using the Read
function). All of these functions return a string. It is up to you to know what
to do with that string, whether display it in a TextField, store it in a
Dictionary, or some other task.
1)
2)
3)
!
Chapter 9: In And Out!
End If!
This example uses the ReadAll function from TextInputStream to read the selected files
entire contents.
4)
5)
6)
7)
TextArea1.Text = t.ReadAll!
to this:
TextArea1.Text = t.ReadLine!
8)
9)
line of a file? It could be used for a number of things. One example would be a quick
preview of a files contents. Or you may want to display each line in a ListBox.
10)
11)
12)
TextArea1.Text = t.ReadLine!
To this:
ListBox1.AddRow(t.ReadLine)!
13)
14)
15)
To read more than one line, you need to use the ReadLine function more
than once. You could simply repeat the line, like so:
ListBox1.AddRow(t.ReadLine)!
ListBox1.AddRow(t.ReadLine)!
ListBox1.AddRow(t.ReadLine)!
Each time you run ReadLine, the app grabs the next line down. But that
approach has two problems. First, its not ecient code at all. Repetitive
tasks like these should be done in a loop. That raises the second problem:
how do you know how many times to do it?
In a nutshell, you keep reading data until you run out of data to read. That
happens when you reach the end of the file, or EOF (which stands for End
Of File). EOF is a boolean: when its false, you still have data left to read;
when its true, no more data remains. So the solution to this problem is to
use a While...Wend loop in conjunction with the TextInputStreams EOF
property.
16)
End If!
Remember from earlier chapters that the Not operator tells your app that you want to
use the opposite of the boolean value that youre referring to. In this case, as long as
EOF is not True, the loop will continue.
17)
18)
19)
Recall that the TextInputStream has functions to read all text, read one line
of text, and read a certain number of characters. The TextOutputStream
has similar methods for writing text, although there are only two of them:
Write and WriteLine.
The WriteLine method takes one parameter, which is a string. It writes that
string to the selected file and thens adds an EndOfLine character (which
could be a line feed, carriage return, or a combination of them, depending
on what kind of computer youre using). If youd prefer to use a dierent
delimiter, you can set the TextOutputStreams Delimiter property.
The Write function also takes one parameter, also a string. It writes that
string to the selected file, but does not add any delimiters or EndOfLine
characters.
1)
2)
3)
End If!
The first few lines of this code should look familiar, although this is the first time youve
seen the SaveAsDialog. The SaveAsDialog is similar to the OpenDialog, but it allows
you to create files rather than open them. So even though MyFile is not Nil, the file it
represents does not yet exist on your computer. The file is written to the disk when the
TextOutputStreams Create function is called. Create is a shared method, as you saw in
previous examples.
After the file is created and you have a TextOutputStream to work with, you can then
add data to the file, using the Write method. In this example, you are adding all of the
text in the TextArea to the file at once.
The Close method of the TextOutputStream tells your app that you are done writing
data to the file, so it is safe to be used by other applications.
4)
5)
Add some text to the TextArea and then click the PushButton.
You will be prompted to save your file. Give it a name and save it.
6)
7)
Styled text is simply text that allows dierent fonts, sizes, and styles, such
as bold, underline, and italic. This project will use a format called RTF, or
Rich Text Format, to store the style information. RTF is a cross-platform,
standard way to store styled text, and the RTF data itself can be stored as
plain text, so you can use TextInputStream and TextOutputStream to open
and save not just your files, but any other RTF file you might have on your
computer.
1)
2)
Here are the controls youll need on Window1 and the names that the
sample code will be using:
Name
Caption
Control
FontMenu
N/A
PopupMenu
FontSizeField
N/A
ComboBox
BoldButton
BevelButton
ItalicButton
BevelButton
UnderlineButton
BevelButton
ColorButton
N/A
Rectangle
OpenButton
Open
PushButton
SaveButton
Save
PushButton
EditingField
N/A
TextArea
3)
4)
5)
EditingField.SelBold = Me.Value!
SelBold is a boolean indicating whether a TextAreas selected text is bold or not. By
setting SelBold to the BevelButtons Value property (which matches its toggle state),
you can make sure that the selected text turns bold when the button is pressed.
6)
EditingField.SelItalic = Me.Value!
7)
EditingField.SelUnderline = Me.Value!
8)
Return True!
For the ColorButton, a Rectangle is being used. This control wasnt covered in the
chapters on controls and events because it doesnt really do much. For example, it has
no Action event. You can, however, use it as a button in a pinch. Set its FillColor
property to black in the Inspector.
The Return True line above is, admittedly, somewhat strange at first glance. To make
sure that the Rectangle responds to a mouse click, you need to implement both its
MouseDown and MouseUp events. MouseUp is where the click should happen,
because thats how buttons work: the action happens when the button is released.
However, a Rectangles MouseUp event doesnt fire unless you have Return True in its
MouseDown event.
9)
End If!
This code will use the SelectColor function to prompt the user to choose a color.
SelectColor returns True if the user picks a color and False if he or she does not. If the
user chooses a color, this code sets the selected texts color to the color that the user
selected. It also sets the FillColor property of the Rectangle itself so that it matches the
text. If the user cancels, and SelectColor returns False, you can safely ignore it.
10)
Next!
The FontMenus code should look familiar, as you worked with similar code in earlier
chapters. This code simply loops through each installed font and adds its name to the
PopupMenu.
11)
End If!
This code sets the selected texts font to the font chosen by the user, after making sure
the user chose a non-empty row.
12)
EditingField.SelTextSize = CDbl(Me.Text)!
This is a simple line of code that grabs the value in the ComboBox, converts to a
numeric value, and sets the TextAreas selected text to that size.
FontSizeField is a ComboBox. This is so that you can provide some preset options for
your user while still allowing him or her to enter a custom font size. This, again, is a
fairly common way for an application to handle a font size menu. To add values to
FontSizeField, click the Pencil icon that appears when you hover over the control with
your mouse. In the dialog that appears, add some values to that you want to see in your
menu. You can use whatever values you like here, but some common font sizes are 10,
11, 12, 14, 18, 24, 36, and 48. And for additional values, your user can always enter a
custom size.
The ComboBox does not have an Action or Change event; when the user makes a
selection or changes the value, the TextChanged event is fired.
13)
14)
15)
The SelChange event is fired whenever the user changes his or her selection, whether
by clicking in a word, using the arrow keys to navigate through the text, or highlighting
some text. The font menu, font size field, style buttons, and color button should all
change to match whatever text is highlighted.!
Most of this code simply works backward from what the various buttons and menus do,
making sure the buttons and menus match what is selected. Note that changing the
text displayed in the FontMenu is more involved than simply setting its Text property.
The Text property cant be set directly, so you need to set up a loop to walk through
each item in the menu and check for a match. When you find one, you set the
PopupMenus ListIndex and then Exit the loop.
16)
17)
Enter some text into the TextArea and play with the styles, fonts,
sizes, and colors.
This time, the menus and buttons should change when you select dierent text. But you
still cant open or save documents.
18)
19)
End If!
This code will prompt the user to select a file and use a TextInputStream to get its
contents. Because the data will be RTF, youll need to read the data into the RTFData
property of the TextAreas StyledText property rather than into the Text property directly.
This sounds more confusing than it is in practice.
Aside from the addition of dealing with RTFData, this code should look very similar to
what youve already learned in this chapter. One nice interface consideration is that this
code also sets the Title of the window to the Name of the file being edited. It also sets
the windows TheFile property to the selected file.
20)
Here in SaveButtons Action event, things arent quite as simple. If the user has already
opened a file, you can save data to the file using the windows TheFile property.
However, if the user has started from scratch, youll need to ask the user where to save
the file and what to call it. Once that part is done, its a matter of writing the RTFData to
the file.
Note that when the file is saved, the windows Title is updated, in case the user created
a new file.
21)
22)
Experiment with opening and saving files and with editing the text
and style data. If you have access to other RTF files, open them as
well.
23)
In this chapter, you have learned the fundamentals of reading and writing
data. But there is still much to learn, especially when it comes to pictures
and databases, both of which youll learn about in the coming chapters.
For now, you should have a solid handle on reading and writing files,
especially text files.
Sometimes this is in the form of pictures that you create outside of Xojo
and import into your project, and sometimes this is in the form of pictures
that you generate with your code. This is another area where the Graphics
class comes into play.
In Chapter 2, you learned about some of the data types that Xojo
supports, including strings, numeric data types, dates, and colors. There
are primarily two data types that you will use when dealing with image
data. One of these data types is Picture. As you probably guessed from its
name, the Picture class represents a picture. That picture can be loaded
from a file that you already have or drawn by your code.
The other data type you will learn about is the Graphics class. It may seem
odd to have both a Graphics class and a Picture class, but the reasons for
this will become clear as you read this chapter. In reality, the Graphics and
Picture classes work together to help you manage image data.
For this chapters example project, youll be making a change to the online
food menu you created in an earlier chapter and giving it the capability to
print the users order.
1)
2)
End If!
Some of this code should certainly look familiar. The code creates a few variables and
then asks the end user to choose a file. One thing that may be unfamiliar, however, is
that one of those variables has the data type of Picture.
3)
4)
Click the PushButton and select a picture file (any common image
format will do, such as JPEG, GIF, PNG, or TIFF).
Notice what happens after you open the file: nothing. Nothing has happened because
you havent told your code to do anything with the picture object yet.
5)
6)
7)
Just above the End If line in the PushButtons Action event, add this
code:
ImageWell1.Image = myPic!
8)
9)
10)
1)
2)
Delete the ImageWell from Window1 and add a Canvas. Again, size it
so that it covers most of the window.
3)
End If!
This is almost identical to the code you entered earlier; only the second to last line has
changed. That new line uses the Graphics property built into the Canvas control. The
Graphics property is an instance of the Graphics class.
The Graphics class has many methods for manipulating image data. In this example,
the DrawPicture method is being used to draw the selected Picture object into the
Canvas (whatever is in the Graphics property of the Canvas will be displayed onscreen).
You will learn much more about the DrawPicture method in this section, but for now,
you should know that the three parameters you have given are the picture to draw
followed by the X and Y coordinates indicating where to draw it.
4)
5)
Note that the image displayed in the Canvas doesnt have the special insert border like
it did in the ImageWell. This is because a Canvas doesnt provide that frame
automatically. Also note that while the ImageWell centered the picture for you, the
Canvas does not. At this point, you may wonder why you would bother with a Canvas
instead of ImageWell. In short, the Canvas gives you far greater control over the display
of your image.
6)
The above example used the DrawPicture method with three parameters:
the Picture to draw, followed by the X and Y coordinates at which to draw
it. The coordinates are relative to the top left corner of the Canvas, so
drawing the image at 0,0 would result in the image being tight against the
upper left corner of the Canvas, while drawing the image at 72,36 would
result in the image being approximately one inch from the left edge of the
Canvas and one half inch from the top. Take a few minutes to experiment
with dierent values for the X and Y coordinates. Notice how the position
of the image changes.
But dont limit yourself by thinking that you can only provide
predetermined numbers as the coordinates. After all, theyre just integers,
so you can give DrawPicture any value that you can calculate. For
example, suppose you wanted to center the image inside the Canvas. If
you knew the size of the image and the size of the Canvas ahead of time,
it would be relatively easy to do the math to center the image. The
challenge comes in when you do not know either size ahead of time.
Fortunately, theres a fairly simple way to center an image. The X
coordinate should be half of the width of the Canvas minus half of the
width of the Picture. The Y coordinate should be the same, only using the
height instead of the width. Conveniently, the Canvas and Picture classes
helpfully provide you with this information with their Height and Width
properties.
7)
8)
Add two new variables at the top of the PushButtons Action event:
Dim x, y As Integer!
9)
Canvas1.Graphics.DrawPicture(myPic,x,y)!
Now comes the tricky part: calculating X and Y. Since you need to know the size of the
image before you can calculate the values, you need to make sure the image is open
first. So under this line:
myPic = Picture.Open(f)!
x = Canvas1.Width/2 - myPic.Width/2!
y = Canvas1.Height/2 - myPic.Height/2!
Those two lines simply calculate the values discussed above. X is half of the width of
the Canvas minus half of the width of the Picture. And Y is half of the height of the
Canvas minus half of the height of the Picture. If that formula is confusing, this diagram
may help:
!
Chapter 10: Picture This (Then Print It Out!)!
10)
11)
Remember that the image is centered within the Canvas, not within the window.
12)
Now that youve learned more about how to position your images using
the DrawPicture method, you may be wondering if its possible to crop or
scale your images. And it is possible.
DrawPicture requires the three parameters youve already seen, but it can
take more than that if you need more control over how the image is
displayed. In fact, DrawPicture can take up to nine parameters.
Canvas1.Graphics.DrawPicture(myPic,20,20,150,150)!
Now add two more parameters, so that your line of code looks like this:
Canvas1.Graphics.DrawPicture(myPic,20,20,150,150,50,50)!
These next two parameters are called SourceX and SourceY, and they tell
DrawPicture where in the original image to start drawing from. By default,
these are both zero, so that DrawPicture starts at the upper left hand
corner of the image.
With SourceX and SourceY in place, you might see an image more like
this:
Canvas1.Graphics.DrawPicture!
(myPic,20,20,150,150,50,50,100,100)!
Note that the image is zoomed in, because its been scaled up.
This is all great if you have some picture handy on your computer already.
But you may have to draw your own at some point. The Graphics class
has several methods that allow you to create images. Rather than go
through some long-winded explanations about these methods, lets dive
into some examples.
1)
2)
3)
g.FillRect(60,20,30,40)!
The G variable here is the Graphics property of Canvas1. The Paint event provides
that property for you:
4)
Note that one rectangle is empty while the other is filled. Thats the dierence between
the DrawRect method, which only draws the outline of a rectangle, and the FillRect
method, which colors in the rectangle. They both take the same four parameters: X, Y,
Width, and Height. So to draw a square, you would make sure that width and height
were the same number.
5)
6)
g.FillOval(60,80,50,60)!
7)
Notice that the ovals are red. This is because you set the ForeColor property of the
Graphics class before drawing the ovals. DrawOval and FillOval, like DrawRect and
FillRect, take four parameters: X, Y, Width, and Height.
8)
9)
g.FillRect(60,200,30,40)!
This time, you have set the ForeColor to green and also made the pen thicker by
setting the PenWidth to 4.
10)
11)
12)
13)
Run your application, and you should see a window that looks like
this:
14)
The Graphics class also has several properties related to drawing strings.
For example you can set its bold property to true before calling DrawString
in order to draw bold text (but dont forget to set it back to false when you
no longer need your text to be bold). The same goes for italic and
underline. In addition, you can set the TextFont and TextSize, and as you
saw earlier, the ForeColor, to control the color of the text.
Now that youve created a masterpiece, you may want to save it. While it
might seem strange, theres no way to save the contents of a Graphics
object. Only a Picture object can be saved to disk. This is easily dealt with,
however, by drawing to a Picture instead of directly to the Canvas.
1)
2)
g.DrawPicture(p,0,0)!
3)
4)
5)
After the line of code that creates the New Picture, add this line:
p.Transparent = 1!
6)
7)
8)
9)
Now that you have your drawing in a Picture object, it can be saved as a file. This
should look somewhat familiar. The code prompts the user to create a new file, then
uses the Pictures Save method to write the picture to a file. Save requires two
parameters: the FolderItem to save the Picture as, and the file format. In this example,
you will save the Picture as a JPEG.
10)
11)
Open masterpiece.jpg in any image editor, and you should see the drawing
you made using the various methods of the Graphics class.
10.4 Printing
Now that you know how to handle Pictures and Graphics, you know most
of what you need to know to print. Printing is done with a Graphics object
as well, but its not part of a Canvas or a Picture. This Graphics object is
returned by the OpenPrinterDialog function. OpenPrinterDialog asks the
user to confirm that he or she intends to print, and then gives you a
Graphics object. Whatever you draw onto that Graphics object is sent to
the printer.
1)
2)
End If!
As you can see, OpenPrinterDialog gives you a Graphics object to work with. You must
check to be sure its not Nil before trying to draw to the Graphics object. If the user
presses the Cancel button in the print dialog, G will be Nil, and no drawing or printing
should be done.
Once youve verified that G is a valid Graphics object, you may use any of the methods
and properties of the Graphics class. The only dierence is whatever you draw will be
printed rather than displayed onscreen.
3)
4)
5)
6)
!
7)
8)
9)
One general rule of printing is this: never assume. You cannot predict what
the user will do, so your code needs to be prepared to handle many
dierent situations, such as dierent page sizes, dierent margins, and
even dierent page orientations. Thats why its best not to use hardcoded positions and sizes for the objects you draw, but to use relative
values and scale your drawing proportionally.
You may be thinking that printing a lot of styled text in this fashion would
be very tedious, and youd be right. Thats why the StyledTextPrinter
exists.
1)
2)
Add a PushButton to the window. Set its Caption to Print and place
this code in its Action event:
Dim g As Graphics!
Dim stp As StyledTextPrinter!
g = OpenPrinterDialog()!
If g <>Nil Then!
stp = EditingField.StyledTextPrinter(g,g.Width)!
stp.DrawBlock(0,0,g.Height)!
End If!
The TextField has a function called StyledTextPrinter that returns an instance of the
StyledTextPrinter class. The function takes two parameters: a Graphics object (which
the OpenPrinterDialog provided) and the desired width of the print area. In this example,
the print area will be the entire width of the page, but you could easily reduce that
number to print in a narrow column, or even in multiple columns.
The StyledTextPrinter class has a method called DrawBlock, which draws its StyledText
into the Graphics object that was specified earlier. DrawBlock takes three parameters:
the X coordinate, the Y coordinate, and the height of the block to be printed. Again, in
this example, the entire page will be used if needed.
3)
4)
5)
Once you have some styled text to work with, click the Print button.
You should see a printout of your styled text.
6)
The Graphics object being used by StyledTextPrinter is just like any other
Graphics object, which means that in addition to your styled text, you may
draw other shapes and object to it as well.
1)
2)
PrintOrder!
3)
g.DrawString(CheeseCheckBox.Caption,100,yOffSet)!
yOffSet = yOffSet + 20!
End If!
If BaconCheckBox.Value Then!
g.Bold = True!
g.DrawString("Extra:",20,yOffSet)!
g.Bold = False!
g.DrawString(BaconCheckBox.Caption,100,yOffSet)!
yOffSet = yOffSet + 20!
End If!
g.Bold = True!
g.DrawString("Notes:",20,yOffSet)!
g.Bold = False!
g.DrawString(NotesField.Text,100,yOffSet,(g.Width-40))!
End If!
End If!
Thats certainly a lot of code - more than youve seen so far in this book. But based on
everything youve learned so far, theres nothing new.
One approach to printing this order would be to draw each element of the order using
DrawString, working your way down the page and increasing the Y coordinate each
time. Thats the basic approach this code takes, but bear in mind that your code needs
to be smart. If a user doesnt choose a side order or an option, you need to ensure that
your application doesnt print a blank line where that part of the order would have been.
Also, since the user can pick zero, one, or two options, you need to make sure that
theres enough room for all of them.
For this reason, this code keeps track of the vertical position on the page by using a
variable called yOSet. If a line needs to be printed, yOSet will be increased, and if a
line needs to be skipped, yOSet will be left alone.
This code is very similar to the code thats in the CompileOrder method. The only
dierence is that instead of adding items to the TextArea, it draws them to the Graphics
object. It also toggles Bold to true for the labels and to False for the actual items.
4)
5)
6)
In this chapter, you learned some valuable skills for dealing with images
and graphics, as well as for printing your users data. You now have
another option to oer to your end users as they use your solutions.
In this chapter, you will learn how to add some networking capabilities to
your own projects. You will also create a sample project called Email
Sender, which will, as you probably guessed by the name, send email
messages. Your project may look something like this:
In fact, its very unlikely that you would even be able to successfully order
lunch!
not to say that you cant read up on a protocol and implement it yourself;
just be warned that its hard, time-consuming work. Fortunately, Xojo
includes built-in support for a number of common protocols.
Now imagine that you were standing outside a friends house, trying to talk
to him or her through a window. For this to be successful, youd both need
to be at the same window. If you were yelling at the living room window
while your friend was upstairs, youd be unable to communicate. But if you
both went to the same window, your conversation would be limited only by
your imagination. Similarly, a port is where the two devices try to
communicate. The port is a number, not an actual physical port on your
computer (such as the USB port or video port). Every computer connected
to a network has thousands of port numbers available. Typically, the first
1,024 ports are reserved for use by the operating system, but many
thousands remain available. Most protocols define the port number on
which they are designed to operate. For example, the HyperText Transfer
Chapter 11: Connections!
Putting all of these together, you may find that your application needs to
talk to google.com (or 72.14.204.102) on port 80 using the HyperText
Transfer Protocol.
The IP version that most devices use today is version 4, but there is
like a lot, but every device on the Internet must have a unique number: every
computer, every smartphone, every tablet, and so on. There are a few
possible unique addresses. Thats two to the one hundred twenty eighth
340,282,366,920,938,000,000,000,000,000,000,000
,000. Thats enough for each person on the planet to have
1)
2)
3)
TCPSocket1.Connect!
The code tells the Socket which address (www.google.com) and which port (80) to
use. It then tells the Socket to connect to that address. Note that you can also set the
Sockets address and port in the Inspector.
4)
This event fires when the Socket has successfully connected to the device at the
specified address using the specified port. Add this code to the event handler.
5)
6)
So far, so good, but admittedly, that project is far from impressive. After all,
the whole point of networking is to send information back and forth
between devices. You can have your application send data and receive
data. To send data with a Socket, you use the Write method.
1)
2)
Me.Write("GET")!
3)
TextArea1.AppendText(s)!
4)
5)
Again, this is still less than impressive, but you now know how to send
data via a Socket using the Write method. What would be even more
impressive, however, would of course be getting some data back. This is
where things get decidedly more dicult. And, perhaps not coincidentally,
Chapter 11: Connections!
this is where protocols come into play as well. As noted above, a protocol
is a set of rules for two devices to communicate over a network, and
without a protocol, such conversations are dicult at best and
impossible at worst.
The TCPSocket you have been working with so far has been operating in
something of a vacuum. Without an established protocol, it doesnt know
how to talk to the other device, or how to respond to it. More importantly,
you dont know how to tell it to do so, unless youve decided to use a
protocol.
1)
2)
3)
4)
5)
6)
MyWebSocket.Get(TextField1.Text)!
This code uses the Get method of HTTPSocket to attempt to load a web page over the
HTTP protocol. The Get method will result in one of two outcomes: either the
HTTPSocket will successfully retrieve the contents of the page, or it will produce an
error.
7)
In the case of an error, the HTTPSockets Error event will fire. The Error event provides
you with the error code, an integer.
Of course, the preferable outcome is the successful retrieval of the page contents. This
happens in the PageReceived event. The PageReceived event provides you with four
variables: URL, a string indicating the address of the page; HTTPStatus, an integer
indicating the status of the transmission; Headers, an instance of the InternetHeaders
class, which gives you additional details about the page; and Content, a string which is
the actual content of the page in question.
8)
TextArea1.Text = Content!
That code will simply fill up TextArea1 with the contents of the page.
9)
10)
For a valid page, notice that youre not seeing a normal, rendered web page. What
youre seeing in the TextArea is the source code of a page, just like you would see if you
chose to View Source in your web browser. If you wanted to see the web page as you
normally would, use the HTMLViewer control that you saw in an earlier chapter.
11)
In this section, you will create the Email Sender project and also learn
about Xojos SMTPSocket. SMTP stands for Simple Mail Transfer Protocol,
and its the protocol most commonly used to send email messages across
the Internet. This section assumes that you have an email account through
Gmail, Yahoo, or iCloud. If you dont, please take a moment to register for
an account through one of those services. You will need your username
and password for this project.
Note that SMTP is only used for sending messages. Receiving messages
is usually done through one of two protocols: POP (Post Oce Protocol)
and IMAP (Internet Message Access Protocol). Because receiving email
messages is decidedly more complicated than sending them, this project
will focus on sending messages. On the surface, it may seem silly to
create an application that can send emails without receiving them, but its
actually quite common. Many applications have built-in support for
sending bug reports to the developer; this is often done by sending an
email behind the scenes. In addition, many applications have a Share
option that often includes emailing a link to your friends.
1)
2)
3)
4)
5)
6)
7)
MailSocket.SendMail!
This method will gather the information from your interface and put it into an
EmailMessage object, which will then be handed over to MailSocket for sending. Most
of the properties of the EmailMessage class are self-explanatory based on their names.
Note that FromAddress property should be set to your own email address.
One interesting method of the EmailMessage class is AddRecipient. This can be used
multiple times on a single message to add multiple people to the to field of an email.!
The SMTPSecureSocket (as well as the SMTPSocket) has an array of EmailMessages
called Messages. You add your own message to the queue by appending an
EmailMessage to that array, as seen in the code above. Once all of the necessary
messages have been added, the SendMail method of the SMTPSecureSocket is called.
The SendMail method sends all of the EmailMessages in the Messages array. With each
message sent, the Socket fires the MessageSent event. This event provides you with a
variable called Email, which is an instance of the EmailMessage class representing the
last message that was sent. When all messages have been sent, the Socket fires the
MailSent event. At this point, the Messages array is empty and the SMTPSecureSocket
is ready to be used again.!
8)
9)
MsgBox ErrorMessage!
Using the MailSent event will help you to keep your end user informed of the apps
status instead of wondering if anything has happened. Another important event is the
ServerError event. In case something goes wrong, your user will want to know that, too.
Now comes the tricky part. As mentioned earlier, this project requires you to have an
email account through Gmail, iCloud, or Yahoo. However, each of these email systems
uses a slightly dierent method of connecting and authenticating, so the code in the
PushButtons Action event will be dierent for each.
10)
If you are using Gmail, proceed to Step 10. For iCloud, go to Step 11.
For Yahoo! Mail, go to Step 12.
11)
SendTheMessage!
Note that your user name should be your full email address, including the @ sign. Skip
to Step 13.
12)
SendTheMessage!
Note that your user name should be your full email address, including the @ sign. Skip
to Step 13.
13)
Yahoo! Mail - Enter this code into the PushButtons Action event:
MailSocket.Address = "smtp.mail.yahoo.com"!
MailSocket.Username = [YOUR YAHOO USER NAME]!
MailSocket.Password = [YOUR YAHOO PASSWORD]!
MailSocket.Port = 465!
MailSocket.Secure = True!
MailSocket.Connect!
SendTheMessage!
Note that your user name should be just the portion of your email address that comes
before the @ sign.
14)
15)
16)
17)
In all the above code listings, your username and password should be
surrounded by quotation marks, since they are strings. Also, please note
that including passwords and usernames in your source code is usually
frowned upon as a bad practice. It doesnt matter much for the purposes
of this project, but an interesting extension to this project would be adding
additional fields to your interface for your username and password so that
theyre not stored as part of your source code.
something like HyperText Transfer Protocol, used to send data for web
browsing, or the protocols used for email messaging: Post Oce Protocol
and Simple Mail Transfer Protocol. These established protocols are usually
accepted by technology industry groups.
This doesnt mean that you cant create your own protocols, however. But
be warned that taking on such a task is, to put it bluntly, a huge
undertaking. Admittedly, even using Xojo Sockets to implement an
existing protocol is quite dicult.
But Xojo does oer you something to make creating your own protocol
quite a bit easier, as long as the only devices using the protocol will be
other computers running applications built with Xojo.
In this chapter, youll learn a bit about database theory, learn some basics
of Structured Query Language, the language used to talk to databases,
and create a sample Address Book application.
12.2 Introduction to
Databases
For now, you need to understand four key concepts about databases:
tables, columns, rows, and queries.
If you remember back to Chapter 8, you may recall that classes can have
properties, and that each property has a certain data type. A database
table is very similar, except that these properties are called columns
instead of properties. Each column in a table represents some attribute of
Chapter 12: Rows And Columns!
Xojo Equivalent
VARCHAR
String
INTEGER
Integer
DATE
Date
DOUBLE
Double
BOOLEAN
Boolean
Hopefully you can see that most data types match up almost exactly. Only
the text data types have dierent names (although some databases
support many more data types, these are all you need to worry about until
you get into very advanced database work).
With these data types in mind, you could have a database table that
looked something like this:
Column Name
Data Type
id
INTEGER
last_name
VARCHAR
first_name
VARCHAR
nickname
VARCHAR
birthdate
DATE
Notice that the sample column names listed above use underscores. Just
like variables in Xojo and all other programming languages, database
column names may not contain spaces. While most databases support
upper and lower case letters in column names, its standard practice in
You may also recall that a class is really a blueprint, and not really the
concept that it represents. In your code, you work with instances of the
class, sometimes called objects, created with the New operator. A
database, again, is very similar. The table is the blueprint, and each
instance of what it represents is called a row. A row in our people table
might look like this:
id
1
last_name
Hewson
first_name
Paul
nickname
Bono
birth_date
1960-05-10
These three concepts tables, columns, and rows are the most critical
parts of databases to understand. And in reality, theyre not complicated.
12.3 Introduction to
Database Queries
But, as mentioned above, there are four concepts you need to know for
now, not just three. The fourth is the query. A query is a way of
communicating with the database. This is done with something called
Structured Query Language, or SQL. Almost every database system in
existence speaks SQL or some variant of it. Many database systems have
slightly customized versions of SQL, but the basics are the same.
SQL is not the only game in town when it comes to databases. There are a
number of SQL alternatives such as Cassandra, MongoDB, CouchDB,
and Memcached. While some of these databases are very fast and are
designed to operate on a massive scale, its not very common to find them
in use in desktop applications, mobile apps, or websites smaller than
Facebook and Google.
Every good language has verbs and SQL is no exception. SQL has four
main verbs that you need to know: SELECT, INSERT, UPDATE, and
DELETE. If youre wondering why the words are capitalized, its because
its common convention to use all capital letters in SQL. Lower case works
fine, too, but as you begin to mix SQL queries in with your Xojo code, the
upper case words are easier to pick out.
These four verbs describe their own functions. SELECT is used to get data
from the database. INSERT is used to add data to the database. UPDATE
is used to modify existing data in the database. And DELETE is used to
remove data from the database. These four verbs work on columns and
rows. There are a few other verbs for working with tables: CREATE is used
to add a table, ALTER is used to modify a table, and DROP is used to
delete a table.
To put several of these pieces together, here is some SQL code to create
our people table:
PRIMARY KEY(id));!
Thats an example of a constraint. NOT NULL means that the column has
to have data in it, even if its just an empty string. In databases, NULL is
The last line, PRIMARY KEY(id), is similar to the NOT NULL UNIQUE
constraint on the id column. PRIMARY KEY tells the database that it
should make sure that id exists, is unique, and can always be
Chapter 12: Rows And Columns!
guaranteed to refer to its row. That is also a constraint, but its a table
constraint rather than a column constraint.
All of these constraints may lead you to wonder why to bother with them.
After all, you could write your code in such a way as to make sure that a
certain value always exists or that it never conflicts with another value. But
the beauty of constraints is that they make the database do that work for
you. With a one time setup, you can now trust that the database will raise
an error when something goes wrong, rather than relying on yourself to
remember every detail later on.
Now that your (admittedly imaginary) people table has been created, you
need to add some data to it. This is done using the INSERT command.
The basic structure of an INSERT looks like this:
VALUES (value1,value2,value3,...valueN)!
Even though this example spilled onto multiple lines, a SQL command can
be all on line as long as you have a space between each element (such as
after the table name).
Column
Value
column1
value1
column2
value2
column3
value3
columnN
valueN
You may specify any number of columns in your INSERT, as long as each
one has a matching value.
You may have noticed that our values in the INSERT were surrounded by
single quotes. In SQL, every string value (or VARCHAR in database terms)
must be surrounded by single quotes. The same rule applies to date
values and booleans. Numeric data does not need single quotes. So the
above example with real data might look like this:
This raises an interesting question: what happens if your text data has a
single quote in it already? If you recall what you learned about string
variables in earlier chapters, you can escape a double quote in Xojo by
using two double quotes in a row. The same goes for single quotes in SQL
(note the two single quotes in the last name):
After running those two INSERT commands, our people table would look
like this:
id
last_name
first_name
nickname
birth_date
Hewson
Paul
Bono
1960-05-10
OHenry
Thomas
NULL
NULL
Note the two NULL values in the second row; thats because those values
were not specified during the INSERT.
Now that you have data in the table, you can use the SELECT command.
The SELECT command lists which columns you want, from the table you
specify:
last_name
first_name
Hewson
Paul
OHenry
Thomas
Note that the database only returns the columns you specify, in the order
you specify. The order of the rows, however, is random, unless you use the
ORDER BY clause:
In this particular example, the data set would look the same, but the order
of the rows would be guaranteed.
You will sometimes see SQL queries that begin with SELECT *, such as
SELECT * FROM PEOPLE. The * tells the database that you want
every single column in the table. This is useful for debugging, but its not
recommended for production code for two reasons. First, you can no
longer be sure of the order of the columns you get back from the database.
Second, you may be retrieving more data (sometimes far more data) from
the database than you need, thereby slowing down your application and
using unnecessary disk or network resources.
You may also search for particular rows using the WHERE clause:
That would return only the first row, because that is the only row in which
the last_name column equals Hewson.
You can also search for a partial match on a string, using the % symbol
(sometimes called a wildcard since it matches any text) and the LIKE
operator:
records that begin with an uppercase B. A search for records that match
%b would find any records that end with a lowercase b. A search for
records that match %b% would find any records that contain a lowercase
b anywhere.
That would return Bonos record, because the LOWER function has
converted everything to lowercase before comparing the strings.
Finally, you can also look for NULL values using the IS operator:
Or conversely:
WHERE id = 2!
WHERE id = 2!
If you eliminate the WHERE clause and issue a command like this:
That would delete Thomas OHenrys record. To clear out all rows:
But a local database just needs a file. Over the next few sections, youll
learn how to create a local database, how to connect to it, and how to
extract data from it. In the process, youll build this chapters sample
project, a simple email address book.
!
Chapter 12: Rows And Columns!
Application Starts
Database Found?
Yes
No
Create Database
Open Database
Continue Running
Application
1)
2)
MyDatabase.SQLExecute(sql)!
MyDatabase.Commit()!
This method will have the job of creating our database table. To do this, you will create
a string containing the SQL commands to create the table (as you saw above) and pass
this string to a method of the database called SQLExecute, which, as its name implies,
executes a SQL command on the database. After running SQLExecute, youll run
another database method called Commit. Commit basically tells the database that
youre sure you want to carry though the command you issued (if youre ever unsure,
theres a method called Rollback that does the opposite).
Creating a schema in code isnt uncommon, but many people prefer to use
a visual tool. Many applications for creating schemas are available,
SQL Server Management Studio. Most of these tools are specific to one
particular database server, but there are also tools that are more
database agnostic, especially in the open source community.
3)
End If!
Else!
Return False!
End If!
End If!
This method will return True if it successfully creates the database, and False if not. This
method works by assigning a FolderItem to the databases DatabaseFile property, then
running a database method called CreateDatabaseFile. It then checks the validity of the
database by trying the Connect function, which returns True if the database is valid and
False if not. If the database is valid, the method then runs the CreateSchema method. If
not, the whole method returns False.
4)
End If!
This method, which returns a Boolean, will attempt to open the database file. If it
succeeds, the app continues as normal. If not, it runs the CreateDatabase method and
returns its boolean result.
5)
End If!
Here is a list of the controls youll need, as well as the names you should
give them:
Control
Name
ListBox
AddressBox
TextField
SearchField
TextField
NameField
TextField
EmailField
PushButton
AddButton
Label
SearchLabel
Also, add a Label for NameField, a Label for EmailField, and a Label for
SearchField.
Youre almost ready for the Populate method. One thing you need first,
however, is a small function called SQLify. If you recall from earlier in the
chapter, SQL uses the single quote as a text delimiter, meaning any time
you have a single in your data, things can go terribly wrong. Thats why
you need to escape every single quote by doubling it. You could do that
manually every time you talk to the database by using Xojos ReplaceAll
function, but youd end up typing a lot of the same code over and over,
which violates one of the laws of programming: Dont Repeat Yourself.
Instead, create a method in Window1 called SQLify. It will take one
parameter, Source as String, and it will return a String. Its code is very
simple, using Xojos ReplaceAll function to find any single quote and
replace it with two single quotes:
Return result!
Note that youre not seeing regular quotation marks embedded in the text:
those are two single quotes side by side. It can be dicult to see in certain
fonts.
Now that SQLify is in place, youre ready for the Populate method. The
Populate method will call upon your existing knowledge of the ListBox
(specifically the DeleteAllRows and AddRow methods) and will introduce
the RecordSet class. A RecordSet is a batch of data returned by a
database query (using the Database classs SQLSelect function). A
RecordSet can contain multiple rows. Each row is dealt with one at a time.
You navigate through the rows using the RecordSets MoveNext method.
Similar to the TextInputStream you saw in an earlier chapter, the
RecordSet uses EOF (End Of File) when the last row is reached. Each row
within the RecordSet can contain multiple columns, which you can retrieve
by name using the RecordSets Field method. In that method, you use the
same column name that is specified in the database schema.
Once the RecordSet is retrieved, the Populate method will create a new
row in the ListBox for each row in the RecordSet, filling in its data as it
goes. But before adding new rows, all existing rows will be deleted. If you
were to skip this step, your ListBox would display duplicate data, and
would continue to add more duplicates each time its populated.
The Populate method will also build a SQL query. If nothing is entered in
SearchField, the query will be straightforward, simply selecting all data
from the addressbook table. However, if the user has entered anything
into SearchField, Populate will take that into account and return only
matching records (SearchField will operate on both the name and email
columns).
With that introduction in mind, here is the code for the Populate method:
End If!
sql = sql + "ORDER BY name"!
rs = MyDatabase.SQLSelect(sql)!
If rs <> Nil Then!
AddressBox.DeleteAllRows!
While Not rs.EOF!
AddressBox.AddRow(rs.Field("name").StringValue)!
AddressBox.Cell(AddressBox.LastIndex,1) !
!
= rs.Field("email").StringValue!
RS.MoveNext!
Wend!
End If!
If you havent done so recently, this is a good time to save your project.
Now that you can retrieve data from the database, you need to add some
data to be retrieved. That will be accomplished using the Action event of
AddButton. The code that you place there will build a SQL statement to
insert whatever data is in NameField and EmailField into the database,
using the Database classs SQLExecute method. If youre wondering
about the dierence between SQLSelect and SQLExecute, its primarily
about what you want back from the database. If youre trying to retrieve
data and need a RecordSet, use SQLSelect. If youre inserting, updating,
or deleting data, SQLExecute is fine, since you dont need a RecordSet in
those cases.
!
Chapter 12: Rows And Columns!
The code will also display any errors that may occur. If no errors are found,
it will commit the database, clear out the data entry fields, and run the
Populate method.
End If!
If you find that youre not a fan of putting all of those SQL queries together,
you can also use Xojos Database API to insert the record without using
SQL. This code is an alternate to the code above (dont run them both!).
MsgBox MyDatabase.ErrorMessage!
Else!
!
MyDatabase.Commit!
End If!
Finally, you need to make sure that the Populate method is run every time
your end user enters text into SearchField. This is easily accomplished by
adding this line of code to SearchFields TextChange event:
Populate!
Run your project and try to add some data to your database. After adding
some rows, try out your search function as well. Quit your application.
In this chapter, youll learn how dierent classes can relate to each other,
and youll create a custom control that you can reuse in other projects.
Property
Data Type
FirstName
String
LastName
String
MiddleName
String
Birthdate
Date
GradeLevel
String
These properties are certainly relevant to a student, but some could easily
apply to other things, even things that may need to be represented in your
Chapter 13: All In The Family!
Property
Data Type
FirstName
String
LastName
String
MiddleName
String
Birthdate
Date
SubjectArea
String
TEACHER
SubjectArea
STUDENT
FirstName
LastName
MiddleName
BirthDate
GradeLevel
As you can see, some of the properties are the same. In fact, in this
example, most of them are.
This is because a student and a teacher are both people, and most people
have some attributes in common with one another. So what this situation
calls for is a new class called Person. The Person class will have the
common properties we saw above:
Property
Data Type
FirstName
String
LastName
String
MiddleName
String
Birthdate
Date
But you still need a way to store information and behaviors for students
and teachers. This is where subclasses come into play. A subclass is a
class that derives properties and behaviors from another class, called a
superclass. This is similar to the parent/child relationship described above.
Create a new Xojo project and save it as Subclasses. You will be building a
small application that lets you add students and teachers to a common
list, while still retaining information about them. Here is a preview of the
interface (although yours may look dierent):
1)
Create a new class by going to the Insert Menu and choosing Class.
Name the class Person.
2)
3)
4)
LastName = LName!
This method takes two parameters: FName as String and LName as String. It allows
you to set both the FirstName and LastName properties with one line of code.
5)
6)
7)
8)
9)
End If!
The job of this method is to determine whether the active Person object is a Student or
a Teacher, and then display the results in a message box. To determine this information,
you will use IsA, a function built into Xojo that will tell you whether one object is also
another kind of object. In this example, youll use it to see if the active Person object is
also a Student or a Teacher.
10)
11)
12)
Name
TextField (w/Label)
FirstNameField
TextField (w/Label)
LastNameField
PopupMenu (w/Label)
TypeMenu
PushButton
AddButton
ListBox
PeopleBox
To populate TypeMenu with a list of options, add this code to its Open
event:
Me.AddRow( "Student" )!
Me.AddRow( "Teacher" )!
Me.ListIndex = 0!
13)
FirstNameField.SetFocus()!
This code will need to create a new Person object (by creating either a Student or
Teacher object) and then add that Persons name to the ListBox. It will also place the
newly created object itself in one of the ListBoxs CellTags. Before you create the
object, youll need to know whether to instantiate a Teacher or a Student, so youll need
to check what TypeMenu says. Finally, in a bit of cleanup, FirstNameField and
LastNameField should be cleared and the focus should be set to FirstNameField.
14)
!
This code enabled PeopleBox to display information about the object that it holds.
Because you stored the Teacher or Student object in a CellTag, you can retrieve that
object and access its properties and methods. Remember that a CellTag is a variant, so
it can contain any object without displaying in the user interface.
15)
16)
17)
For example, consider the Label control. As it stands, its handy for
indicating the purpose of a neighboring control, such as a TextField or
PopupMenu, but it doesnt really do anything interesting, at least by
default. Suppose you wanted your end user to be able to click on a label
to see more information about something, or to visit a URL that you could
specify in your code. It would be a relatively simple exercise to implement
this behavior.
In broad strokes, you would need to add a Label to a Window. You would
need to implement its MouseDown event; remember that returning True in
MouseDown causes MouseUp to fire. MouseUp is where you would use
the ShowURL method to open the URL in question, which you would have
to provide in your code. If you wanted to, you could also implement the
Labels MouseEnter and MouseExit events (which are fired when the
mouse moves over the control and when it leaves the control, respectively)
to change the color of the text in the label and even change the mouse
cursor to the standard pointing finger cursor that most web browsers
use to indicate links (this would be a very good visual indicator for your
users that the item is clickable).
The steps outlined above would work well, but what if you needed the
same functionality from a Label in a dierent Window? You would need to
repeat all of the same steps above, possibly only changing the URL to be
visited.
Thats a lot of duplicate eort, which means a lot of wasted time. This is a
perfect situation for subclassing.
1)
Drag the Label from the Library on the right side of the screen to the
Contents pane on the left side of the screen.
A subclass with the name CustomLabel will automatically be created. Rename it
HyperLabel, since youll be using it for hyperlinks.
2)
3)
Make sure the CheckBox next to URL is checked; that will cause the URL property to
appear in the Inspector. If youd like, you can also turn o any properties you wont
need to see in the Inspector. Press OK when done.
4)
This makes the text blue and underlined, to make HyperLabel appear more like a
hyperlink on a web page.
5)
Return True!
6)
ShowURL( URL )!
You need to implement its MouseDown and MouseUp events to make HyperLabel
respond to clicks, as mentioned above.
7)
MouseCursor = System.Cursors.FingerPointer!
To make HyperLabel behave more like a hyperlink on a web page, change its color
slightly when the user points to it, and change the mouse cursor to the pointing finger
cursor that you typically see in web pages.
8)
MouseCursor = System.Cursors.StandardPointer!
This code resets its appearance when the user stops pointing to it.
9)
10)
In the Inspector, set its text to Xojo and set its URL property to
http://www.xojo.com.
11)
12)
Mouse over the HyperLabel and make sure your cursor changes and
the text color changes. Try clicking the text.
13)
!
Chapter 14: Spit And Polish!
But another important topic, and one that too many developers ignore, is
the user experience. Some people hear this, and they try to think of ways
to add some magical wow factor to their applications that will grab their
users attention and set their applications apart from the crowd.
In reality, the wow factor isnt the important thing. The important thing is
providing your users with a consistent and intuitive experience.
In this chapter, you will learn skills that you can apply to all three of these
areas.
These guidelines can be quite specific, even going so far as to outline how
many pixels a certain type of control should be from the top of a window
or how many pixels should be between PushButtons. You should follow
these guidelines to the best of your ability when it suits the purposes of
your application.
Note the inconsistent spacing, incorrect spelling of OK, and even a nonstandard button being used.
As you can see, while both interfaces can accomplish the same task, one
will be much more pleasant to use (and is also likely to be more consistent
and stable).
Xojo helps you follow the guidelines by helping you position your controls
correctly (notice the blue lines that appear when you drag a control near
the edge of a window, for example).
http://en.wikipedia.org/wiki/Human_interface_guidelines
Although they can certainly make for some dry reading material, its worth
keeping a copy of them somewhere you can access it.
14.3 Creating A
Responsive Interface
Have you ever been using an application and wondered what it was
doing? Maybe you were trying to download a file, print a document, or
process an image. Often, an application will provide you with some
indicator of both its progress and how much time remains. The
applications that dont provide any feedback often give the impression that
they are frozen or hung; as a user, this can be very frustrating, as you must
decide at which point you stop waiting and force the application to quit.
Think back to the controls you learned about in earlier chapters. Two
controls that are excellent for providing feedback to the user are the
ProgressWheel and ProgressBar. If you recall from earlier, the ProgressBar
is best used when you can quantify what your application is doing. In other
words, if you are processing a known number of records or can calculate
how long a process will take, the ProgressBar is a great fit. This is because
it gives the user an indication not just that something is happening, but
how much has happened and how much remains to be done.
1)
2)
MsgBox("Done Processing!")!
This may be your first exposure to the Random class. The Random class, as implied by
its name, is used to generate random numbers. In this example, youre using its
InRange function, which takes two numbers as parameters and returns a number
between those two numbers (in this case, between 1 and 1,000).
3)
4)
5)
6)
7)
Thread1.Run!
This will set the ProgressBars Maximum and current value, set the timer to run every
half second, and tell the Thread to start running.
8)
Next!
This is a slightly modified version of the code that was previously in the PushButtons
Action event. For each number that the app processes, the Windows Progress property
will be increased by one. Because this is being done inside a Thread, the user interface
will remain responsive throughout the operation.
9)
End If!
This code in the Timers Action event will update the ProgressBar twice every second. If
the data processing is complete, the Timer will turns itself o and present the message
box. You may wonder why this isnt done in the thread itself. The answer is that for
technical reasons, code inside a thread should never touch the user interface, since
more than one thread can be running at a time. Imagine if two chefs with dierent
recipes were working on the same cake in the same bowl and youll get an idea of what
could go wrong.
10)
11)
Again, click the PushButton and wait for the message box.
It still takes a few seconds, but this time, the ProgressBar lets you know that something
is happening and that the application isnt stuck, frozen, or crashed.
12)
To see a Timer in action, you are going to create an application that keeps
a clock running in order to keep the user informed of the current time.
1)
2)
ClockLabel.Text = today.LongTime!
This method has no parameters. Its job is to determine the current time (using a Date
object) and display it in ClockLabel.
3)
UpdateClock!
4)
5)
6)
So far, this is a pretty bad user experience. If the user needs to see the
current time, he or she needs to click the PushButton. Its time to improve
this project.
1)
2)
In the Inspector, make sure the Timers Mode is set to Multiple and its
Period is set to 1000.
The Mode can be O, Single, or Multiple. When the Mode is set to O, the Timer is
essentially dormant and wont do anything. When the Mode is set to Single, the Timers
Action event will fire one time, and thats it. When the Mode is set to Multiple, the
Timers Action event will fire repeatedly, depending on the value of the Period property.
The Period is set in milliseconds, or thousandths of a second, so our value of 1000 will
cause the Timers Action event to fire every second.
3)
UpdateClock!
4)
5)
Applications with multiple windows are quite common. For example, any
time you use an application with a tool palette, youre using multiple
windows. Many email clients have multiple windows as well: one for the
list of messages and one for composing a new message. In addition, some
applications will allow you to open two windows with dierent views of the
same data!
As you work with various applications, see if you can figure out how many
windows each one has defined.
Create a new project and save it as MultiWindows. This project will allow
you to use one window to add names to a list, which is displayed in
another window. It may look something like this:
1)
2)
3)
4)
5)
6)
Next!
This methods job is to sort the names in the array and then add each one to the
ListBox, using a For Each loop. Because it will be run multiple times, it will need to
remove all existing rows from the ListBox first:
7)
PopulateNames!
This methods job is to add a new value to the Names array and then run the
PopulateNames method.
8)
PopulateNames!
9)
10)
11)
12)
CancelButton, when pressed, should close its containing Window. This code makes
that happen.
13)
Self.Close!
OKButton has more work to do. It needs to take the text in NameField and add it to
ListWindows Names array, then close its containing window. Since it needs to refer
back to ListWindow, you might assume that you need to create a variable for it, as you
did with DetailWindow above. While that would work, it would also create another
instance of ListWindow when the New keyword is used. Windows in Xojo feature
something called implicit instantiation, which is a fancy way of saying that if a window is
already open, and the application only needs one copy of that window, you can access
it by name at any time.
14)
15)
16)
Dim d As Date!
MsgBox d.ShortDate!
If you run that code, you will see a NilObjectException, because D, the
Date object, hasnt been instantiated. The variable exists, but it points to
an object that doesnt yet. This is, of course, easily fixed:
Dim d As Date!
d = New Date!
MsgBox d.ShortDate!
Dim s As Student!
s = GetStudent( 12345 )!
MsgBox s.BirthDate.ShortDate!
This would probably work well as long as you have a valid ID number.
What could cause an invalid ID number? There are several possibilities.
First, a user could enter an incorrect value when trying to look up a record.
Second, its possible that between the time you start looking for a certain
record and the time that its displayed to you, someone else has deleted
the record from the database. Other possibilities exist as well.
With that in mind, your code should look more like this:
Dim s As Student!
s = GetStudent( 12345 )!
If s <> Nil Then!
MsgBox s.BirthDate.ShortDate!
End If!
That If statement, checking to see if S is Nil, can protect you and your
users from a lot of pain. Even better would be to provide an error message
if S actually is Nil:
Dim s As Student!
s = GetStudent( 12345 )!
If s <> Nil Then!
MsgBox s.BirthDate.ShortDate!
Else!
MsgBox "The student could not be found."!
End If!
Of course, there are some exceptions that you cant do much about. One
example is the OutOfMemoryException, which occurs when the computer
is basically maxed out and cant spare the memory resources required for
the task at hand. In such a case, the best you can do is try to recover
gracefully.
With these exceptions, and all others, a good rule of thumb is to use the
Try/Catch method. This allows you to attempt to run some code, and also
provide alternate code to use as a failsafe. The Student example from
above, for example, would look like this:
Try!
Dim s As Student!
s = GetStudent( 12345 )!
MsgBox s.BirthDate.ShortDate!
Catch err As NilObjectException!
MsgBox "The student could not be found."!
End Try!
Learning to code defensively like this is the best way to protect you and
your users from unexpected errors.
Chapter 14: Spit And Polish!
This chapter will be dierent from the rest. Rather than providing you with
instructions for a sample project, this chapter will pose some questions
that are intended to be discussed by your class.
The best way to define the problem is to ask questions. When you get
answers, keep asking questions. Then repeat the questions. Keep going
until you thoroughly understand what the client or user wants. Then write it
down and develop a flowchart of what the client or user has described and
go over it with them. Before you write a single line of code, make sure you
understand the problem that youre trying to solve.
Just as important as the questions you ask are the people you talk to. Its
always a good idea to talk to whoever is signing the check, so to speak,
but its also critical to get into the trenches and talk with the people who
will be using your application, perhaps on a daily basis.
But be aware that your end users wont always be able to specify what
they want. After all, as Henry Ford pointed out, if he had asked people
what they wanted, they would have asked for a faster horse. Before Apple
Very often, the problem that needs to be solved will not be the one
specified by the client or user. In such cases, you will need to dig deeper.
A classic example tells of a man who said he needed a hammer. Digging
deeper into his story, it turns out that while he did need a hammer, that
wasn't his real problem. He actually needed to drive a nail into a wall. But
that wasn't his real need either. He actually needed the nail in the wall so
he could hang a picture. And he wanted to hang the picture because he
wanted to beautify his surroundings. When asked, the man said he needed
a hammer, but what he really wanted was art and beauty around him. In
the same way, you need to ask questions and dig deeper.
This leads into the developer's second main job: adding value. Your work
and your code should add value to the user's experience. This can take
Chapter 15: The Rulebook!
FOR DISCUSSION:
1)
2)
How would you handle someone who came to you with a detailed
solution already mapped out without specifying the actual problem?
3)
Whenever you have duplicate code, you are inviting problems, and bugs,
into your application. Inevitably, something will change down the road and
you will need to change your code. Will you remember to change it in all of
the relevant places? No matter how smart or diligent you are, history
suggests that you will eventually forget to make an important change, and
your code will end up out of sync.
portion of code is more than two or three lines and you are using that
portion of code in more than two places (this is known as the Rule of
Three), you would be well served by moving that code into a method or
function that you can call as needed.
Also remember that if your code isn't DRY, it's WET. WET stands for Write
Everything Twice.
FOR DISCUSSION:
1)
2)
Or imagine that you logged into Facebook only to find that all of your
photos had been deleted.
Odds are good that you would be pretty upset in either case. Your users
would be upset, too.
It's important to note that this applies only to user data. If your code
generates some temporary files that no longer store important data, those
are always safe to delete. In fact, as in the rest of life, it's a good idea to
clean up after yourself. But data that the user has created or saved must
be kept safe.
As stated above, before you delete user data, you need a very good
reason. The most obvious reason is the user deciding to delete something.
Another reason might be that the data has expired. There may be others
as well. An example of a bad reason to delete user data is a programming
error. If your application deletes data for no good reason, you can rest
assured that very few people will use it!
You also need the user's permission. If the user has initiated the deletion
process, then you are probably clear on this one. If your application
started the process, then you need to make sure, through a dialog box or
other mechanism, that your user is granting you permission to continue.
Finally, you need to provide an opportunity for the user to cancel the
deletion. This usually takes the form of an "Are you sure?" dialog box.
Granted, these can become cumbersome as a user, but that
inconvenience is a good trade o for more secure data.
As a bonus, you might provide a method for the user to undo deleting the
data. This is not required, although it is very common. If the deletion
cannot be undone, it's a good idea to warn your user of that fact when
confirming the deletion.
FOR DISCUSSION:
1)
2)
Now, this is not to say that your application should never surprise your
users. In fact, sometimes surprises are excellent. But, a surprise should
always leave the user delighted rather than astonished. Always, always
strive to delight your users; there are few better ways to keep people using
your software. But conversely, try never to surprise your user in a negative
way.
This ties into a related rule known as KISS, which stands for, if you'll
pardon the expression, Keep It Simple, Stupid!
Many developers fall into the trap of making too many aspects of their
applications configurable, which often leads to a mess of a user interface.
Bear in mind, however, that simple for the user does not necessarily
translate into simple for the developer. In fact, quite often, the simpler the
interface is, the more complex the code behind it is.
FOR DISCUSSION:
1)
2)
3)
What are some ways that your application could delight rather than
astonish your users?
That may sound harsh, but the reality is that you need to predict
everything that could possibly go wrong and defend your user against it.
This usually also involves defending your user against himself or herself,
because many times, the user is his or her own worst enemy.
Design your application so that it minimizes the damage a user can do.
Some of it goes back to the "User Data Is Sacred" section a few pages
back. But you should be even more proactive than that.
For example, if your application has a TextField in which the user is only
supposed to enter numbers, don't let them enter any letters (to see how,
check out the Asc function and the KeyDown event).
If the user is supposed to enter a date, don't just hope that they enter it in
the correct format. Some will use dashes and some will use hyphens.
Some will use the US format and some will use the UK format. Some will
use the business standard and some will use the academic standard.
Some will just go ahead and spell out the month. If possible, use a third
party datepicker or provide some popupmenus to guide the user in
entering the date.
The key point is this: if you allow your user to enter invalid data, whatever
happens after that is your fault. Allowing the user to do something sends
the message that it's okay to do it, so allowing them to enter arbitrary text
into a numeric field or a date field without warning them tells them that
you're going to parse the data correctly. If you need the data in a certain
way, make it easy for the user to enter it that way and extremely dicult (if
not impossible) to enter it the wrong way.
You will be amazed at the things that users try to do with your
applications. Some of these things will be great ideas that you can
implement, but many of them will be things that quite honestly make you
scratch your head and wonder.
In the last chapter, you learned about catching errors and exceptions. This
is where errors and exceptions really come into play in the real world. It
may sound cynical, but you really do need to prepare for your users to do
destructive, seemingly random things. And if your code allows it, then it's
your fault.
FOR DISCUSSION:
1)
Aside from numeric and date inputs, what other formats might need
special consideration?
2)
In what ways can you make sure that your application is solving the
right problems in the right ways?
Your code will likely need to be updated as well. Your application might not
be used for decades like some of these examples, but the chances that it
will be perfect and complete at version 1.0 are very close to zero.
Because of this, you need to plan for the future. The best way to do this is
to write your code to be read. This means that you should use logical and
consistent method, function, and variable names. You should also stick to
the DRY principle. And you should comment your code extensively.
Someday down the line, someone will need to update your code, and that
person will need to be able to figure out how the code works. And there's
an excellent chance that person will be you. Remember that whats fresh
in your head now will likely be very stale a year from now.
So do your future self a favor, and write readable code now. And if it's not
you who has to maintain it, then you will be making some other developer
very happy.
someday it might be more, and your application should be ready for that
with minimal or no code changes.
FOR DISCUSSION:
1)
2)
When it comes to optimization, take a lesson from Donald Knuth. You have
probably never heard of Donald Knuth, but you owe him some thanks
simply because you're using a computer. Born in 1938, Knuth is a pioneer
in computer science and computer programming. One of his best known
quotes about software development relates directly to optimization: "We
should forget about small eciencies, say about 97% of the time:
premature optimization is the root of all evil."
Perhaps Knuth was overstating things a bit for the sake of making his
point, but it's a point worth making: don't get so caught up in making your
application faster that you never get around to shipping it.
This is related to another trap called feature creep, which occurs when a
developer repeatedly tries to add "one more feature" to an application
before shipping it. This happens quite often, and it is easy to fall into. But it
can be avoided by drawing up two very important documents: the spec
and the roadmap.
The spec, or specification, details exactly which features are required for
shipping the application. The roadmap, on the other hand, lays out when,
and sometimes how, new features will be added. For instance, the spec
for your new email client should include items such as sending email,
receiving email, contact management, and even spell check. These are the
necessities. The roadmap is where you might find features like Facebook
integration, a real time Twitter stream, and interactive Google Maps. Cool
features, to be sure, but not necessary for the first version of your
application.
FOR DISCUSSION:
1)
What other items might you find in the spec for a basic email client?
And in the roadmap?
2)
This may sound like a contradiction, but at the same time, you should also
strive to develop applications that are so simple to use that very few users
need the documentation.
FOR DISCUSSION:
1)
What are some simple and practical ways you could include
documentation with a Xojo application?
2)
When was the last time you used an apps documentation and why?
Afterword
Thanks for taking the time to read Introduction to Programming with Xojo.
Whether you went through this book alone or as part of a class, I hope that
it has provided you with some of the fundamentals of computer
programming. You may not be destined for a career as a dedicated app
developer, but its highly likely that some programming skills will come in
handy in our increasingly technological world.
Afterword!
He is also a former columnist for XDev Magazine and has presented at the
Xojo Developer Conference on many dierent topics.
Brad has spent most of his professional career working in the public
school system.
When hes not writing code or writing about code, youll find Brad playing
his guitar, hanging out with his family, or running.
He lives in rural Pennsylvania with his wife and their two children, as well
as a dog and two maladjusted cats.
This work is licensed under a Creative Commons AttributionNonCommercial-ShareAlike 3.0 Unported License. This means that you
are free to share the material in this book provided you are not doing so for
profit and you retain the attribution to Xojo, Inc.
If you wish to print copies of this book, you are hereby granted permission
to do so, provided all of the content remains intact, including this link to
the freely available PDF: http://www.xojo.com/textbook