By Zap <RuneMoennike@hotmail.com>
So... You want to know how to do a textviewer in Qb...
Hu? You don't? Hmm... What if I tell you that I'll learn how to do a formatted text viewer in QB, and that I promise It'll be a series?
Aahh... I knew you would say yes then! So what are we waiting for, let's get started!
A formatted text viewer can be used in many places: As a help
system for your game or program, as a stand-alone one, and... and...
eh... a formatted text-viewer. Yes...
Oh whatever, I'm sure you'll come up with something.
... I will teach how to do a simple text scroller, with auto-linebreaking of course, and maybe some base formatting if I feel like I want to show you. ;-)
... You will need something to view: Let's make a .txt file and call it MyBrain.txt, something like this:
this file is called MyBrain.txt. I've wanted to call it something longer, like TheContentsOfMyBrain.Text. But, when Bill Gate$ did DOS (or stole it, to be more presicely) he didn't have money for a big hard-drive, there- fore he allowed the filenames only to be 77 Bytes long. But I'll survive, and here is the contents of my brain: --------------------------------------- qMqyw erretlyeugiioopna s?d fIgth jiksl zWxIcRvAbJnOmDqAw,e rmtyy uoiwonp aQsBdAfSgIhCj kilnzvxecnvtbendm qrweelritgyeuoino pwaistdhf gfhojukrl zgxocdvsb:n mWqiwledrCtayrudi o-p aGsoddf gohfj kkliznxdcnvebsnsm qRwaedritoyHuainodpsa s-d fGgohdj kolfz xtcuvtbonrmiqawlesr tJyouridoapna s-d fGgohdj kolfz xwcevbbsnimtqewsr tDyaurikoDparsedafdg h-j kGlozdx covfb ncmoqdwienrgt --------------------------------------- Can you break the code of the above, and read the real text? try, cause indeed there is one. Here's a tip: Each line is encoded alone but by the same encoding formula, and the encoding is so simple that you will laugh, when you guess it...
Mind you that none of the lines exceeds 40 characters, 'cause our first text-viewer will not support linebreaking.
Now, cut and paste it into notepad, and save it in the same dir as you plan to be coding you text-viewer. From now on, I will be referring to that dir as the viewer dir.
... were we will be using DQB for the ease: We don't need first to make our own font, graphics, and page-flipping routines! YES!
Make sure that you know have a copy of the DirectQb lib, compiled with all routines (for MY ease), in your viewer dir. The viewer dir should now contain the following files: MyBrain.txt, DQB.Lib (if you'd like to compile), DQB.Qlb, and DirectQB.Bi.
Let's get started. First, the DECLARE lines:
'$INCLUDE: 'directqb.bi' DECLARE SUB DrawScreen (update%) DECLARE SUB EndProgram () DECLARE SUB Init () DECLARE SUB LoadFile (File$)
The first line includes the DirectQB include file, with the DECLARE statements for the lib. The next, DrawScreen, will be called to update the screen (to Layer 1, mind you), its argument, update%, tells the sub to, or not to, copy Layer 1 to the real screen. The others should be self-explaining, if you don't think so you will understand the subs later on.
And on we go:
DIM SHARED File(1 TO 2048) AS STRING DIM SHARED TopLine AS INTEGER DIM SHARED NumOfLines AS INTEGER
this was the DIM statements, if you haven't figured out...
File(1 to 2048) is the STRING array were we will store the file at run-time.
TopLine tells us what index in the File array that is the topmost one
on the screen. Will be needed to know were to start printing, in the
sub DrawScreen.
NumOfLines tells us how many lines there is in the file, so we can find were to stop the user from scrolling further.
Ready for more?
Init LoadFile "MyBrain.txt" DrawScreen 1
this calls the subs, which will be explained later.
Now, its time for our main loop:
do
It wasn't that tough, hu? he, he... Sorry...
Our key press detection:
if DQBkey(KEYUP) THEN if TopLine > 1 THEN TopLine = TopLine - 1: change = 1 ELSEIF DQBkey(KEYDOWN) THEN if TopLine < NumOfLines - 17 THEN TopLine = TopLine + 1: change = 1 ELSEIF DQBkey(73) THEN if TopLine > 15 THEN TopLine = TopLine - 15: change = 1 ELSEIF DQBkey(81) THEN if TopLine < NumOfLines - 17 - 15 THEN TopLine = TopLine + 15: change = 1 ELSEIF DQBkey(KEYESC) THEN quit = 1 END if
I know it's not the best way, but it'll work fine here.
Key number 73 and 81 is PgUp and PgDown, respectively.
The quit var is set if we want to quit.
About
the change var: if its false, we don't need to update the screen coz
nothing has changed. If it is true, then we'll need to update the
screen:
if change = 1 THEN change = 0 DrawScreen 1 END if
this is pretty simple: if the change var is set, we reset it and update the screen.
Lastly in our main code, we end the main loop and end the program by calling EndProgram:
LOOP UNTIL quit = 1 EndProgram
Of cause the program won't run yet, as we're left to do the subs.
Hu? You want the all of the main code listed now? EASY! You'll get that later...
... Are coming now. In alphabetic listing:
SUB DrawScreen (update%) DQBboxf 1, 0, 0, 319, 10, 1 DQBboxf 1, 0, 11, 319, 188, 7 DQBboxf 1, 0, 189, 319, 199, 8 DQBprint 1, "QFT viewer by Zap/QGZ", CENTERED, 1, 15 DQBprint 1, "Use arrow keys + PgUp & PgDown to scroll", 1, 190, 7 x% = 11 for a = TopLine TO TopLine + 17 DQBprint 1, File(a), 1, x%, 15 x% = x% + 10 NEXT if update THEN DQBcopyLayer 1, VIDEO END SUB
Here's an explanation for the DrawScreen sub:
First three lines draws the background, next we print the title (put anything you like there), and then some helpful text at the bottom.
Then we set the start pos for the text (eleven pixels from the top, here), and then print seventeen lines of text.
Lastly, but not less, we update the screen, if we're told to do so, mind you.
We continue:
SUB EndProgram DQBclose END END SUB
do I really have to explain this mum? *SIGH*
First we call DQBClose, which closes DQB and removes the keyboard handler.
Next we... Oh forget it! You know what that does, right?!
And we go on:
SUB Init if DQBinit(1, 0, 0) THEN PRINT "Internal Error, aborting program" DQBinitVGA DQBinstallKeyboard TopLine = 1 END SUB
this sub Installs DQB, VGA screen, and DQB Keyboard handler. It
also sets TopLine to one, because the first line is number one...
My fingers are starting to hurt now. Hmm. Next and last sub (so far, anyways):
SUB LoadFile (File$) OPEN File$ for INPUT AS #1 do linenumber% = linenumber% + 1 LINE INPUT #1, File(linenumber%) LOOP UNTIL EOF(1) CLOSE NumOfLines = linenumber% END SUB
this loads the file, and sets the NumOfLines var.
... We're done! (With the very simple version...)
Here's the full code (Both the main, as I promised, and a bonus: the subs!...)
'$INCLUDE: 'directqb.bi' DECLARE SUB DrawScreen (update%) DECLARE SUB EndProgram () DECLARE SUB Init () DECLARE SUB LoadFile (File$) DIM SHARED File(1 TO 2048) AS STRING DIM SHARED TopLine AS INTEGER DIM SHARED NumOfLines AS INTEGER Init LoadFile "crap.txt" DrawScreen 1 do if DQBkey(KEYUP) THEN if TopLine > 1 THEN TopLine = TopLine - 1: change = 1 ELSEIF DQBkey(KEYDOWN) THEN if TopLine < NumOfLines - 17 THEN TopLine = TopLine + 1: change = 1 ELSEIF DQBkey(KEYESC) THEN quit = 1 ELSEIF DQBkey(73) THEN if TopLine > 15 THEN TopLine = TopLine - 15: change = 1 ELSEIF DQBkey(81) THEN if TopLine < NumOfLines - 17 - 15 THEN TopLine = TopLine + 15: change = 1 END if if change = 1 THEN change = 0 DrawScreen 1 END if LOOP UNTIL quit = 1 EndProgram SUB DrawScreen (update%) DQBboxf 1, 0, 0, 319, 10, 1 DQBboxf 1, 0, 11, 319, 188, 7 DQBboxf 1, 0, 189, 319, 199, 8 DQBprint 1, "QFT viewer by Zap/QGZ", CENTERED, 1, 15 DQBprint 1, "Use arrow keys + PgUp & PgDown to scroll", 1, 190, 7 x% = 11 for a = TopLine TO TopLine + 17 DQBprint 1, File(a), 1, x%, 15 x% = x% + 10 NEXT if update THEN DQBcopyLayer 1, VIDEO END SUB SUB EndProgram DQBclose END END SUB SUB Init if DQBinit(1, 0, 0) THEN PRINT "Internal Error, aborting program" DQBinitVGA DQBinstallKeyboard TopLine = 1 END SUB SUB LoadFile (File$) OPEN File$ for INPUT AS #1 do linenumber% = linenumber% + 1 LINE INPUT #1, File(linenumber%) LOOP UNTIL EOF(1) CLOSE NumOfLines = linenumber% END sub
Copy & Paste this into NotePad, and save it as QFTView.bas in your Viewer dir .
Then: RUN IT!
If it works, which it will, it should look like this:
Try scroll up and down with the arrow keys. If you're running on a computer faster then a 386, 16 MHz, you should notice that it is scrolling quite fast. This can be corrected:
Add this line at the top (after the DECLARE's, before the main loop):
CONST ScrollDelay=3
... and this line in the IF block, that updates the screen:
IF ScrollDelay => 1 then DQBWait ScrollDelay
Run it, and change the ScrollDelay to anything that fits on you PC.
The reason why we have to check if the ScrollDelay var is greater than or equal to one, is because if you call DQBWait, which waits for vertical retrace, with eg. a value of 0.3 it'll wait for vertical retrace under 1 times, which is impossible. If you anyway do this, you'll end up with a locked computer.
He'll rather choose to download another text viewer, than have to download QB, change the vars to fit etc.
Therefore, we'll compile!
Hey! STOP! Don't compile yet. How in the nine hells should the user then open a file? (except the crap one we did before. Oh! BTW have you decoded it? No? SHAME ONE YOU!)
The solve to our problem, is to use the built-in COMMAND$ variable, which returns the parameters shipped with the command-line.
Change this:
Init LoadFile "crap.txt"
To this:
DIM CurFile AS STRING, ScrollDelay AS INTEGER dum$ = COMMAND$ IsThere% = INSTR(dum$, "-") IF IsThere% THEN CurFile = LEFT$(dum$, IsThere%) arg$ = MID$(dum$, IsThere% + 1, 1) checkarg: SELECT CASE LCASE$(arg$) CASE "?" CLS PRINT "USAGE:" PRINT "QFTView -? | FILENAME.TXT [-dSCROLLDELAY#]" PRINT PRINT "e.g.:" PRINT "QFTView somefile.txt -d15#" PRINT "Will display the file somefile.txt and set the scrolling delay to 15" END CASE "d" argend% = INSTR(IsThere%, dum$, "#") arglen% = argend% - IsThere% ScrollDelay = VAL(MID$(dum$, IsThere% + 2, arglen%)) END SELECT ELSE CurFile = dum$ ScrollDelay = 0 END IF LoadFile CurFile Init
I don't like to explain all this, so if you don't understand it, accept it. I have some small remarks to do, though: The CheckArg: line is for future usage. Make sure that the LoadFile call is BEFORE the Init call, if it's not, and the user gives a wrong filename, he will end up with a locked-up computer (which he will probably throw out the window, and charge you...).
Try compile it, now. If it doesn't work, YOU have probably done something wrong. In case, here's the code:
'$INCLUDE: 'directqb.bi' DECLARE SUB DrawScreen (update%) DECLARE SUB EndProgram () DECLARE SUB Init () DECLARE SUB LoadFile (File$) DIM SHARED File(1 TO 2048) AS STRING DIM SHARED TopLine AS INTEGER DIM SHARED NumOfLines AS INTEGER DIM CurFile AS STRING, ScrollDelay AS INTEGER dum$ = COMMAND$ IsThere% = INSTR(dum$, "-") IF IsThere% THEN CurFile = LEFT$(dum$, IsThere%) arg$ = MID$(dum$, IsThere% + 1, 1) checkarg: SELECT CASE LCASE$(arg$) CASE "?" CLS PRINT "USAGE:" PRINT "QFTView -? | FILENAME.TXT [-dSCROLLDELAY#]" PRINT PRINT "e.g.:" PRINT "QFTView somefile.txt -d15#" PRINT "Will display the file somefile.txt and set the scrolling delay to 15" END CASE "d" argend% = INSTR(IsThere%, dum$, "#") arglen% = argend% - IsThere% ScrollDelay = VAL(MID$(dum$, IsThere% + 2, arglen%)) END SELECT ELSE CurFile = dum$ ScrollDelay = 0 END IF LoadFile CurFile Init DrawScreen 1 DO IF DQBkey(KEYUP) THEN IF TopLine > 1 THEN TopLine = TopLine - 1: change = 1 ELSEIF DQBkey(KEYDOWN) THEN IF TopLine < NumOfLines - 17 THEN TopLine = TopLine + 1: change = 1 ELSEIF DQBkey(KEYESC) THEN quit = 1 ELSEIF DQBkey(73) THEN IF TopLine > 15 THEN TopLine = TopLine - 15: change = 1 ELSEIF DQBkey(81) THEN IF TopLine < NumOfLines - 17 - 15 THEN TopLine = TopLine + 15: change = 1 END IF IF change = 1 THEN change = 0 DrawScreen 1 '/* Scrolling delay */ IF ScrollDelay >= 1 THEN DQBwait ScrollDelay END IF LOOP UNTIL quit = 1 EndProgram REM $DYNAMIC SUB DrawScreen (update%) DQBboxf 1, 0, 0, 319, 10, 1 DQBboxf 1, 0, 11, 319, 188, 7 DQBboxf 1, 0, 189, 319, 199, 8 DQBprint 1, "QFT viewer by Zap/QGZ", CENTERED, 1, 15 DQBprint 1, "Use arrow keys + PgUp & PgDown to scroll", 1, 190, 7 x% = 11 FOR a = TopLine TO TopLine + 17 DQBprint 1, File(a), 1, x%, 15 x% = x% + 10 NEXT IF update THEN DQBcopyLayer 1, VIDEO END SUB SUB EndProgram DQBclose END END SUB SUB Init IF DQBinit(1, 0, 0) THEN PRINT "Internal Error, aborting program" DQBinitVGA DQBinstallKeyboard TopLine = 1 END SUB SUB LoadFile (File$) OPEN File$ FOR INPUT AS #1 DO linenumber% = linenumber% + 1 LINE INPUT #1, File(linenumber%) LOOP UNTIL EOF(1) CLOSE NumOfLines = linenumber% END SUB
Copy & Paste this into NotePad, save it as QFTView.bas in your Viewer dir, open it in QB 4.5, compile it, and run it.
Try it with different parameters. You might notice that if you run it with a wrong filename, it'll come up with a strange error.
Now you expect me to correct it right? NO! This is an EXERCISE for YOU to make.
Hmm... why not end with a little competition? Here:
So... Guess this is the end of this part... *SNIF* ... Well... Mail me with any complaints, greets, ideas for next part (have some myself, but more's needed), or anything else about this article. You could of course also go to the QbasicNews Forum and post there.
PS: Yes, I know I didn't teach any formatting this issue, but after writing 500 lines of HTML code, I decided that it would just have to wait.
'Till next time, Zap.