Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Windows Programming With Basic


APR92: WINDOWS PROGRAMMING WITH BASIC

WINDOWS PROGRAMMING WITH BASIC

GFA Basic simplifies Windows programming while maintaining DOS compatibility

Raymond J. Schneider

Ray is the director of engineering at ComSonics Inc. in Harrisonburg, Va. He is a licensed professional engineer in the state of Virginia and a doctoral student of Information Technology at George Mason University.


Writing programs for Windows 3 can be a daunting task, especially with Microsoft's SDK (System Development Kit) and other C-based development environments. Basic, however, promises to deliver Windows programming with much less effort. And with Microsoft's Visual Basic, Within Technologies' Realizer Basic, and GFA Software's GFA Basic for Windows, there's suddenly a plethora of Windows development tools available for all programmers.

Sure, many programmers think that "real programmers" don't use Basic, but it can't be beat for writing quick, scientific programs. (In the IEEE 488 world of instrument control, in fact, Basic is the norm.) Basic is also terrific for checking algorithms and building those quick-look prototypes.

Consequently, when I received a copy of GFA Basic for Windows 3, I was anxious to put it through its paces. To test GFA Basic's effectiveness as a Windows programming tool, I built an application based on a GW Basic program I'd previously published (see Computer User, November 1990) that uses Lorenz equations to show how mathematical chaos works. The Windows version of the application presented here uses standard Windows features such as menuing, multiple windows, buttons, and so on.

Programming for Chaos

In his efforts to understand the unpredictability of weather, MIT meteorologist Edward Lorenz discovered chaos when experimenting with a simplified model of the weather in the early '60s. He found that even tiny changes in the starting conditions quickly led to major shifts in the predicted behavior. This came to be called the "Butterfly Effect," because changes as small as the flick of a butterfly's wing in initial conditions led to substantial changes later, in the time evolution of the equations. Lorenz concluded that if weather actually behaves in a fashion similar to his equations, then long-range weather prediction isn't possible.

The Lorenz equations, shown in Example 1(a), are a simplified model of atmospheric convective warming -- a flat, fluid layer is warmed from below and cooled from above. The variable x represents the convective motion, y the horizontal temperature variation, and z the vertical temperature variation. Sigma, Rho, and B are proportional to the Prandtl number, the Rayleigh number, and the size of the region being approximated, respectively. All these parameters are positive.

Example 1: (a) The Lorenz equation; (b) a typical loop DO loop to process events (UNTIL MENU signals that the close box has been moused); (c) using a SWITCH statement to process menu selections.

  (a)

  dx/dt=SIGMA*(-x+y)
  dy/dt=-x*z+RHO*x-y
  dz/dt=x*y-B*z

  (b)

  DO
    GETEVENT
    [Statements to Process Events]
  UNTIL MENU(1)=4

  (c)

  IF MENU(1)=20
    SWITCH MENU(0)
    CASE 1 ...
    ENDSWITCH
  ENDIF

The Lorenz equations are three dimensional, so you can have three different normalized plane views. Consequently, I wanted to use a menu bar to select views of the Lorenz equations to graph, and to provide some pop-up requesters to set the parameters. To keep it simple, I wanted to have a menu bar that let me select views (XY, YZ, XZ), a pop-up requester to set the initial parameters (Sigma, Rho, and B), and finally a Go menu item to start the calculations and plotting. The equations run in all the selected boxes until a predefined number of points has been plotted; selecting Go again will plot another slug of points.

My first step was getting the menu bar to activate. This seemed easy because all you have to do is initialize a string array with the various menu titles, submenu titles, and separating blank strings and then invoke the menu with a MENU array$() command.

All communications between GFA Basic and Windows take place through an array named MENU(), which is only a little confusing. You have to get used to Windows doing all sorts of things over which you have little control: At any moment your program must be prepared to respond to an event caused by some operator action. (This event-driven programming style does not come naturally to a Basic programmer used to strictly procedural code.)

Processing Events

GFA Basic hooks into the Windows environment through a variety of functions, the MENU() array, ON MENU functions, and looping while listening to Windows. A typical construct is shown in Example 1(b).

There are two ways to process menu items: The first uses a SWITCH statement in the event loop, and the second uses the ON MENU GOSUB statement. In the application (see listing One, page 112), I chose the first method, which nests a SWITCH statement inside an IF statement.

In Example 1(c), for instance, MENU (1) is set to 20 to signal a menu-bar event, and the string array selected is contained in MENU(O). It took me a little time to discover that the menu titles, despite being highlighted and having a string-array number, were not returned in MENU(O). So, I changed my menu bar to have GO as a submenu item rather than a main-menu item. There's probably a way to detect the mouse click on the main-menu item, but I didn't find it in the documentation. Once you can invoke a menu-bar item, it's simple to incorporate the necessary instructions in the CASE elements of the SWITCH statement.

Dialogs and Views

Next I needed a dialog box to pop up on the screen and let me enter the critical parameters of the Lorenz equations -- SIGMA, RHO, and B. GFA Basic supplies a lot of push buttons, radio buttons, check boxes, combo boxes, list boxes, and so on. But all I wanted was a simple box to enter data into and a button to push when finished. Digging through the documentation produced instructions on how to set up a dialog box. The procedure SetDialog() records the process. Within a DIALOG statement, you list the properties and locations of the control elements that you want in the dialog box. When you've defined all these items, you put the dialog box on the window with a SHOW-DIALOG #n statement, where #n is the number of the dialog.

The views were established as child windows -- windows inside a parent window. To maximize simplicity, I didn't try to incorporate resizing or redrawing functions, but with enough attention to detail (all those messages in the MENU() array) you can detect window resizing, requests to paint the window over, and all the other amazing amount of stuff you have to keep track of to maintain a well-behaved Windows application.

The HandleMessage() and GetText() procedures were modeled on similar procedures in the GFA Basic manuals.

Computing the Function

The final task was to add the computation and graphics to the application. I wrote a single procedure, PlotLorenz (X,Y,Z,N%,I%), which plots N% points starting at X,Y,Z in the plane identified by the integer I% (1 = XY, 2 = YZ, 3 = ZX). On repeated presses of GO, the program continues to plot points in additional groups of N%, set to 100 in the program. The actual plotting was accomplished using the LINE x1,y1,x2,y2 statement. I made no attempt to scale the data for proper aspect ratio or "handedness," although that would be more accurate for visualization.

Nevertheless, the resulting program is interesting. First you pop open the windows you want (usually all three), then open the control menu and select "Set Parameters." Next, you enter the values in the EDITTEXT boxes and mouse on the OK button to accept the values. Finally, click the mouse on GO and continue until satisfied. Restart the program for another run. A reasonable starting value is SIGMA = 60, RHO = 40, B = 20. This gets you a view of a strange attractor with a lazy-eight orbit; see Figure 1.

About GFA Basic for Windows

While the chaos program gave me an opportunity to sample the joys of Windows programming, I've only lightly touched the power of GFA Basic. The programming environment combines a syntax-sensitive editor and a direct-mode environment which I didn't find much occasion to use. The editor is easy to use and helpful, because it refuses to let you enter a line with incorrect syntax. It could, however, be confused by incorrectly terminated compound statements (NEXT I% or ENDIF, for example).

The language itself is rich in capability. It includes a large array of graphics functions, linear algebra (matrix) functions, and a host of specialized functions for handling the Windows environment. Remarkably, except for about 25 Windows-specific commands, the language is compatible with its DOS counterpart, so that developers creating applications in GFA Basic can easily transport them, complete with windowing functions, to a non-Windows environment.

GFA Basic for Windows comes with several example programs, written in GFA Basic, which double as utilities and examples of powerful Windows code. RCS.GFW is an elementary dialog editor which generates ASCII text files of statements that create the code for radio buttons, combo boxes, and so on for an application. When you SAVE your window with the various elements that you have selected and positioned, you get the necessary GFA Basic instructions written to a text file, which can then be merged with your program under development.

ICOEDIT.GFW is another example, this time of an icon editor. I played around with ICOEDIT and created a little icon with a feather pen and an ink bottle. Then I saved the icon to a file with an .ICO extension.

To test the built-in compiler which generates .EXE files, I first asked it to make an .EXE file out of the ICO-EDIT.GFW. This it did in a flash. I attached the ink-pot icon I'd designed to the file and popped it into my program-manager window. I double-clicked on the ink pot and there I was, running the icon editor as an independent .EXE file. The compiler ran quickly and transparently.

I found several of the example programs somewhat fragile. Some locked up my machine, forcing an ALT-CTRL-DEL to escape from the situation.

GFA vs. Visual Basic

How does GFA Basic stack up to the more famous Microsoft Visual Basic? The two are sharply different in philosophy and feel. Visual Basic is a dramatic departure from traditional procedural programming languages because it requires the programmer to adopt a particular event-driven, state-machine model of programming.

Visual Basic programs are not composed in a text-editor environment, but rather in an environment that resembles a draw program. The left side of the screen contains a vertical panel of tool icons, while in the center of the screen is a generic window to receive the programmer's ministrations.

To construct a Visual Basic program, you first create the forms that will communicate with the user. You then add features such as menus, text boxes, and buttons to your forms. Most of this is accomplished by "hook and drag" mousing around. Then you add code to each element of your form or control in a text editor, so that when the control is invoked, the program does the right thing. After saving your code as a project, you test it and create an executable. This is easy for small programs with just a few choices, but it gets complex fast.

The tools Visual Basic provides for manipulating forms include a variety of buttons and boxes as well as labels, scrolling controls, and timers. If you don't find enough controls already built in, Microsoft offers the Control Development System so you can develop your own.

For small programs, Visual Basic is the hands-down winner in the ease-of-use category. As programs get larger, however, you'll find that more discipline is required in using Visual Basic, because the event-driven paradigm fragments the program into small pieces which may be invoked under a variety of complex conditions. Debugging such a beast is rather different from debugging structured procedural code. Moreover, when you print out your Visual Basic programs, you don't get all the code. Menus generated in the menu generator, for example, don't produce any printout when you print out your program. The same is true of your forms, which are built up but not documented in a readable form by the system.

GFA Basic is harder to use for small programs than Visual Basic, but it has the advantage of offering source-code compatibility with its DOS counterpart to create windows and pull-down menus, and to control mouse actions. In addition, GFA Basic adds advanced graphics functions to create splines, ellipses, arcs, and Bezier curves; DLLs to access and update dBase files; LAN support; support for huge arrays up to 20 Mbytes; and more.

Conclusion

GFA Basic is a good way to get into Windows programming and offers a way of more quickly creating at least relatively simple Windows applications. A good friend of mine likes to talk about the law of "Conservation of Complexity" -- there's no such thing as a free lunch. While GFA Basic can help make Windows programming a little less difficult, the fact remains that there's a complex beast under those windows, and it takes a complex program to keep up.

Products Mentioned

GFA Basic for Windows 3 GFA Software Technologies Inc. 27 Congress St. Salem, MA 01970 508-744-0201 $295


_WINDOWS PROGRAMMING WITH BASIC_
by Raymond J. Schneider



[LISTING ONE]
<a name="00ef_000e">

/* Lorenz Equations in GFA BASIC
/* Copyright 1991 Raymond J. Schneider
XEND=0,YEND=0,ZEND=0 //Initializes end of plot run variables
/* Configure and Open Parent Window
pstyle%=      WS_OVERLAPPEDWINDOW
OR pstyle%, WS_CLIPCHILDREN
OR pstyle%, WS_VISIBLE
TITLEW #1, "Lorenz Equations"
PARENTW #1,0,0,_X,_Y,pstyle% //Open full window

/* Configure three child windows
cstyle%=0
cstyle%=  WS_SYSMENU

/* Title the windows
TITLEW #2, "Lorenz XY-View"
TITLEW #3, "Lorenz YZ-View"
TITLEW #4, "Lorenz ZX-View"

/* Initalize Menu Structure
DIM m$(15)
m$(0)="&Views"   //First Menu Item
m$(1)="&XY-View" // Sub-Menu Items
m$(2)="&YZ-View"
m$(3)="&ZX-View"
m$(4)=""         // Null-string terminates sub-menus
m$(5)="&Control"
m$(6)="&Set Parameters"
m$(7)="&GO"
m$(8)=""
m$(9)=""
MENU m$( )

/* Main Program
cww%=_X/2-30,chh%=_Y/2-30
ON MENU MESSAGE GOSUB HandleMessage( )
DO
  GETEVENT
  IF MENU(1)=20 //Then a Menu Selection Has been Pressed
    /* Process Menu Selection
    SWITCH MENU(0)
    CASE 1 // Open XY-View
      CHILDW #2,1,5,5,cww%,chh%,cstyle%
    CASE 2 // Open YZ-View
      CHILDW #3,1,cww%+8,5,cww%,chh%,cstyle%
    CASE 3 // Open ZX-View
      CHILDW #4,1,5,chh%+8,cww%,chh%,cstyle%
    CASE 6 //Set-Parameters
      EXIT IF   DLGRV&<>0
      SetDialog()
      DO
        SLEEP
      UNTIL DLGRV&
      TEXT 0,0,"Sigma="+STR$(SIGMA)
      TEXT 0,12,"Rho= "+STR$(RHO)
      TEXT 0,24,"B= "+STR$(B)
    CASE 7 // Calculate Lorenz and Plot in Windows
      TOPW #2
      IF XEND=0  //Initialization of starting conditions X,Y,Z
        X=1
      ELSE
        X=XEND
      ENDIF
      IF YEND=0
        Y=1
      ELSE
        Y=YEND
      ENDIF
      IF ZEND=0
        Z=1
      ELSE
        Z=ZEND
      ENDIF
      PlotLorenz(X,Y,Z,100,1)
      TOPW #3
      PlotLorenz(X,Y,Z,100,2)
      TOPW #4
      PlotLorenz(X,Y,Z,100,3)
    ENDSWITCH
  ENDIF
  IF MENU(1)=4
    SWITCH MENU(14)
    CASE 2
      CLOSEW #2
    CASE 3
      CLOSEW #3
    CASE 4
      CLOSEW #4
    ENDSWITCH
  ENDIF
  EXIT IF MENU(1)=4 && MENU(14)=1
LOOP
CLOSEW #1
END

PROCEDURE HandleMessage( )
  IF DLG(1)=MENU(15)
  ENDIF /*Discard General Messages
  DLGRV&=0
  hw%=GetParent(MENU(15))
  IF hw%=DLG(1)
    SWITCH MENU(6)
    CASE 100
      IF MENU(1)=30
        GetText(1,101,SIGMA$)
        GetText(1,102,RHO$)
        GetText(1,103,B$)
        SIGMA=VAL(SIGMA$),RHO=VAL(RHO$),B=VAL(B$)
        DLGRV&=MENU(6)
      ENDIF
    ENDSWITCH
  ENDIF
RETURN

PROCEDURE GetText(d|,di&,VAR a$)
  LOCAL buffer$
  buffer$=SPACE$(100)
  IF GetWindowText(DLGITEM(d|,di&),V:buffer$,LEN(buffer$))>0
    a$=CHAR{V:buffer$}
  ELSE
    a$=""
  ENDIF
RETURN

PROCEDURE SetDialog()
  s%=WS_TABSTOP
  sb%=s%
  sb%|=BS_DEFPUSHBUTTON
  seb%=s%
  seb%|=WS_BORDER
  seb%|=ES_UPPERCASE
  ~SetFocus(DLGITEM(1,100))
  DLGRV&=0
  DIALOG #1,325,175,300,160,"Set Parameters"
    DLGBASE UNIT
    DEFPUSHBUTTON "OK",100,80,65,14,12,sb%
    EDITTEXT "",101,80,10,40,12,seb%
    EDITTEXT "",102,80,30,40,12,seb%
    EDITTEXT "",103,80,50,40,12,seb%
    RTEXT "SIGMA",104,10,10,55,12
    RTEXT "RHO",105,10,30,55,12
    RTEXT "B",106,10,50,55,12
  ENDDIALOG
  SHOWDIALOG #1
RETURN

PROCEDURE PlotLorenz(X,Y,Z,N%,I%)
  /* SIGMA, RHO, B assumed Global
  LOCAL LX,LY,LZ,LX1,LY1,LZ1,DT,j%
  LOCAL DX,DY,DZ
  PX=_X/4+50,PY=_Y/4+10 // Plot Offsets
  LX=X,LY=Y,LZ=Z,DT=.01
  FOR j%=1 TO N%
    DX=SIGMA*(LY-LX)*DT
    DY=(-LX*LZ+RHO*LX-LY)*DT
    DZ=(LX*LY - B*LZ)*DT
    LX1=LX+DX
    LY1=LY+DY
    LZ1=LZ+DZ
    SWITCH I%
    CASE 1 //PLOT XY
      LINE LX+PX,LY+PY,LX1+PX,LY1+PY
    CASE 2 //PLOT YZ
      LINE LY+PX,LZ+PY,LY1+PX,LZ1+PY
    CASE 3 //PLOT ZX
      LINE LZ+PX,LX+PY,LZ1+PX,LX1+PY
    ENDSWITCH
    LX=LX1,LY=LY1,LZ=LZ1 // Update function
  NEXT j%
  XEND=LX,YEND=LY,ZEND=LZ
RETURN


Copyright © 1992, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.