ARTICLE 12--FOR EACH, INSTR, AND THE PICTUREBOX OBJECT

Programming Using NSBasicCE


ARTICLE 12--FOR EACH, INSTR, AND THE PICTUREBOX OBJECT

All content (c)1999 Serg Koren.
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 EACH  IN 
     ....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!

©2007 Serg Koren & VisualNewt Software.  All rights reserved.