| |||||||||||||||||||||||||||
|
| |||||||||||||||||||||||||||
Print This Article REALbasic University: Column 061
Monotab: Part IIIn our previous lesson, we got Monotab's interface set up, but hadn't started writing the conversion code. We'll finish the program today.
Importing a FileOur first task is to bring in a text file so we can convert it. We already set up listBox1 to accept a dropped file: now we just have to do something with it. Go to listBox1's DropObject event and add this code:
This simply checks to see if a folderItem is available, and if so, sends it to a routine called addText. Let's add that method now. Create a new method (Edit menu, "New Method") and name it addText. First we'll make sure it's a valid file and try to open it as a text file. If either of those operations fail, we'll exit the routine without doing anything. If the file is successfully opened as a text file, we'll extract the text and add it to listBox1. Here's the code:
Note that we first delete all the rows in listBox1. That's in case the user has already dropped one file on to fill up the listbox: this cleans it up. Next, we read in just the first line of the text file. From that first line we set up how many fields the file will contain. It's therefore important that the first line of your text file include the same number of fields as all other lines. In fact, we assume that this first line contains the names of each column type (the headers). Obviously, for a commercial or professional program we might not want to assume this, but for a program we're writing for our own use, this is a valid assumption. To count the fields in the first line, we use the countFields command and tell it the fields are separated by tabs. We then set the headings for listBox1 by extracting them from the first line. Once the headings have been established, all that's left is to read in the data. We start a while-wend loop which lasts as long as the file has stuff left to read. For each pass through the loop, we read in a single line of text. Then we parse that line with the nthField command (which extracts the text of individual fields by number), and carefully add each field's text to a cell in listBox1. (Remember, since listBox1 has several columns, we can't just use the addRow command: that only adds to the first column in the row. The data for the other columns must be added cell by cell.) When we've finished all that, we close the file and the method is done. The file has been imported and is now in our program's memory.
Converting the TextIn order to convert the text, we'll need a couple special routines. The first is simple: a function that will return a string of n spaces (where n is an integer). Create a new method (Edit menu, "New Method") and call it padSpaces. Give it n as integer as its parameter, and a return type of string like this: ![]() Here's the code for the method:
As you can see, this is a pretty simple function. It just adds n spaces to s, effectively returning a string of n spaces. The second routine we'll need to handle the conversion is a little more complicated. Last week we explored the conversion task and discovered that for us to know how wide (in characters) a column must be, we must know the width of the largest item within that column of data. The example I used was the list of MLS teams, where the top team was the "San Jose Earthquakes," which, while long, isn't as long as the "New York/New Jersey Metrostars." To figure out this calculation, we need to examine the length of each item within a field. Since we need to save this information, we need a place to store it. Since we'll need a value saved for each column, it makes sense to store this value inside an array with an element for each column. Let's add a property to window1. Go to the Edit menu and choose "New Property." Add an array like this: colMax(0) as integer. Now create a new method (Edit menu, "New Method") and call it CalcMax. This routine will go through and figure out the largest (widest) string for each column and store that within the colMax array. The first thing the routine does is initialize colMax to the number of fields within the current data file. Then it starts up two nested loops: the outer one (col) steps through each column, while the inner one (row) steps through each line (record) of the text and sets n to the width of that field. Then it checks n to see if it's bigger than whatever value has been stored in colMax(col). If it is, then we store n inside colMax(col), replacing what used to be there. Here's the code:
Note that after this routine runs, colMax contains the maximum lengths of each field. That all the routine does: build the colMax array. Now let's create a new method called exportText. This is where the actual conversion takes place. We basically need to do two things: create a new file where we saved the converted text, and convert the tabs to spaces. The first part isn't difficult. We ask the user to name and save the new file, and then we try to create it (with the .createTextFile function). If that all works, we're set to convert the text. Here's the code:
Before we begin the conversion, we first call calcMax to set the colMax array. Next, we examine the headers of listBox1 and build the first row of s, which will become our exported file. Note that the amount we send padSpaces (the number of spaces between fields) uses the following calculation formula:
After adding our headers to s we add a carriage return (chr(13)), then we start some for-next loops. The outer loop is row, in which row counts through each row of listBox1. The inner loop is col, which steps through each column of data. As we encounter each field, we add the appropriate number of spaces to pad out the column. After each row, we add a return character to s to finish off the line. When we've finished the loops, we write s to the file to save it, and close it. We display a "Done" message so the user knows the file has been saved, and we're all finished. Before our program will work, however, there's one more thing to do: we must call exportText from our exportButton. Add this line to exportButton's Action event.
There! We're all finished. How does it work? Let's test it using the sample file I gave out last week (Option-click to save it). Here's the result:
Looks pretty good, eh? Note that we don't take into account the overall length of each line, so this could create lines too long for email (most email programs wrap text longer than 65 or 70 characters). An improved Monotab would wrap text cells to keep the overall line length within a user-specified maximum. Perhaps we'll do that in a future RBU -- at present I explored creating that version, but it's surprisingly complicated and I never finished it. If you would like the complete REALbasic project file for this week's tutorial (including resources), you may download it here.
Bonus Program: Convert TimesJust to show you how I'm a pathalogical user of REALbasic, I'm going to let you look a the source for another program I wrote along the lines of Monotab, called Convert Times. Convert Times was written specifically to look at the World Cup TV schedule above and convert the times from Eastern to Pacific (I live in California). Obviously that's useless for other purposes, but it is interesting to look at the code, and the program presented some interesting challenges. For instance, converting from Eastern to Pacific is the "simple" matter of subtracting three hours: but what happens when a show starts at 2:30 a.m. ET? If you'd like the project file for Convert Times, you can download it here.
Next WeekWe'll have a mini-review of the latest version of REALbasic, 4.5, released last week at the Macworld Expo in New York.
NewsREALbasic Developer Magazine Launched!Speaking of Macworld Expo New York, yours truly was there in person to hand out flyers and printed copies of the premiere issue of REALbasic Developer. The results were outstanding: everyone was excited to see the first printed copies, and the balance of articles seemed to appeal to potential readers. For people who've already subscribed to REALbasic Developer, your copies are being mailed right now. (International orders will take a little bit longer, due to red tape with the U.S. postal service.) Those who've ordered digital (PDF) subscriptions will receive an email shortly with instructions on how to download your copy. If you'd still like to subscribe, it's not too late: we'll be doing a second mailing of the premiere issue at the end of August (keep in mind this is the August/September issue) to catch any late subscribers.
LettersThis week we hear from Joe, who writes:
Pictures are one of those "obvious" things that are only obvious to the engineers who created REALbasic. In truth they're not difficult to work with, especially if you've used graphics in other languages, but the documentation certainly leaves out a few steps for the non-programmer. There are basically three types of pictures you can work with from within REALbasic:
Let's look at these in reverse order, which is least common usage to most common usage. Graphics you draw programmatically within RB. You can use REALbasic's drawing commands, which are available within a graphics object, to draw lines, points, circles, polygons, etc. If you save the results of those drawing commands to a picture object, you've got a picture. Graphic files you read into your program while it's running. Another way of getting a picture object is to load one from a file. If your computer has QuickTime installed, you can open any graphics format QuickTime supports (which is a fair variety). Here is a program that loads a picture from a file and displays it as the background for window1:
Place this code inside a pushButton's action event to try it. Note that we have a special file type called "picture" defined (Edit menu, "File Types"): it uses ???? and ???? for the Type and Creator, meaning it will let you open any file. After making sure the picture opening worked (p is not nil), we set the backdrop of window1 to p. Graphics you import into your RB project file. The most common way of working with pictures is to import a picture into your project: you do this by dragging a picture into REALbasic's project window: ![]() In the above, I've dragged a picture called "pfs.jpg" to my RB project window where it is displayed as pfs. Note that the name appears in italics, meaning that it's a linked item. That means the actual picture is not embedded in your project file (so don't throw away the original item or your project won't compile). With a picture imported this way, its name appears on menus within REALbasic where you can assign a picture to an item. For instance, windows and canvases have a backdrop property, which displays whatever picture you assign to it. You can pick an imported picture from a popup list to assign to an item's backdrop, like this: ![]() You also could assign the backdrop programatically, like this:
You'd generally put that into the item's Open event so the code gets executed as the item opens. If you do it programatically, you could assign it a picture that you obtained via one of the first two methods of obtaining a picture. With any of the three methods of obtaining a picture, you end up with a picture object. A picture object is simply a REALbasic object that is a picture. Once you've got a picture object, you can tell RB to display it, animate it, even programmatically manipulate it pixel by pixel if you want. I hope that answers your question, Joe. Have fun using pictures! 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 See the REALbasic University Archives
REALbasic University contents ©2001-2004 by Marc Zeedar and REALbasic Developer. All Rights Reserved.
| |||||||||||||||||||||||||||