Click here if you are stuck in someone else's frames.
Libraries in QuickBASIC

The following information pertains to creating libraries using QuickBASIC 4.5.  Earlier versions of QuickBASIC may also support libraries but no version of QBasic (that freebie interpreter that comes with MS-DOS 5.x to 6.x) does.  If you are not using QuickBASIC 4.x, this information may not be very useful.

Okay, first off let's build a simple library using the functions found in FGRAPH.BAS code file.  This file contains the code for the DrawCircle and the DrawLine procedures that we've went over before.  Except with a small twist to help illustrate a point.

     ' FGRAPH.BAS -- by Gary Neal, Jr.
     '
     ' Draws Circles and Lines on the graphics screen using floating point math.
     '

     ' Contains the value to increment the Circle's angle with.
     DIM SHARED angleIncr AS SINGLE

     ' DrawCircle
     ' Draws a circle on the graphics screen using floating point math.
     '
     SUB DrawCircle (xOffset%, yOffset%, radius%, C%)
          DIM xPlot!, yPlot!     ' Current pixel being plotted.
          DIM angle!, angleRad!  ' Current angle in degrees & radiens.

          IF angleIncr < 1! THEN angleIncr = .5

          FOR angle! = 0! TO 360! STEP angleIncr

               ' Convert degrees to radiens.
               angleRad! = angle! * (3.141592654# / 180!)

               ' Convert polar to rectangular coordinates.
               xPlot! = (radius% * COS(angleRad!)) + xOffset%
               yPlot! = (radius% * SIN(angleRad!)) + yOffset%

               ' Check boundaries.
               IF xPlot! < 0 THEN
                   xPlot! = 0
               ELSEIF xPlot! > 319 THEN
                   xPlot! = 319
               END IF

               IF yPlot! < 0 THEN
                   yPlot! = 0
               ELSEIF yPlot! > 199 THEN
                   yPlot! = 199
               END IF

               ' Plot the pixel on the graphics screen.
               PSET (xPlot!, yPlot!), C%
          NEXT angle!
     END SUB

     ' Line function
     '
     ' Draws a line on the graphics screen using floating point math.
     '
     SUB DrawLine (X1%, Y1%, X2%, Y2%, C%)
         DIM currX!, currY!            ' Current pixel to be plotted
         DIM deltaX!, deltaY!, slope!  ' 2 deltas and slope

         deltaX! = X2% - X1%           ' Get value for delta X
         deltaY! = Y2% - Y1%           ' Get value for delta Y

         IF ABS(deltaY!) > ABS(deltaX!) THEN

             ' |slope| > 1
             IF Y2% < Y1% THEN
                 SWAP Y2%, Y1%         ' Swap coordinates
                 SWAP X2%, X1%         ' Y1 must be < Y2
             END IF

             ' Compute the slope off the vertical axis
             slope! = deltaX! / deltaY!

             ' Plot each pixel starting at (X1, X2)
             currX! = X1%
             FOR currY! = Y1% TO Y2%
                 PSET (currX!, currY!), C%

                 ' Increment X by slope
                 currX! = currX! + slope!
             NEXT currY!
             EXIT SUB

         ELSEIF deltaX! <> 0! OR deltaY! <> 0! THEN

             ' |slope| < 1
             IF X2% < X1% THEN
                 SWAP X2%, X1%         ' Swap coordinates
                 SWAP Y2%, Y1%         ' X1 must be < X2
             END IF

             ' Compute the slope off the horizontal axis
             slope! = deltaY! / deltaX!

             ' Plot each pixel starting at (X1, X2)
             currY! = Y1%
             FOR currX! = X1% TO X2%
                 PSET (currX!, currY!), C%

                 ' Increment X by slope
                 currY! = currY! + slope!
             NEXT currX!
             EXIT SUB

         ELSE

             ' Set a single pixel because X1 = X2 and Y1 = Y2
             PSET (X1%, X2%), C%

         END IF
     END SUB

     ' Returns the angleIncr value for other modules.
     '
     FUNCTION GetAngleIncr!
         GetAngleIncr! = angleIncr
     END FUNCTION

     ' Sets the angleIncr value for other modules.
     '
     SUB SetAngleIncr (newIncr AS SINGLE)
         IF newIncr > 0 THEN
             angleIncr = newIncr MOD 360
         END IF
     END SUB

Okay, the first example on how we will reuse the code is to load it into QuickBASIC as a second module.  To do that, we must have some code that we plan to use as a main module.  In other words, our main program.  This program, called RANGRAPH.BAS will do just the trick.

     ' RANGRAPH.BAS -- by Gary Neal, Jr.
     '
     ' Generates random graphics using the procedures found in FGRAPH.BAS
     '

     SCREEN 13

     ' Random pixels
     WHILE INKEY$ = ""
         PSET (RND * 320, RND * 200), RND * 256
     WEND

     ' Clear keyboard
     WHILE INKEY$ <> "": WEND
     CLS

     ' Random lines
     WHILE INKEY$ = ""
         DrawLine RND * 320, RND * 200, RND * 320, RND * 200, RND * 256
     WEND

     ' Clear keyboard
     WHILE INKEY$ <> "": WEND
     CLS

     ' The next line is the line of interest
     ' SetAngleIncr 1!

     DrawCircle 160, 100, 90, 15

     ' Wait for keypress
     WHILE INKEY$ = "": WEND

     ' Clear the keyboard
     WHILE INKEY$ <> "": WEND

     ' Clean up and exit
     SCREEN 0, 0, 0
     END    ' You can use SYSTEM also.

Now, ensure that you load both files in as seperate modules.  Then make sure that you set RANGRAPH.BAS as the main module.  If you are not sure how to do this, consult your QuickBASIC documentation or online help.  Obviously, this set up will not work in QBasic, eeven though the code itself will.  To run this in QBasic, you must merge the two files RANGRAPH.BAS and FGRAPH.BAS into a single file and load it into QBasic (defeating the purpore of this exercise).  If you are all set, run it and watch it fly.

You notice that this program plots many pixels and draws many lines but only one circle.  This one circle is to illustrate a point.  Does the circle appear "broken up" to you?  Well, remove the apostrophe (REM) from the beginning of the line of interest in the RANGRAPH.BAS program and run it again.  Ah, the circle should appear even more broken up now.  Basically, we increased the 'angleIncr' variable by setting it to one, now for the million dollar question that's probably in your mind.  Why use a SUB procedure to set the value of the variable 'angleIncr' and a FUNCTION to retreive it?  Why not just access it directly?  Simply put, you can't.  At least not from the RANGRAPH module.  Why not?  Isn't 'angleIncr' global?  It is, after all, declared using DIM SHARED!

The truth is, no, DIM SHARED does not make a variable GLOBAL.  It does, however, allow the variable to be seen by all procedures within the module that it's declared in.  For example, the variable 'angleIncr' can be seen (and therefore used) by all functions within the FGRAPH.BAS code module.  But only the functions and procedures can be seen outside the code module, hence the reason why the GetAngleIncr function and the SetAngleIncr procedure.  Don't beleive me, try it, modify the lines of interest within the RANGRAPH.BAS module and make it look like so:

     ' The next line is the line of interest.
     ' SetAngleIncr 1!
     angleIncr = 1!    ' Added line...

Now run it and you'll see that the circle is back to the way it was prior to your removing the comment from the line of interest.  Still not convinced?  Okay, add this line to the RANGRAPH.BAS program and run it.

     ' Clean up and exit.
     SCREEN 0, 0, 0
     PRINT angleIncr, GetAngleIncr     ' Added line
     END     ' You can use SYSTEM also.

Run it and the following numbers should appear after displaying all the graphics:

     1               0.5

As you can see, modifying 'angleIncr' in the RANGRAPH.BAS module does not affect the variable of the same name in the FGRAPH.BAS module.  Variables in QuickBASIC cannot be shared across modules.

Note:  If you've used Visual Basic for Windows before you'll notice that BAS file modules allow the use of a GLOBAL keyword to allow a variable to be modified by all modules as well as procedures.  QuickBASIC does not support truly GLOBAL variables.  Visual Basic versions 4.0 and up suggest using the PUBLIC keyword for global variables since they also work in forms as well as modules.

Previous Page | Main Page | Next page