REALbasic University Resources:

RBU: Glossary Defines common REALbasic programming terms
  Archives Previously published columns
Translations: Dutch Courtesy of Floris van Sandwijk
  Japanese Courtesy of Kazuo Ishizuka
  Chinese Courtesy of Dong Li
  RBU Translation Guide Information on Translating RBU into other languages
Books: Matt's Book (2nd Edition!) Ideal for experienced programmers
  Erick's Book Best for beginning programmers
Websites: Mother Ship The publisher of REALbasic
  RB Webring Links to hundreds of REALbasic websites
  RESExcellence Another REALbasic programming column
  REALbasic Developer Magazine The premiere source for REALbasic instruction.

REALbasic University is Sponsored by

Make your Mac do what YOU want it to. Create games, utilities, cool Mac OS X tricks. Download REALbasic now and create your own software.


Print This Article

REALbasic University: Column 060

Monotab: Part I

My favorite thing about REALbasic is the way it incorporates into my thinking. Whenever I have a problem to solve, even a trivial one, I turn to REALbasic. It's like a best friend that's always around to help.

But I must be alert to opportunties for REALbasic to help me. Any time I do anything repetative I ask myself, "Can I write a program that will make this task easier?"

One task that has cropped up from time to time is that I'll have some tabular data in a tab-deliminated format and I need to convert it to a format suitable for emailing. (This often happens when I copy data from a table on a web page.) Since most email programs are text-only, a tab-deliminated table will appear something like this (data courtesy Major League Soccer):

Team	GP	W	L	T	Pts	GF	GA
San Jose Earthquakes	17	10	5	2	32	27	16
Dallas Burn	16	7	3	6	27	24	19
Colorado Rapids	17	8	8	1	25	24	28
New York/New Jersey MetroStars	16	7	7	2	23	24	21
Los Angeles Galaxy	16	7	7	2	23	20	22
Kansas City Wizards	16	5	5	6	21	21	22
Chicago Fire	15	6	7	2	20	24	22
D.C. United	15	6	8	1	19	18	22
New England Revolution	16	6	9	1	19	27	31
Columbus Crew	16	5	8	3	18	21	27

Eek! That looks awful and is nearly impossible to read. (You can't even tell my Quakes are leading the league! ;-) But if we convert those tabs to spaces and displayed the table in a monospaced font, we have a text-only table that's easy to read.

Unfortunately, that's a tediously mind-numbing task do by hand, and most of us wouldn't bother. Fortunately, I'm the kind of person that's picky about how emails are formatted, and I have REALbasic to assist me.

Planning Monotab

For today's project, we're going to create a program that will convert a tab-deliminated file into a text file where each piece of text is separated by the appropriate number of spaces. That last condition is what makes a simple procedure complicated, as the number of spaces are potentially different for each bit of text.

Before we begin programming, let's do a little thinking about exactly how Monotab will work.

First, we need a way to input a text file into our program: I suggest a simple drag-and-drop interface rather than mess with an awkward "Open Document" dialog.

Second, let's think about how we'll actually handle the conversion. What algorithm will we use?

We obviously cannot simply replace tab characters will a set number of spaces since the number of spaces change depending on the length of the text. For example, in the sample text displayed earlier, we have a list of Major League Soccer teams and their current standings in the league. But since the team names are of different lengths, the number of spaces after the team name changes if we want the next column to start at the same place.

Here's what that table looks like when we replace each tab with three spaces:

Team   GP   W   L   T   Pts   GF   GA
San Jose Earthquakes   17   10   5   2   32   27   16
Dallas Burn   16   7   3   6   27   24   19
Colorado Rapids   17   8   8   1   25   24   28
New York/New Jersey MetroStars   16   7   7   2   23   24   21
Los Angeles Galaxy   16   7   7   2   23   20   22
Kansas City Wizards   16   5   5   6   21   21   22
Chicago Fire   15   6   7   2   20   24   22
D.C. United   15   6   8   1   19   18   22
New England Revolution   16   6   9   1   19   27   31
Columbus Crew   16   5   8   3   18   21   27

Yuck! So in order to display our table correctly, we must do some calulations and figure out the appropriate number of spaces for each field.

There are two calculations that must be done. First, we must figure out where each column must start. That's more difficult than it sounds as we'll see in a minute. Second, we must calculate the number of spaces for each line of each field. Let's look at the first few lines in the example to see how this works.

Team                 GP   W   L   T   Pts   GF   GA
San Jose Earthquakes   17   10   5   2   32   27   16
Dallas Burn   16   7   3   6   27   24   19
Colorado Rapids   17   8   8   1   25   24   28
New York/New Jersey MetroStars   16   7   7   2   23   24   21

To align "GP" so it's further right than the end of "San Jose Earthquakes" we must put at least 17 spaces after "Team." However, it's easy to see that since "New York/New Jersey MetroStars" is even longer than "San Jose Earthquakes" even 17 spaces aren't enough!

That should tell us that in order to calculate the minimum number of spaces between fields, we must first discover the widest data within the current field (in this case, the "New York/New Jersey MetroStars" phrase).

However, you'll see that even when we do that, it isn't always enough. Sure, the first two columns are aligned, but for the wide column, there isn't much breathing room between the first two columns:

Team                           GP   W   L   T   Pts   GF   GA
San Jose Earthquakes           17   10   5   2   32   27   16
Dallas Burn                    16   7   3   6   27   24   19
Colorado Rapids                17   8   8   1   25   24   28
New York/New Jersey MetroStars 16   7   7   2   23   24   21

Wouldn't it be nice to have a minimum amount (like three spaces) between each field? Even better, why not allow the user to dynamically specify this amount?

That leads us to our third question: what kind of interface does Monotab need?

Obviously, this is a program for internal use: it isn't going to be sold or distributed, so it doesn't need much beyond the bare essentials. It could even not have any interface at all and be run as a command-line program (i.e. drop a file onto the Monotab's icon and it converts it and quits)! However, since this is REALbasic and even bare bones interfaces are simple, we'll give our program an interface.

My first thought for an interface is that since this is a program working with tabular data, it makes sense to organize the data inside a listbox, with one row of data for each line in the text, and a column for each field. That way the user can check the data to make sure it was parsed correctly before converting it. To set our "minimum spaces" amount, we'll use a slider control.

Before we create Monotab, we need a test file we can use to make sure our program is working correctly. Prior to the competition, I used Monotab to generate a text-only World Cup soccer TV schedule which I emailed to friends and family. Here's the original tab-deliminated file you can use for testing Monotab (you should Option-click on the link to download the file, otherwise your web browser will display the file).

Setting up the Interface

Create a new blank project file in REALbasic (launch RB and choose "New" from the File menu). Double-click on the Window1 window created by default and attempt to make it look something like this:

That's a listbox at the top. Its properties don't matter too much, since we'll change most dynamically as the program runs, but it would be a good idea to set all the "lock" properties (lockLeft, lockRight, etc.) so that the listbox's size will change if the user enlarges the window.

The slider control is named padSlider and has maximum set to 25 and value set to 3. The pushButton is called exportButton. Other than those properties, the defaults should work for everything else.

StaticText1 is a textual indicator of padSlider's current value: so we just need to put the following code in its Open and ValueChanged events:

 staticText1.text = str(me.value) + " spaces" 

If you've set padSlider to update dynamically (liveScroll is true), the staticText will be redrawn as the user slides the control.

Next, we need to add the ability to accept a dropped file. As usual, this is a two-step process. First, we must tell REALbasic about the kind of file we'll accept. In this case, that's a text file. So go to the Edit menu and choose "File Types." There you'll add a new type (click the "Add..." button) and give it settings like this:

Second, we've got to tell listBox1 to accept files of this type. Within the Open event of listBox1 put this code:

 me.acceptFileDrop("text") 

Perfect! Now any text files dropped on listBox1 will be sent to the DropObject event. Next week we'll handle parsing those files and write the code that does the actual conversion.

If you would like the complete REALbasic project file for this week's tutorial (including resources), you may download it here.

SimpleEtch

I previously promised a special version of our SimplePaint project, so I'll briefly present that here.

The idea is to modify SimplePaint into SimpleEtch, a virtual Etch-a-Sketch drawing program. If you remember using an Etch-a-Sketch as a child, you'll remember that once you put the "pen tip" down, you cannot lift it up and move the cursor without drawing. Thus all Etch-a-Sketch drawings are made of a single continuous line. That makes it awkward (or shall we say challenging), but that's also what makes it unique and interesting.

Here's a drawing I made with SimpleEtch:

To change SimplePaint into SimpleEtch isn't especially difficult and I won't explain it in detail here. The basic differences are:

  • Since an Etch-a-Sketch has no color, we eliminate SimplePaint's color palette and other interface items.
  • When the program is initially ran, or after deleting an existing drawing ("shaking" the Etch-a-Sketch), we allow the user to use the mouse to position the cursor at the starting position. After that, the mouse is no longer used.
  • Once the mouse has been clicked to set the starting position, the user moves the cursor (and draws a point) with the arrow keys.
  • Because the cursor can be moved over previous drawing, making the black cursor impossible to see on a black drawing, we make the current drawing point red. (See the red cursor point at the bottom right of the above drawing.)
  • I also removed the feature allowing the user to change the drawing point size, hard-coding it instead.

The complete REALbasic project file for SimpleEtch is available here: download it and study the changes I made to see how the variation works.

Next Week

We finish Monotab.

Letters

This week we've got a question from Spain! Manuel writes:

Dear Marc:

What would be the REALBasic equivalence of the following CodeWarrior's Pascal instruction:

 getValue := ord(firstValue >= secondValue) 

where getValue, firstValue and secondValue are of extended Pascal Types

Yours sincerely,

Manuel Urrutia Avisrror
Professor of Urology
University of Salamanca
SPAIN

Interesting question. I'm not sure of the answer, since I'm not sure what you are trying to do here. Pascal used to be my favorite language (I never learned C), but it's been a while since I've used it. Unless I'm completely missing something, the statement above is an odd one.

The ord() function returns the ASCII value of the character passed. For instance, pass it a "C" and it returns a 67. But in your code you're passing it a boolean value: the "firstValue >= secondValue" phrase is true if firstValue is greater or equal to secondValue, otherwise it is false. That means getValue will be assigned the result of either ord(true) or ord(false), and it's been too long for me to remember what Pascal would do with that. (I suspect it would be either one or zero, since that's what true and false usually evaluate to, but I'm not 100% certain.)

At any rate, the REALbasic version of this is similar. Something like this is a literal translation:

  
dim getValue, firstValue, secondValue as integer

getValue = asc(firstValue >= secondValue)

However, if you try this, you'll get a "Type Mismatch" error. That's because REALbasic's asc() function is expecting a string and you're passing it a boolean. asc(true) and asc(false) don't work.

The way around this, if this is what you are wanting, would be to frame the code within an if-then statement like this:

  
dim getValue, firstValue, secondValue as integer

if (firstValue >= secondValue) then
getValue = 1
else
getValue = 0
end if

This is a little more convoluted, of course, but it's doable. If this is a function you expect to use often, I'd suggest you make it into a method. Let's call it ascBool and set it up like this:

  
function ascBool(bool as boolean) as integer
if bool then
return 1
else
return 0
end if
end function

If you create the above method, then this code works:

 getValue = ascBool(firstValue >= secondValue) 


About the Column
REALbasic University is a weekly instructional column on programming with REALbasic and is brought to you by REALbasic Developer, the magazine for REALbasic programmers.

Each week we answer select reader questions, and we're always open to ideas for future columns. Send your questions to . (Keep your questions simple and specific. General queries like "How do I write my own web browser?" will be neglected.) Your question won't be answered immediately, but will be answered in a future column. (If you don't want your correspondence published, just be sure to indicate that when you write. Otherwise it's fair game.)

About the Author
is an author, philosopher, graphic designer, photographer, film director, soccer fanatic, and programmer (among other things). He writes for MacOpinion, runs his own software company, Stone Table Software, which sells the revolutionary Z-Write word processor, and is Publisher and Editor of REALbasic Developer. He lives in Northern California with his cats, Mischief and Mayhem, and is rapidly running out of free time.

See the REALbasic University Archives


REALbasic University contents ©2001-2004 by Marc Zeedar and REALbasic Developer. All Rights Reserved.

Email This Article - Comment On This Article

.

Reader Specials

Server Racks Online:
Apple Xserve CompatibleServer Racks and Universal Network Racks
42U KVM Switch Solutions:
High-End Mac and Multi-Platform KVM Matrix switching solutions!
Digital Camera Online:
Great prices on Digital Cameras and accessories!
KVM Switches Online:
Great prices on Mac KVM Switches from the leading manufacturers!
LCD Monitors Online:
Great prices on LCD Monitors from the leading manufacturers!
LCD Projectors Online:
Shop online for LCD Projectors from the leading manufacturers!
USB 2.0 Online:
Great prices on USB 2.0 products from the leading manufacturers

Serious Business Software:
Accounting, Sales, Inventory, CRM, Shipping, Payroll & more!

KVM Switch solutions for MACs:
DAXTEN is a KVM switch, KVM extender and monitor splitter specialist for PC, SUN and MAC applications from name brand manufacturers - offices worldwide.

The "Think Different Store: The iPod Accessories Store - iPod cases, iPod mini, iPod photo, speakers, itrip, inMotion, Soundstage and all other iPod accessories

Earn Cash with the ThinkDifferent Store Affiliates Program

Need A Web Site?
Applelinks Web Hosting Starting at 19.95 a Month

iTunes_RGB_9mm

.

iTunes_RGB_9mm

Cool Mac Gear


iPod 1G-2G
iPod 3G
iPod 4G
iPod Mini
PowerBook-iBook
Keyboard Skins
Garageband