home *** CD-ROM | disk | FTP | other *** search
- As programmers, we all have several creative problem-solving routines we have
- written for clients that we like to brag about -- they were clever, compact,
- and tight. They might have even compiled and run perfectly the first time.
- But let's face it -- writing meaningful, consistent user interfaces with
- exceptional attention to thorough error-trapping takes a lot of TIME, perhaps
- even the most time we spend in the actual coding development and code writing
- process. It certainly increases the bulkiness of our code (by way of many
- K-bytes of TEXT data structures).
-
- But this aspect of programming -- user interface --is the singularly most
- important determining factor of client satisfaction. As a maintenance
- programmer, I have been apalled at the abject lack of user interfaces. In
- one situation, the previous coder before me wrote coder before me wrote no
- code to give the user any status messages indicating what was happening
- when the user was finished working with data. i.e., "Saving the new data to
- disk", "Deleting your record from the file", etc.). The little red light
- on the drive may have come on, but what was happening was anyone's guess.
- When an internal error from an error trap was encountered, there were often
- no messages -- simply a return to the previous calling menu before the error.
- Apparently, the user was supposed know what error had been committed. Even
- worse, some of the important data input was not error-trapped that could
- overwrite data in an unintended record, or simply crash the program.
-
- In virtually EVERY maintenance program I have ever worked on, I have been
- absolutely shocked at the AUSTERITY of the input screens I have seen. There
- is no regard for the fact that clients have to look at that screen, perhaps
- as often as long as eight full hours EVERY WORKING DAY. If the screen is
- dull and unattractive, how long do you think it will be before they start
- making mistakes--and then blaming YOU, the programmer, for data crashes???
-
- The recently vast improving user interfaces in commercially available general-
- user software (word processors, database managers, spreadsheets) makes
- inexcusable this "let's-continue-the-awe-about-computers-and-programming-
- with-mystery" fashion of doing business with a client. I predict in a few
- years anyone thinking that nothing less than absolutely superior user
- interfaces --including top-notch, attractive screens-- for a common end user
- will render that individual unemployable in programming. And since dbaseIII
- handles much of our file handling activities with single lines of code and/or
- commands, there is now more time for programmers to spend more of their
- precious time with good user interface development.
-
- To that end, then, I have developed some simple, yet extremely useful
- subroutines that can be used almost as meta-commands. It makes development
- a lot simpler.
-
-
-
-
- This DB3STOCK.ARC file contains the following files:
-
-
- DB3STOCK.DOC -- this (introductory) file
-
-
-
- bigboxdt.prg -- A simple "MAIN MENU" type, graphics-drawn box that centers,
- highlights, and displays a header message at the top inside
- line of the box, and then displays the date and time at the
- left and right sides of the box, respectively.
-
- boxclear.prg -- A routine that clears the inside of BIGBOXDT without having
- to clear the screen and redraw it. This is helpful for
- continuous LISTs or DISPLAYs of data. The starting line of
- the clearing procedure is defined by the numeric variable
- LN, and it is helpful to have it user defineable BEFORE ent-
- ering the routine, as you may have subheaders towards the
- top of the screen that you do NOT want to erase and redraw.
-
- smallbox.prg -- A routine that creates a smaller box on the screen. Useful
- for help screens or flagging important data entry.
-
- slinboxm.prg -- A routine that draws a single line box in the middle of the
- screen, and then centers, highlights and displays a user-
- defined message (MSG) inside the box.
-
- slinboxt.prg -- A routine that draws a single line box at the top of the
- screen, and then centers, highlights and displays a user-
- defined message (MSG) inside the box.
-
- slinboxb.prg -- A routine that draws a single line box at the bottom of the
- screen, and then centers, highlights and displays a user-
- defined message (MSG) inside the box.
-
- dlinboxm.prg -- These three programs are indentical to their "SLINBOXx" sub-
- dlinboxt.prg -- routines above, with the exception that they use a double
- dlinboxb.prg -- line graphic-oriented box instead of the single line box.
-
- linprm23.prg -- This is a metacommand that will save no ends of programming,
- particularly where multiple branches are about to occur. Let's
- take an example: you have displayed a screen of data from a
- file record. The decision list is as follows:
-
- "<A>dd <E>dit <D>elete <N>ext <P>revious <X>Exit"
-
- Merely define the variable "MSG" as the text in quotes above.
- Define the variable "TEST" as the string literal :"AEDNPX" .
- Define TZ as " ". Now the next line of code would be "DO
- LINPRM23". The routine centers, highlights and displays the
- text and waits for the <A>, <E>, <D>, <N>, <P>, or <X> key
- to be pressed. The input is automatically made uppercase.
- And only those individual keys from "TEST" are acceptable
- input. The final code in this example would look like this:
-
- tz=" "
- test="AEDNPX"
- msg="<A>dd <E>dit <D>elete <N>ext <P>revious <X>Exit"
- do linprm23
-
- You are now free to use the appropriate IF/ENDIF or
- DO CASE/CASE statements -- based on the key pressed.
-
- linmsg23.prg -- Sometimes you will want to put a message on the screen and
- wait for the user to acknowledge the message. That is exactly
- what this routine does. You define the message, and it
- centers, highlights, and displays the message, and then waits
- for any keystroke. As in the subroutine above, you define the
- "MSG" and "TZ" variables before entering the routine. This
- routine is FAR more attractive than the WAIT statement, and
- is more helpful to an end user because you can customize the
- message to help guide the user when he continues.
-
- prtmsg23.prg -- This routine is identical to the routine above, except that
- no input of any kind by the user is required. It merely high-
- lights, centers, and displays the message ("MSG") at the bottom
- of the screen. This routine is immensely useful for writing
- those oh-so-needed messages like, "Saving new data to disk"
- or "ACCOUNTS CLOSING IN PROGRESS. Please wait." You can
- INCLUDE MACRO variables as part of the message for further
- convenience, such as :
-
- msg="Department "+&deptID+" has "+str(records,4,0)+" entries."
- DO PRTMSG23
-
- getfld23.prg -- This is one of my favorite routines. If I want a user to input
- data that is not part of the input screen nor part of the data
- file (say, it is part of an overall calculation or series of
- calculations), and I DON'T WANT TO LOSE ANY OF THE SCREEN DATA
- DISPLAYED, I can avoid drafting the code that redraws the
- screen and data by getting the information at the bottom of
- the screen. It is attractive, gets the immediate and proper
- attention of the user, and allows the coder to focus on getting
- data! An example:
-
- Mcost=0.00 : * the target data variable for user input.
- FEELD=space(6) : * the length of the variable, pict "9999.99"
- kol=0
- msg="ENTER the total cost of the Advertisement :"
- do getfld23
- do while Mcost<=0 .or. Mcost>7290.05
- Mcost=0
- @ 23,kol get Mcost picture "9999.99" : * length=6 spaces
- enddo
-
- prevmo.prg -- A routine that calculates what the actual previous calendar
- month is, REGARDLESS of what the current system date is.
-
- nextmo.prg -- A routine that calculates what the actual NEXT calendar month
- is, regardless of what the current system date is.
-
- passwerd.prg -- A fully functional password program. It is misspelled on pur-
- pose. Many public domain and commercially available dbase rou-
- tines use "PASSWORD.PRG" as its namesake. I don't want to
- accidentally overwrite any files you may have by that name when
- you copy this file! You must first create a file from
- within dbase III, called "SECURITY.DBF". It consists of one
- field, of character, and 12 characters in length. The field
- name should be called "ENTEROK". Then create a temporary
- ".PRG" file which contains ONLY the block of code from within
- "PASSWERD.PRG" that starts from the comment: "PASSWORD ADDITION
- ROUTINE starts here" to the comment: "PASSWORD ADDITION ROUTINE
- ends here". Run that as a separate program and the first
- record in the file will be the MASTER PASSWORD. ONLY the
- MASTER PASSWORD will allow other passwords to be logged into
- the SECURITY file. Just for fun, do a DISPLAY ALL of the
- SECURITY.dbf file records from the dbase III interpreter.
-
- lincount.prg -- is a routine that will keep a running count of all information
- written to the screen or to the printer, and how many lines you
- have left before the screen must be refreshed (BOXCLEAR), or
- a page EJECT invoked. It also allows 6 headers to be used as
- part of the top of your page, whether you are using to screen
- or printer.
-
- displrut.prg -- is a text file only. SEE DB3STOCK.TXT below.
-
-
- You will notice that some of these routines require that several variables
- need to be initialized BEFORE entering the routine. First, you might ask, "Why
- not use the dbaseIII convention, DO <subroutine> WITH <parameters>?" Secondly,
- you might ask, "What if my application is currently using the same named
- variables as the routines above?"
-
- In answer to the first question,
- I avoid DO WITH constructs because you have to use a TWO SETS of variables to
- successfully complete a DO WITH procedure -- one set to pass variables TO
- the routine, and one set to RECEIVE the passed variables. You could use the
- same variables as parameters, but dbase III has a myriad of memory variable
- handling functions (RESTORE from <filename>.MEM [ADDITIVE], CLEAR [ALL | LIKE
- <skeleton>, PUBLIC,PRIVATE,HIDDEN) that can, in conjunction with each other,
- often create memory management conflicts, even amongst the most organized of
- us. The dbase III Advanced Programmer's Guide (Castro, et. al.) strongly
- advises against identical variable/parameter passing. Translation: it's
- probably going to have bugs if you do. I always initialize variable(s) before
- entering routines because : (1) it is ALWAYS easier to write (2) you have
- fewer variable names in the long run to trace/debug for any given routine(s),
- and (3) - whether the variables are PUBLIC or PRIVATE, initializing them
- BEFORE invoking the routine makes them accessible to that called routine.
- Frankly, I've hated PUBLIC/PRIVATE nonsense. Initializing variables just
- before use is almost a sure way of emulating a "globalness" of your variable
- condition -- something I always enjoyed about dbase II and BASIC.
-
- In answer to the second question, I find that most applications programmers
- have a unique style to their memory variable name assignments. In all the
- maintenance program work I have done, I have not yet found ANY of my variable
- names in my routines to be in conflict with the assignments of the code I had
- to maintain. It might just be luck, but I rather doubt it. If you do have
- problems with variable names, you will have to rename yours or rename mine.
- As a matter of PRAGMATISM, (not ego), you might find it more time saving to
- rename YOURS, for two reasons: (1) You know where all the locations of
- your variables are, what they do, what they stand for, and what effect they
- have on every aspect of all the other modules in your application. It's your
- own code, so who else but you would know what affect variable naming
- procedures and initialization assignments would do to those modules?
- (2) Many of the subroutines above CALL EACH OTHER, "PASSWERD.PRG" in
- particular. You know the domino theory. And it certainly applies to
- variables in programming -- one module SNAFU's, and they probably all will
- have a large or small SNAFU in them somewhere.
-
- A final word about these routines. They take great care in forecasting the
- environment that needs to exist after they have been executed. For example,
- the routines that contain "??????23.PRG" initialize the set color commands,
- clear from line 23 any existing "MSG", and print the new one. Where key
- input is required, line 23 is CLEARED, so you don't have to remember to code
- that yourself. Where it is not required, of course, the "MSG" remains on
- screen, as the routine assumes the condition exhibited by the message remains
- in effect until another message (or screen!) indicates otherwise.
-
-
-
- DB3STOCK.OBJ -- an 8088-relocatable object code file, which can be linked
- with PLINK86, in the formation of final dbaseIII compiled
- ".EXE" programs. It is a Clipper (TM) compiled file of all
- the source programs (subroutines) above. If you write in
- dbaseIII and compile your applications using the Clipper
- compiler, you do not need to recompile these programs. Merely
- include this file as the LAST object code file to link with
- your other object code files, and they will be available to
- your applications program. The only stipulation is, of
- course, that when compiling your other programs that make up
- the total of your application is that you do NOT use the
- convention,
-
- "clipper <filename>"
-
- where <filename> is the main calling program that calls all
- other programs. Rather, use the convention:
-
- "clipper @<filelist>.CLP"
-
- where <filelist>.CLP is an ascii text file listing of ALL the
- programs you need compiled for your application. Don't forget,
- in using this latter convention, the first filename in the
- <filelist> should be <filename>, i.e., the main calling
- program that calls all other programs. DO NOT list any of
- the subroutines above in your <filelist>, as the DB3STOCK.OBJ
- file already contains them.
-
- DB3STOCK.TXT -- An ascii text file, which contains the following subroutines:
-
- bigboxdt.prg
- boxclear.prg
- smallbox.prg
- lineboxm.prg
- slinboxm.prg
- slinboxt.prg
- slinboxb.prg
- dlinboxm.prg
- dlinboxt.prg
- dlinboxb.prg
- linprm23.prg
- linmsg23.prg
- prtmsg23.prg
- getfld23.prg
- prevmo.prg
- nextmo.prg
- passwerd.prg
- lincount.prg
- * displrut.prg
-
- DISPLRUT.PRG is an educational text file, not a dbaseIII
- executable PRG file per se. It is invaluable as a routine
- to write to EITHER print or to screen, and is easily custom-
- izable.
- Again, these files are identical to the prg's described above
- but they are collected into one file for archival purposes.
-
-
- DB3STOCK.SKL -- An ascii text file, which contains the following procedures:
-
- procedure bigboxdt
- procedure boxclear
- procedure smallbox
- procedure lineboxm
- procedure slinboxm
- procedure slinboxt
- procedure slinboxb
- procedure dlinboxm
- procedure dlinboxt
- procedure dlinboxb
- procedure linprm23
- procedure linmsg23
- procedure prtmsg23
- procedure getfld23
- procedure prevmo
- procedure nextmo
- procedure passwerd
-
- These files are IDENTICAL to the PRG's as listed above, but
- they have been put into a procedure file. You can then do
- one of two things with this file:
- 1). Merge it directly at the end of any of your current
- dbaseIII procedure file and you can now make any calls
- to the above subroutines directly.
- 2). Do you use the new GENIFER (TM) program from Bytel Corporation?
- (It is an OUTSTANDING APPLICATIONS GENERATOR -- the best I
- have EVER seen. It is worth every penny of the $295.00 I
- paid for it. I spent about six hours giving GENIFER the
- parameters for the code I needed generated. GENIFER took
- about 30 minutes generating the code. I then charged the
- client 800 bucks. The client loved it, and so did I.)
- Using a simple text editor, I have merged DB3STOCK.SKL to
- the very end of the three GENIFER ".SKL" files that come
- with GENIFER. The last line of every GENIFER ".SKL" file
- contains the line,
- "wd* EOF {{program}}"
- where GENIFER replaces "{{program}}" with your program
- name when the program is generated. JUST ABOVE THIS LINE
- use the MERGE function (or block insert or block merge
- or file merge or whatever your word processor/editor
- calls it) of "DB3STOCK.SKL" INTO each of these GENIFER
- ".SKL" files. Every program now generated with GENIFER
- will now also generate these subroutines for your program
- AUTOMATICALLY.
-
-
- Hope these routines are of some benefit. Give me some feedback on how you
- might find ways to improve on them!
-
-
-
- Scott Brock
- The Outer Bridge
- 1600 San Fernando Blvd. Suite 235
- Burbank, CA. 91504
- 1-818-848-8955