Programming Using NSBasicCE
All content (c)1999 Serg Koren.
ARTICLE 12--FOR EACH, INSTR, AND THE PICTUREBOX OBJECT
All rights reserved.
Welcome to the "dozenth" installment of NSBasicCE.
This time around we discuss the "EACH" version of the FOR NEXT loop, the PRINT statement and the PictureBox object.
Leftovers from Last Time
Last time around we talked about getting loops and asked you to modify the answer to the last problem to use loops. Here is the code from last time that you had to start with:
'-------------code starts here
'
' Article 10
'
OPTION EXPLICIT
DIM Colors(7)
' our color array
'-------------- create our UI
' create a listbox
SUB CreateMyListbox
ADDOBJECT "ListBox","MyListBox",120,10,100,120 ' leave room for label
' load the colors into the listbox...assumes you've set up the array first
MyListBox.AddItem Colors(1)
MyListBox.AddItem Colors(2)
MyListBox.AddItem Colors(3)
MyListBox.AddItem Colors(4)
MyListBox.AddItem Colors(5)
MyListBox.AddItem Colors(6)
MyListBox.AddItem Colors(7)
END SUB
' create a label
SUB CreateMyLabel
ADDOBJECT "Label","MyLabel",35,5,80,20 ' to the right of the listbox
MyLabel.Caption = "Colors"
END SUB
' create our Remove commandbutton
SUB CreateRemoveCommandButton
ADDOBJECT "CommandButton","Remove",10,35,100,20
Remove.Caption = "Remove"
END SUB
' create our Add commandbutton
SUB CreateAddCommandButton
ADDOBJECT "CommandButton","Add",10,65,100,20
Add.Caption = "Add"
END SUB
' create FindMissing commandbutton
SUB CreateFindMissingCommandButton
ADDOBJECT "CommandButton","FindMissing",10,95,100,20
FindMissing.Caption = "Find Missing"
END SUB
' create FindDuplicates commandbutton
SUB CreateFindDuplicatesCommandButton
ADDOBJECT "CommandButton","FindDuplicates",10,125,100,20
FindDuplicates.Caption = "Find Duplicates"
END SUB
'----------------event handlers
' Our Remove handler
SUB Remove_click
' remove the selected listbox item
MyListBox.RemoveItem MyListBox.ListIndex
' MyListBox.ListIndex returns the number (array index) of the selected item
END SUB
' Our Add handler
SUB Add_click
' add the selected listbox item to the end of the listbox list
MyListBox.AddItem MyListBox.List(MyListBox.ListIndex)
' MyListBox.List( ) returns the text in the list
END SUB
' Find missing event handler
SUB FindMissing_click
' you probably got stuck trying to figure out how to do this... don't worry this was a trick problem.
END SUB
' Find duplicates event handler
SUB FindDuplicates_click
' you probably got stuck trying to figure out how to do this... don't worry this was a trick problem.
END SUB
'----------------main routines here
' set up our color array
SUB SETUPCOLORS
Colors(1) = "Red"
Colors(2) = "Orange"
Colors(3) = "Yellow"
Colors(4) = "Green"
Colors(5) = "Blue"
Colors(6) = "Indigo"
Colors(7) = "Violet"
END SUB
' set up our user interface
SUB SETUPUI
CreateMyListBox
CreateRemoveCommandButton
CreateAddCommandButton
CreateFindMissingCommandButton
CreateFindDuplicatesCommandButton
END SUB
SUB INITIALIZE
SETUPCOLORS ' this has to be done first because its used by CreateMyListBox
SETUPUI
END SUB
SUB MAIN
INITIALIZE
END SUB
MAIN ' our normal kickstart
'-------------code ends here
A hint that you need a loop are sequences of lines that are identical apart from the index into an array. In this example there are two subroutines that are ripe for loops: CreateMyListBox and SETUPCOLORS.
For CreateMyListBox replace the existing one with:
' create a listbox SUB CreateMyListbox
DIM I ' our index for our FOR loop ADDOBJECT "ListBox","MyListBox",120,10,100,120 ' leave room for label ' load the colors into the listbox...assumes you've set up the array first FOR I = 1 TO 7 ' loop through all of our colors MyListBox.AddItem Colors(I) ' add a row with the proper color NEXT I
END SUB
SETUPCOLORS is harder to figure out. That is because we need to figure out how to get the hardcoded colors into an indexable list. But it seems by hardcoding it we already have, so do we need to put it into a loop?
No, not really. The existing code is good enough for most purposes. Personally, (a style thing) I still don't like the fact that the colors are actually hidden somewhere in the code, which makes it harder to find if say we want to add a color "Gray" for instance.
What I would do is extract the actual colors into a global string:
DIM MasterColors DIM MaxColors MaxColors = 7 'number of colors MasterColors = "Red,Orange,Yellow,Green,Blue,Indigo,Violet," ' note the comma at the end...we need this
and then in the SETUPCOLORS subroutine I'd pull the appropriate substring out and assign it to the array. But to do this we need to know about another string function. We talked earlier about LEFT, RIGHT, and MID, now we need to learn about something called:
INSTR and INSTRREV
INSTR and INSTRREV are often used in combination with LEFT, RIGHT, and MID. INSTR lets you find where a certain substring starts, starting from the left end, INSTRREV does the same, but starts from the right end of the string (last character). How do they find a substring?
If you refer to the manual you see, that INSTR and INSTRREV are functions that are called using:
INSTR([start],<main string>,<delimiter)
[start] is an optional chaaracter position where to start searcing (say start at character 3). <main string> is the string we are searching through (in our case MasterColors), and <delimiter> is a string that we are looking for.
For example, the following code:
DIM A DIM I A = "ABCDEFABCDEF" I = INSTR(A,"B") ' assume [start] is 0, find B MSGBOX I I = INSTR(I+1,"B") ' find the next occurance of B MSGBOX I
would return 2, and 8 In our assignment, MasterColors has colors separated by commas, so "," would be a natural delimiter. So to find the end of a string we search for a comma. That's why we need the comma at the end in MasterColors, it makes finding the last element easier. How do we find the start of the next string? It's the location of the last comma plus one.
So our code becomes:
SUB SETUPCOLORS DIM I ' Index into our array and FOR loop DIM J ' Index into our MasterColors string DIM J1 ' last occurance of a comma DIM TempColor ' a string that holds an actual color once we parse it from MasterColors J = 0 ' Initialize our index J1 = 0 FOR I = 1 TO MaxColors ' process each color J = INSTR(J1 + 1,MasterColors,",") ' find the next occurance of the , separator Temp = MID(MasterColors,,J,J1 - J) ' extract the actual color between commas (starting at J and for length J1 -J) Colors(I) = Temp ' assign the actual color to our array now. NEXT END SUB
It looks more complicated than the original (and it is), but if you need to add more colors (or subtract colors) all you have to do is change the value of MaxColors and our MasterColors string, and everything continues to work properly!
The lines:
J = INSTR(J1 + 1,x,",") Temp = MID(x,,J,J1 - J) y(I) = Temp
are what are known as a "pattern" in computer jargon. A "pattern" is merely a programming idiom (like an English idiom...if you don't know what "idiom" means, look it up.) or a way of programming a common task. Something you'll do again and again. And what this tells me (and should you at this point) is that it belongs in its own subroutine or function...I'll leave writing this function as an exercise for you to solve. I have one that I use all the time to parse a string delimited by commas. It's a very useful routine, and you should have one in your own bag of tricks!
On to our next topic:
FOR EACH..NEXT
The FOR EACH statement is a very useful way of going through an array and doing something for each (hence the name) element in the array. It's syntax is easy:
FOR EACHIN ....do stuff NEXT
is the item at a given index into the array. Usually you give it a more descriptive name than I, or J (which is typical for a normal FOR NEXT). is the array you want to do things to. For example lets say you want to have an array of 100 numbers where the value of the element is the index value. That is, element 33 has the number 33 in it, the element 56 has 56, etc. DIM NumberArray(100) ' our array DIM I ' a number I = 0 FOR EACH Number IN NumberArray ' Number automatically becomes the element at a given index. Number = I I = I + 1 NEXT Yes: FOR I = 0 TO 100 NumberArray(I) = I NEXT
is better, I just made up the example to show you the differences. The FOR EACH doesn't require you to DIM the index., the normal FOR does. The FOR EACH is a bit more readable (understandable) than the normal FOR. Here's another example. The FOR EACH doesn't use a subscribe (index) into the array to get an element, the FOR does. Let's print out our Colors array from the code above:
FOR EACH Color in Colors PRINT Color NEXT
is a lot easier to program and understand than:
FOR I = 1 TO MaxColors PRINT Colors(I) NEXT
That's the FOR EACH loop. Once you get used to using it you'll like it. Now to our object of the day.
PICTUREBOX
A PictureBox is one of the most complex objects you'll deal with. It's complexity lies in the different properties, events, and methods it allows you to manipulate. At its core, a PictureBox allows you to draw text and graphics in a contained area on the screen.
You already know how to create one:
ADDOBJECT "PictureBox","MyPictureBox,"10,10,200,200
I suggest first reading the manual to get a feel for the different things you can do with a PictureBox. Then try to write a program that uses them. Here's a quick run through of the things a PictureBox has:
Properties:
• BorderStyle - 0, blends with the window, 1, has a border.
• DrawWidth - a number specifying how thick lines will draw.
• FillColor - enclosed polygons (circles, rectangles, etc. can be drawn with a single command) can be filled with a color
• FillStyle - 0 solid, 1 transparent
• FontTransparent - True/False (no I don't know why this isn't 0,1)
• Picture - you can pass in the name of a graphics file (it has to be a *.bmp) and the picture will automatically draw itself into your picturebox.
• Scaleheight/Width - you can specify how things get scaled in the picturebox
• ScaleLeft/Top - left and top edges of the object
• ScaleMode - this is a MS thingy. Most of the time you want to set this to 3 (pixels) otherwise you'll wonder why things don't draw the way you expect. For more info, find some MS documentation online.
Methods:
• Cls - Erases the picturebox contents
• DrawCircle - Draws a circle, or ellipse. You can specify the radius, color, etc.
• DrawLine - This lets you specify a line or set of lines. You can also set a flag to specify you want to draw a box (rectangle or square).
• DrawPicture - lets you draw and manipulate a bitmap image file (*.bmp)
• DrawPoint - just what it says. Turn on a single pixel.
• DrawText - pretty useless since it doesn't let you specify WHERE in the box you want to draw the text. Might be useful for debugging.
• Refresh - redraw the contents of the PictureBox (if something needs to be redone because something covered the PictureBox say.)
• ScaleX, ScaleY,SetScale - lets you convert scale values
• TextHeight, TextWidth - Returns the height and width of the heighest or widest lines of text. Used with DrawText.
Events:
• KeyDown - key is pressed
• KeyUp - key is released
• KeyPress - KeyDown followed by KeyUp
• MouseDown, MouseUp - mouse clicks
• MouseMove - MouseDown and then you move the mouse (like a drag).
Yes the number of Properties, Methods, and Events is large, but taken individually, they aren't too confusing. The best way to learn about the PictureBox is to use it. So...
For next time
Using the Colors program,
- Add a PictureBox object and draw a filled box of the given color whenever the user Adds a color to the list. (Just have one colored box in the PictureBox at any given time. Draw the last added color.)
- When the user taps a key on the keyboard. Draw the letter inside the picturebox.
- When the user taps on the colored box, display a message with the name of the color being tapped.
We'll also go over the PRINT statement, the REDIM statement, and the TextBox object!
Cheers!

