The Professor Answers Your Questions...
Have a question on QB programming? Just ask...and be sure that he knows the
answer.
A Message from The Professor
Life will be boring if you don't have anything to do. For example what would
happen if there weren't so many questions for The Professor to answer? Surely
he would go and start writing more code! It's a programmer's way. So go and
start the work (of course after reading The Professor's column!). If there are
any problems, as there are always, just send your question to the Professor to
prof@sepent.com.
Dear Professor,
Would you please write a program for me which enabes the
computer to tell the user whether the given word is a
palindrome (e.g. dad, mum, hannah) or not, using QBasic. Please
help me. I have been working on this problem for a long time.
Yours,
Felix Malawi
It is very simple. Take a look at this code:
DIM wrd As STRING
DIM wrd2 As STRING
DIM i As INTEGER
INPUT "Enter a word: ", wrd
wrd = LCASE$(wrd)
FOR i = LEN(wrd) TO 1 STEP -1
wrd2 = wrd2 + MID$(wrd, i, 1)
NEXT
IF wrd2 = wrd THEN
Print "The word is a palindrome."
ELSE
Print "The word is not a palindrome."
END IF
The Professor
Dear Professor,
When utilizing a PRINT USING format statement (for example,
print using "###.##"; 1115.55), when I run the program, I still
get output, but preceded by %. Since I am a new student of
QBasic, I wanted to know what this means.
Sincerely,
Lee Floyd
Dear Lee,
A percent mark being printed at the left of the number shows
you that the number is larger than the field. It is clear that
1115.55 does not fit in ###.## because it has one digit more
than the field. In this instance you should change the format
string to ####.## to fix the problem. You should always
remember that the help system of QB is your primary resource of
syntax of the statements. You could easily and quickly find the
answer to this question using the help in a few minutes while
you got the answer from The Professor in a few days!
The Professor
Dear Professor,
I have downloaded VBDOS to a new folder. I have QB 4.5 and
some programs I've written in another folder. How do I get
VBDOS to "recognize" the QB 4.5 programs? I haven't been able
to "copy and paste" the code from one to the other with any
success, either. I can do it one line at a time (with many
mouse clicks per line) but there must be a better way.
I am completely unfamiliar with libraries. This sounds like
what I really need- a place to store subroutines, accessible to
all programs. Is this assumption correct? How do I create and
use libraries?
Can you recommend a site where information such as this is
available? Or should I pester you every couple days? :-)
Truly ignorant and quite thankful (not for the ignorance,
but for your help).
Dale Ludwig
Dear Dale,
To enable VBDOS to open your old programs, you should save
the files in text format. To do this, open the files in QB 4.5
and choose "Save As..." from "File" menu. Under "Format" frame,
select "Text" option and save the file. Now you can open the
file in VBDOS.
Your guess about how the libraries work is quite right. The
libraries are a way of reusing code in your programs, or
sharing them with others without distributing your source code.
You can put the needed subroutines in a module or a project
with multiple modules and open them in QB, then choose
"Make Library..." from "Run" menu. Two files will be created.
A file with ".LIB" extension which is the library file that
will be linked to your program when making the EXE, and the
other one a file with ".QLB" extension which is called a quick
library. Quick libraries can be loaded in QB or VBDOS
environment using the /L command-line option. When you want to
debug and run your programs that use a library you should load
the quick library first. Remember that quick libraries have
different format for various versions of QB and VBDOS.
The Professor cannot recommend you a single site to find
information about QB. There are a lot of QB sites, especially
those that have a Learning or Tutorials section. Search the QB
sites that you know. Almost all QB related sites have links to
other sites that can guide you to find the information you
need. Sepent also has a QB Knowledge Base that may help you in
some areas of programming. The Knowledge Base is located
at http://www.sepent.com/prog/basic/knbase/. Of course the
knowledge base is now small and does not cover many aspects of
programming in QB, but Sepent is going to extend the knowledge
base in near future.
The Professor
Dear Professor,
I've suddenly developed a problem in my QB4.5 program. All
was well. I made some minor changes to the display --changed
some PRINT statements. I added some more data. Everything still
worked until I exited and attempted to restart the program. It
wouldn't run. It says, "Binding" in the very bottom left corner
and freezes. If I compile the program, it still works.
How can I avoid "binding" so I can run the program and edit
it at the same time?
Thank you,
Dale Ludwig
Dear Dale,
The problem is probably the size of your program. If your
program size has exceeded the largest possible size, then such
problems may occur. You can do several things to fix the
problem. You can move to QB 7.1 or VBDOS that can manage larger
files. This is a quick way, although sometimes some changes to
the code are required. The better way, of course, is reducing
the size of your program. For example, if you have a lot of
DATA statements that make the code very large, you can put the
data in an external file and load them dynamically in run-time.
Also, you can split your code into several modules and work on
them, then compile each module to a separate .OBJ file and link
them together.
The Professor
Dear Professor,
I'm using the QBASIC.EXE interpreter. When CHAINing between
programs, can I make COMMON variables also CONSTant?
Richard Emery
Dear Richard,
There are three ways The Professor can suggest you, although
none of them is a perfect solution for you. One way is to use
common variables instead of constants. This is not in fact
recommended. The better way which needs more work is putting
CONST statements in all used modules. The last way is upgrading
to a higher version of QB. Using higher versions, you can put
all general constants in an include module (a .bi file) and
including it in all the modules with $INCLUDE meta command.
Also you can use a multiple-module program in these versions
which is usually better than using CHAIN command (For more
information on modular programming in QB you can visit Sepent's
QB Knowledge Base located at http://www.sepent.com/prog/basic/knbase/).
The Professor
Dear Professor,
Is there a way to give a student only 3 seconds to type an
answer?
Thanks, Alison.
Dear Alison,
The Professor can suggest you two ways, one easy to be done
and the other not that easy.
You can simply use an INPUT statement and then calculate the
time it took the user to answer the question and if it is less
than 3 seconds, the program can give the user the appropriate
score. This can be done like this:
DIM StartTime AS SINGLE
DIM EndTime AS SINGLE
DIM ans AS STRING
CLS
PRINT "You have three seconds to answer the following question."
PRINT
StartTime = TIMER
INPUT "What's your name?! ", ans
EndTime = TIMER
IF EndTime - StartTime > 3 THEN
PRINT "Oops! It took you too long."
PRINT "You don't get any score."
ELSE
'Of course, you should check the answer, but here
'it is not necessary! (How can you check the name?)
PRINT "Excellent! You did it!"
END IF
END
The second way, needs more work. You should implement an INPUT
statement using INKEY$ function. It does not seem very good,
but it's the best choice if your program is a high quality one.
The Professor can guide you to do it. Here is a simple sample:
DECLARE SUB CustomInput (var AS STRING)
CONST True = -1
DIM SHARED TimedOut AS INTEGER
ON TIMER(3) GOSUB TimeHandler
TIMER ON
DIM ans AS STRING
CLS
PRINT "You have three seconds to answer the following question."
PRINT
PRINT "What's your name?! ";
CustomInput ans
TIMER OFF
PRINT
IF TimedOut THEN
PRINT "Oops! It took you too long."
PRINT "You don't get any score."
ELSE
'Of course, you should check the answer, but here
'it is not necessary! (How can you check the name?)
PRINT "Excellent! You did it!"
END IF
END
TimeHandler:
BEEP
TimedOut = True
RETURN
SUB CustomInput (var AS STRING)
CONST ScreenWidth = 80
DIM startrow AS INTEGER
DIM startcol AS INTEGER
DIM curpos AS INTEGER
DIM ch AS STRING
startrow = CSRLIN
startcol = POS(0)
curpos = startcol
LOCATE startrow, startcol, 1
IF startcol = ScreenWidth THEN
'Not enoguh space.
ERROR 200
ELSE
DO
IF TimedOut THEN EXIT SUB
ch = INKEY$
IF LEN(ch) = 1 THEN
SELECT CASE ASC(ch)
CASE 97 TO 122, 65 TO 90, 48 TO 57, 32
'You can add other allowed characters to
'this CASE statement.
IF curpos < 80 THEN
LOCATE startrow, curpos, 1
PRINT ch;
var = var + ch
curpos = curpos + 1
END IF
CASE 8
IF curpos > startcol THEN
curpos = curpos - 1
var = LEFT$(var, LEN(var) - 1)
LOCATE startrow, curpos
PRINT SPACE$(1);
LOCATE startrow, curpos, 1
END IF
CASE 13
PRINT
EXIT SUB
END SELECT
END IF
LOOP
END IF
END SUB
This code, obviously, does not have many features. But you can
add other features to it easily!
Uh, what a long (and pleasant) answer it was! Have fun!
The Professor
Dear Professor,
My program (attached to this email) gives me an "OUT OF DATA"
error message. Could you please try it to see what I have done?
I would appreciate it. Thanks.
Jesse Hobby
Attached Code(Finalpro.BAS)
---------------------------
100 REM FINAL PROJECT Jesse Hobby 12-8-02
110 REM this program will ask the user to enter an instrument name and then
120 REM it will display the instrument name, classification, key of
125 REM instrument, year of invention, and inventor of the instrument.
130 variables:
140 REM uname$ instrument name chosen by user
150 REM iname$ instrument name
160 REM class$ instrument classification
170 REM counter counts number of times there was no match
180 REM invn$ inventor of instrument
190 REM year$ year instrument was invented
200 REM key$ key of instrument
205
210 PRINT "Hello, what is the instrument name you would like";
215 PRINT "to receive information; about; "; ""
220 INPUT uname$
225 PRINT "Name__________Classification____Inventor______Year____Key"
230 counter = 0
240 DO
250 READ iname$, class$, invn$, year$, key$
260 IF iname$ = "end" THEN EXIT DO
270 IF uname$ = iname$ THEN
280 PRINT iname$, class$, invn$, year$, key$
290 counter = counter + 1
300 END IF
310 LOOP
320 IF counter = 0 THEN
330 PRINT "I'm sorry but there is no information available";
335 PRINT " on that instrument.; "; ""
340 END IF
350 PRINT "Thank you for using this program."
360 PRINT "This program was designed by Jesse Hobby."
370 PRINT "All musical information received from my brilliant";
375 PRINT " sweet heart Cambria; Quinn.; "; ""
(some PRINT statements removed!)
550 PRINT "Copywright December 8, 2002 - a J & C Creation"
560
570 DATA tuba, brass, Jean Aste', 1817, F
580 DATA clarinet, woodwind, 1700, B flat
590 DATA flute, woodwind, Theobald Boehm, 1794, C
600 DATA piano, percussion, Bartolomeo Cristofori, 1709, C
610 DATA saxophone, woodwind, Adolphe Sax, 1840, F
620 DATA violin, string, Andrea Amati, 1510, C
630 DATA guitar, string, Spanish Peasants, 1100, C
640 DATA end, end, end, 0, O
650 END
---------------------------
Dear Jesse,
The problem with your program is only a comma! Take a look at
line 580. You should put a comma between "B" and "Flat" (I
think the data is incorrect, but this comma will correct the
syntax of the program. You can then correct the data). Your
program will work, if you add the comma. Remmember that data
elements should always be separated by commas.
The Professor
P.S.: The Professor should explain somthing here. This error is
in fact caused by a logical mistake, that is not placing
the inventor's name in its place at line 580. So it
can be said that this is a matter of missing a data
element, not missing a comma! (You see he is a professor,
not a musician!!)
Dear Professor,
Is it possible to use OPEN COM statement without ON COM
statement in QB?
Also, my old program uses ON COM statement in each module.
When I converted this program to QB, an error message occurres
telling me that ON COM statement cannot be used in SUB
procedures. What's the problem? Thanks.
Lukman NulHakim
Dear Lukman,
Of course it is possible to use OPEN COM statement without
using ON COM. But about your second question I should tell you
that all QBASIC event-trapping statements (ON ... statements)
-except ON LOCAL ERROR- are module level and cannot be set up
in a SUB or FUNCTION.
The Professor
Dear Professor,
I’m new in QBASIC programming, but my Boss wants me to convert
an NS88Basic program to QBASIC. Some code of the program I'm
making interface with port (PLC system), and I don’t know about
port programming in QBASIC. So can you give a little example
about it, please? Thanks.
Lukman NulHakim
Dear Lukman,
The Professor is glad to hear from you. But you haven't
included much information on what exactly you want to do. So I
will give you some general instructions. First of all, you
should know that all versions of QB only support accessing
serial communications ports(COM1 & COM2) directly. You may open
a communications channel using OPEN COM statement. The port can
be opened in three file-access modes: INPUT, OUTPUT and RANDOM.
In each mode, you can use ordinary file-access commands to read
and/or write from/in the port. You can also use ON COM
statement to trap communication events. Refer to the help
system of your version of QB for detailed information about
these statements as well as examples on their usage.
The Professor
Dear Professor,
I have a problem with a program I made in QBASIC (The code is
attached to the email). I use SCREEN 13 to read the DATA in a
FOR...NEXT loop. It writes the word "sponge". The problem is
that when I use a GOTO command to run the drawing code again,
It doesn't read the data. What's wrong?
Steve Wagner
Attached code (Sponge.BAS):
--------------------------------
SCREEN 13
FOR y = 1 TO 5
FOR x = 1 TO 28
READ clr
IF clr = 1 THEN LINE (x * 5, y * 5)-(x * 5 + 5, y * 5 + 5), 14, BF
IF clr = 0 THEN LINE (x * 5, y * 5)-(x * 5 + 5, y * 5 + 5), 1, BF
NEXT
NEXT
DATA 1,1,1,0,1,1,1,0,0,1,1,1,1,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1
DATA 1,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,0,0,1,0,0
DATA 1,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,1,1
DATA 0,0,1,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,1,0,1,0,0,1,0,1,0,0
DATA 1,1,1,0,1,0,0,0,0,1,1,1,1,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1
startscreen:
PRINT ""
PRINT ""
PRINT ""
PRINT ""
PRINT ""
PRINT "This is Spongebob Trivia!"
PRINT ""
PRINT "Please press H for help"
PRINT "or S to start the game"
INPUT sorh$
IF sorh$ = "h" THEN
GOTO help
ELSEIF sorh$ = "s" THEN
GOTO difficulty
ELSE
PRINT "dummy!"
GOTO startscreen
END IF
help:
PRINT ""
PRINT "Help!"
PRINT "There are 2 different skill levels in"
PRINT "this trivia game:"
PRINT "easy: All multiple choice."
PRINT "hard: All short answer"
PRINT "After answering a question you will"
PRINT "be told either right or wrong,"
PRINT " and at the end of the game, your"
PRINT "score will be given. Have fun!"
PRINT ""
INPUT "Type r to return to the title screen"; helpr$
IF helpr$ = "r" THEN
CLS
GOTO startscreen
ELSE
CLS
GOTO startscreen
END IF
difficulty:
PRINT ""
INPUT "Easy or Hard?"; diff$
IF diff$ = "easy" THEN
PRINT ""
GOTO easystart
ELSEIF diff$ = "hard" THEN
PRINT ""
GOTO hardstart
ELSE
PRINT ""
PRINT "dummy"
GOTO difficulty
END IF
easystart:
hardstart:
--------------------------
Dear Steve,
The answer to your problem is really easy(If I had realized the
problem correctly!). You should put the "startscreen" label at
the begining of your program after SCREEN 13 statement. Like
this:
SCREEN 13
startscreen:
Then you should put a RESTORE statement after it. This restores
the DATA reading order to the first DATA statement and you can
read the DATA correctly. Without it, you would get an
"OUT OF DATA" error message. I hope this had helped you.
The Professor
Dear Professor,
I have written a program in QuickBASIC 7.1 (BASIC PDS) and I
want user not be able to interrupt execution of the executable
file by pressing Ctrl-Break. Can you help?
Sincerely Yours,
Sepent
Your problem is really very easy to solve, young Sepent. Just
uncheck "Run-Time Error Checking" option in "Make EXE File"
dialog box. Or if you use command-line, don't include /D
command line option. Then Ctrl-Break will not work!