Rapid-Q Preface

Rapid-Q Documentation by William Yu (c)1999 Preface

BASIC is a language which has been around for decades, and thankfully, most of the language specifications have been maintained throughout. I'm not about to change the world by releasing something which deviates from the "normal" BASIC semantics. Most often, BASIC has been regarded as a purely procedural language devoid of any object oriented paradigm. This is only because people don't believe one can exist, but that's what they said about OOP-Pascal, but see how far Delphi has reached. Granted, Rapid-Q is not an object oriented programming language, but it does take some of the concepts of "objects." Rapid-Q is meant to be a fairly intuitive type language, meaning there should be some logic to the way you construct your programs. I did not create this language as a replacement to any other commercial, BASIC or other, compiler. That would be up to you to decide. Even though Rapid-Q supports many of the modern features of Windows programming, it is definitely not the end all. Since I know its limitations and what it can or cannot do, it's safe to say I won't be putting these other companies out of business. All I can say is, try the language out for yourself, and if you feel too restricted in the way you program your applications, then maybe Rapid-Q isn't the language for you.

My Goals
My goal is very simple, to expand people's knowledge by providing free products and services to the community. I'm providing Rapid-Q as a means for people, especially educators, to teach or learn Windows programming without the high costs required for other commercial compilers. Most of the concepts like event handling, object properties and methods can easily be abstracted to other languages. Since Rapid-Q is much simpler to use than C++ or Java for the first time user, it can become that bridge between failure and success. Most newbies are thrown right out of their seats by the confusion in using MFCs for Visual C++, or the harsh and strict type checked language like Java. Even Delphi would be intimidating if the user doesn't know enough about OOP-Pascal. Rapid-Q throws all these complex schemes out the window. That's why I say Rapid-Q wouldn't fit the bill for professional or advanced users. They would only use it for a quick hack of small applications. So I'm really aiming Rapid-Q at the newbie Windows programmer and intermediate programmers. Those who don't have the money to spend on the expensive development tools like C++ and Delphi, and don't want to learn harsh languages like Java can pick up Rapid-Q and start coding right away. Since distribution is fairly small, it appeals to many to download and try the compiler for themselves.

Source Codes
I have always stressed that the best way to learn is by example. It really isn't enough just to look at it and say "Uh huh, yeah." Take some time to take it apart and rewrite the code yourself. Trial and error is always a good way of learning. It seems we learn more by our mistakes, this is also true for programming. Yes, you'll have many nights of frustration when your code just doesn't seem to run properly, but once that bug is found, you'll be dancing around like there's no tomorrow.

Rapid-Q Audience
As stated before, Rapid-Q would probably not make a good language tool for advanced or professional users, but that's not to say they can't use it just the same. You can write a simple application in Rapid-Q which takes less time to write than if you coded it in C++, Java, or Delphi. It's all in what you're comfortable with. Since BASIC is a language with relaxed type checking, sometimes you feel lazy and don't want to declare all your variables, that's okay in Rapid-Q. Or sometimes you want to use a feature in Rapid-Q which is much easier to use than other languages so you would use Rapid-Q for that purpose. Taking all these into consideration, I've targeted beginner and intermediate programmers. It would be most appropriate in a classroom setting, but that's far fetched.

The Future of Rapid-Q
I plan to port the interpreter portion of Rapid-Q over to Linux and hopefully Unix systems as well. The parser is already portable, but I'm sure the Linux version will be a somewhat stripped down version. More news as they become available.

Comments & Suggestions
I appreciate all comments, suggestions and constructive criticism. I'm always turned off by the comment: "Screw it, it's only bytecode." That's not constructive criticism, that's a flat out bash. Yes, Rapid-Q is bytecode based. I just don't have the time and patience to do a Native code Rapid-Q compiler. Most likely that I'll do a Rapid-Q to Delphi or Rapid-Q to Java translator, but not a true native-code compiler. If you ever attempted to do this yourself, I'm sure you know the amount of time and effort this requires. That's not to say that writing a bytecode compiler is any easier or takes less effort and time, it still requires both.

E-mail me
William Yu <voxel@edmc.net>


Table of Contents

Rapid-Q Documentation by William Yu ©1999-2000 Contents

Contents

    Preface
    Chapter 1: Rapid-Q Overview
    • 1.1 How slow is Rapid-Q anyway?
    • 1.2 What about bloat-ware?
    • 1.3 Does Rapid-Q require any extra runtime DLLs?
    • 1.4 How much memory does Rapid-Q suck out of my programs?
    • 1.5 How easy is it to hack into my programs?
    • 1.6 Do I need a license to distribute my programs?
    Chapter 2: Rapid-Q Fundamentals
    • 2.1 Rapid-Q Environment
      • Required files and settings
    • 2.2 Using the Rapid-Q IDE
    • 2.3 Compiling and Running a Simple Application
    • 2.4 Command line switches
    • 2.5 General Structure of a Rapid-Q Program
    • 2.6 How close to the BASIC language is Rapid-Q?
    Chapter 3: Rapid-Q Language Guide
    • 3.1 Rapid-Q Directives
      • $APPTYPE
      • $DEFINE and $UNDEF
      • $ESCAPECHARS
      • $IFDEF and $IFNDEF
      • $INCLUDE
      • $OPTIMIZE
      • $OPTION
      • $RESOURCE
      • $TYPECHECK
    • 3.2 Variables and Assignments
      • Numeric types, string types
      • Numeric Range values
      • Proper assignment, and inconsistencies
    • 3.3 Rapid-Q Components/Objects
    • 3.4 Component Methods & Events
    • 3.5 Rapid-Q Subroutines & Functions
      • Special conditions
      • Passing by value or reference
    • 3.6 Rules of Scope
    Chapter 4: Writing your first Rapid-Q Application
    • 4.1 Deciding what to write
      • Simple database like program
      • Using QButton, QEdit, QForm, QLabel, and QListBox
    • 4.2 Designing the form
    • 4.3 Handling events
      • How to handle on click events
    • 4.4 Source Code Listing
    Chapter 5: Introduction to Forms
    • 5.1 What's in a form?
    • 5.2 Adding components to a form
    • 5.3 Tracking mouse position on form
      • Introduction to MouseX and MouseY
    • 5.4 Special Events for forms
      • OnResize, OnKeypress, OnKeydown
    • 5.5 Dialog boxes
      • Use of ModalResult
    • 5.6 Using the CREATE Method
    • 5.7 Embedding CREATEs
    • 5.8 Creating Menus
    Chapter 6: Writing Console Applications
    • 6.1 Overview of console functions
    • 6.2 Hello world example
      • Writing/Copying to/from offscreen pages
    • 6.3 Using PEEK and POKE
    • 6.4 Trapping extended keys
      • Introduction to DoEvents
    • 6.5 Mixing CONSOLE with GUI
    • 6.6 Linux/Unix console
    Chapter 7: Introduction to streams
    • 7.1 File streams
      • Reading/Writing numbers and strings
    • 7.2 Memory streams
      • Copying between streams
    Chapter 8: Using Image Resources
    • 8.1 Supported Resources
    • 8.2 Introduction to Image lists
      • More on Rapid-Q's image cache
    • 8.3 Other kinds of Resources
    Chapter 9: SUBI, FUNCTIONI, and DLLs
    • 9.1 SUB/FUNCTIONs with variable parameters
    • 9.2 More on FUNCTIONI
    • 9.3 Introduction to DLLs
    • 9.4 How to call a DLL
    • 9.5 Using Quick View
    • 9.6 Writing your own DLLs
    • 9.7 Using unsupported types in DLL call
    Chapter 10: Creating Custom Components
    • 10.1 Introduction to object creation
    • 10.2 Extending QCanvas
      • Adding new properties
      • Using Constructor
    • 10.3 Adding/Overriding Methods
    • 10.4 Defining Events
      • Inherting Events
    • 10.5 Adding components to components
    • 10.6 Extending empty components
    • 10.7 Public/Private properties and methods
    • 10.8 Summary
    • 10.9 QDiamondBox Source Code Listing
    Chapter 11: Using Function Pointers
    • 11.1 Introduction to the concept
    • 11.2 Defining function pointers
    • 11.3 Using function pointers properly
    • 11.4 What's not supported in Rapid-Q
    Chapter 12: Graphics under Windows
    • 12.1 Graphics under DOS versus Windows
    • 12.2 What components require painting
    • 12.3 Drawing graphics dynamically
      • Using QBITMAP as the off-screen page
    • 12.4 Ownerdraw List and Combo Boxes
      • Ownerdraw Variable vs. Fixed
    • 12.5 Using DirectX
    Chapter 13: Direct3D for Rapid-Q
    • 13.1 Requirement specifications
      • Required or suggested files
    • 13.2 Using Anim8or to create 3D models
    • 13.3 Loading/Using .X files
    • 13.4 Wrapping textures around an object
    • 13.5 Rotate/Moving objects
    Chapter 14: Programming in MySQL
    • 14.1 Quick introduction
      • Required files
    • 14.2 Connecting to MySQL
    • 14.3 How to perform queries and obtain result
    • 14.4 Interfacing QMYSQL with QSTRINGGRID
    • 14.5 Storing and retrieving blobs
    • 14.6 Using LOADBLOB and SAVEBLOB
    • 14.7 In conclusion
    Appendix A: Rapid-Q Component/Object Reference
    • CLIPBOARD
      • Properties, Methods ClipBoard examples
    • PRINTER
      • Properties, Methods Printer examples
    • QBITMAP
      • Properties, Methods QBitmap examples
    • QBUTTON (Windows/Linux)
      • Properties, Methods, Events QButton examples
    • QCANVAS (Windows/Linux)
      • Properties, Methods, Events QCanvas examples
    • QCHECKBOX (Windows/Linux)
      • Properties, Events, QCheckbox examples
    • QCOMBOBOX (Windows/Linux)
      • Properties, Methods, Events, QCombobox examples
    • QCOMPORT
      • Properties, Methods, Events, QComPort examples
    • QCOOLBTN (Windows/Linux)
      • Properties, Methods, Events QCoolbtn examples
    • QDIRTREE
      • Properties, Methods, Events, QDirTree examples
    • QEDIT (Windows/Linux)
      • Properties, Events, QEdit examples
    • QFILELISTBOX
      • Properties, Methods, Events, QFileListBox examples
    • QFILESTREAM (Windows/Linux)
      • Properties, Methods, QFilestream examples
    • QFONT (Windows/Linux)
      • Properties, Methods, QFont examples
    • QFONTDIALOG
      • Properties, Methods, Events, QFontDialog examples
    • QFORM (Windows/Linux)
      • Properties, Methods, Events, QForm examples
    • QGAUGE
      • Properties, QGauge examples
    • QGLASSFRAME
      • Properties QGlassFrame examples
    • QGROUPBOX
      • Properties, Methods, Events, QGroupBox examples
    • QHEADER
      • Properties, Methods, Events QHeader examples
    • QIMAGE
      • Properties, Methods, Events QImage examples
    • QIMAGELIST
      • Properties, Methods, QImageList examples
    • QLABEL (Windows/Linux)
      • Properties, Events, QLabel examples
    • QLISTBOX (Windows/Linux)
      • Properties, Methods, Events, QListbox examples
    • QLISTVIEW
      • Properties, Methods, Events, QListView examples
    • QMAINMENU (Windows/Linux)
      • Properties, Methods, QMainMenu examples
    • QMEMORYSTREAM (Windows/Linux)
      • Properties, Methods, QMemorystream examples
    • QMENUITEM (Windows/Linux)
      • Properties, Methods, Events QMenuItem examples
    • QMYSQL (Windows/Linux)
      • Properties, Methods, QMySQL examples
    • QNOTIFYICONDATA
    • QOPENDIALOG (Windows/Linux)
      • Properties, Methods, QOpenDialog examples
    • QOUTLINE
      • Properties, Methods, Events, QOutLine examples
    • QOVALBTN (Windows/Linux)
      • Properties, Methods, Events QOvalbtn examples
    • QPANEL (Windows/Linux)
      • Properties, Events, QPanel examples
    • QPOPUPMENU
      • Properties, Methods, QPopupMenu examples
    • QRADIOBUTTON (Windows/Linux)
      • Properties, Events, QRadioButton examples
    • QRECT
    • QREGISTRY
      • Properties, Methods, QRegistry examples
    • QRICHEDIT (Windows/Linux)
      • Properties, Methods, Events, QRichedit examples
    • QSAVEDIALOG
      • Properties, Methods, QSaveDialog examples
    • QSCROLLBAR (Windows/Linux)
      • Properties, Events, QScrollBar examples
    • QSCROLLBOX
      • Properties, Methods, Events, QScrollBox examples
    • QSOCKET (Windows/Linux)
      • Properties, Methods, QSocket examples
    • QSPLITTER
      • Properties, Events, QSplitter examples
    • QSTATUSBAR
      • Properties, Methods, Events, QTrackBar examples
    • QSTRINGGRID
      • Properties, Methods, Events, QStringGrid examples
    • QSTRINGLIST
      • Properties, Methods, QStringList examples
    • QTABCONTROL
      • Properties, Methods, Events, QTabControl examples
    • QTIMER (Windows/Linux)
      • Properties, Events, QTimer examples
    • QTRACKBAR
      • Properties, Methods, Events, QTrackBar examples
    Appendix B: Rapid-Q DirectX Component/Object Reference
    • QDXIMAGELIST
      • Properties, Methods, Events QDXImageList examples
    • QDXSCREEN
      • Properties, Methods, Events QDXScreen examples
    • QDXTIMER
      • Properties, Methods, Events QDXTimer examples
    Rapid-Q Direct3D Component/Object Reference
    This is a work in progress, some properties or methods may change in the future. All 3D operations are done in Retained mode.
    • QD3DFace
      • Properties, Methods, QD3DFace examples
    • QD3DFrame
      • Properties, Methods, QD3DFrame examples
    • QD3DLight
      • Methods, QD3DLight examples
    • QD3DMesh
      • Properties, Methods, QD3DMesh examples
    • QD3DMeshBuilder
      • Methods, QD3DMeshBuilder examples
    • QD3DTexture
      • Methods, QD3DTexture examples
    • QD3DVector
      • Properties, QD3DVector examples
    • QD3DVisual
      • Methods, QD3DVisual examples
    • QD3DWrap
      • Methods, QD3DWrap examples
    Appendix C: Rapid-Q Keywords & Statements
    • Valid Operators (In order of precedence)
      • Exponentiation (^)
      • Multiplication/Division and Shifts (*, /, \ (integer division), SHL, SHR)
      • Modulo arithmetic (MOD, INV)
      • Addition and subtraction (+, -)
      • Relation operations (=, >, <, <>, <=, >=)
      • Logical operations in order from high to low (NOT, AND, OR, XOR)
    • Rapid-Q internal definitions
      • WIN32, UNIX, TYPE
    • Branching with GOTO and GOSUB
      • GOTO, GOSUB, RETURN
    • User defined types
      • TYPE versus STRUCT
    • Conditional statements
      • IF .. THEN .. ELSE, SELECT CASE
    • Loops
      • FOR .. NEXT, DO .. LOOP, WHILE .. WEND
    • Constructors/Methods
      • CONSTRUCTOR, CREATE, WITH
    • Procedures
      • SUB, FUNCTION, SUBI, FUNCTIONI
    • Internal Variables
      • MouseX, MouseY, etc...
    • Console keywords, Detailed list
      • CLS, COLOR, PRINT, INKEY$, etc...
    • Other reserved keywords, Detailed list
      • ABS, LEN, MID$, SWAP, etc...
    • Touble Shooting
      • How to Debug your programs
Next Chapter


Chapter 1: Rapid-Q Overview

Rapid-Q Documentation by William Yu (c)1999 Chapter 1

1. Rapid-Q Overview

So what is Rapid-Q? Put simply, a free BASIC (bytecode) compiler for Windows and several flavours of Unix, including Linux. Most people must be wondering, is it slow, is it as bloated as Visual Basic, do I need runtime DLLs, how much memory does Rapid-Q take away from my programs? These are all trade-off issues. One language may not be suitable for your needs, so you try another. Rapid-Q won't suit everybody, nor even the majority of prorgammers (BASIC or otherwise). However, I'm not going to fool anyone either and claim Rapid-Q is faster than this language or is better than another. It is a language, like any other language, to be used (anywhere), to be picked apart, to be judged fairly or otherwise, and above all, to be used to create your Windows or Linux/Unix applications as you want it to be created.

1.1 How slow is Rapid-Q anyway?
Well, since Rapid-Q is event based and the bytecode is optimized for high level constructs (hehe, I'm rambling here), Rapid-Q isn't as slow as many think. It's only slow if you require heavy computation or to perform very low level manipulation to data. For example, reading a single byte from a 1MB file will obviously take longer in Rapid-Q than in most languages, but not so extremely slow that you'll be sleeping at the keyboard. Same with looping I = I + 1 a few thousand times. But in terms of displaying graphics, controls and forms, it's just as fast as any other language. For computations, I suggest writing a separate DLL in a more accustomed language like C, and call the DLL in Rapid-Q when you just need that extra speed.

 1.2 What about bloat-ware?
This is obviously something which there's nothing much you can do about. Rapid-Q (the interpreter part) itself, requires about 300KB (150KB for Linux, 600KB for Sparc). So this is the overhead that all your programs will have. Compared to some Windows programs, this isn't that bad, but still bloated if all you wanted was a simple "Hello World!" program. Your bytecode will only add to it, but most likely your bytecode is less than 50KB anyway (for a moderate/large application), plus any resources and graphics you may want to include of course.

1.3 Does Rapid-Q require extra runtime DLLs?
No. All your programs require no extra runtime DLLs or externalities. Just distribute your .EXE file and that's it. They should run on any Win95/98/NT system, assuming the end user hasn't done anything to his Windows System files. If you compare the bloat-ware of Rapid-Q and the runtime DLLs of other languages, Rapid-Q isn't that bad in terms of bloated size.

1.4 How much memory does Rapid-Q suck out of my programs?
It doesn't suck anything out of your programs (not literally), but it does suck memory out of Windows which in turn limit the amount of memory for your program(s). It really isn't as bad as one might think though. It eats up less than 80KB for virtual, global, and heap memory combined. This is because all variables and objects are created dynamically, and even objects take up less than 1KB to create. The heap memory is the one you should look out for. If your program is deeply nested or involves intense recursion, this can grow and shrink very rapidly. You don't need to worry about cleaning up your objects or variables when your program terminates. Rapid-Q will free all your objects and clean up the memory space for you.

1.5 How easy is it to hack into my programs?
Being a bytecode compiler, if the end user knows how everything is constructed, then it's just a formality. However, Rapid-Q generates a non-standard, or non-specific type bytecode output, which means, unless the user specifically knows what each operation does, it is very very difficult to hack your program. It's easy to hack into your string variables (like any other language), because these things aren't encrypted anyway. In most cases, your program should be safe from snoopers, they might not even know your program is bytecode generated! Unlike Java or other languages, Rapid-Q does not attach any symbol table or extra debugging information to your .EXE.

1.6 Do I need a license to distribute my programs?
No. You don't need a license to use Rapid-Q (it's free), and you definitely don't need any license to distribute or sell your programs. Rapid-Q can be used for any task, whether it's profit-seeking or otherwise. You don't pay me a cent, and you don't even have to acknowledge that your program was created with Rapid-Q (although this would be a nice gesture). You CANNOT, however, distribute Rapid-Q (the program itself) and charge for it. You're allowed to bundle Rapid-Q along with your program(s), so long as the user is well informed that it's not buying into Rapid-Q, but rather, buying into your program. How is that done? By not even advertising that your distribution includes a copy of Rapid-Q. Call it the hidden feature. I don't mind if you include Rapid-Q into those shareware or freeware type CD-ROMs. That's because I know they're not going to spend 30 some dollars just to get a copy of Rapid-Q, so advertise all you want.


Chapter 2: Rapid-Q Fundamentals

Rapid-Q Documentation by William Yu (c)1999 Chapter 2

2. Rapid-Q Fundamentals

Before jumping into any language, it helps to know how to use it first. This chapter will introduce you to the Rapid-Q environment, how to compile and run your programs, and what the general structure of your Rapid-Q program will look like.

2.1 Rapid-Q environment
Your Rapid-Q distribution should have included a simple IDE (integrated development environment) program (called RAPIDQ.EXE), along with the actual Rapid-Q compiler (RC.EXE). RAPIDQ32.LIB and RAPIDQCC.LIB are also required to compile any of your programs. These are the main (4) programs that you will need to develop and compile your Rapid-Q source codes. The IDE is strictly optional. If you feel more comfortable writing your programs in NotePad or whatever editor you choose, that's also fine. If that is the case, you probably want to skip the next section on Using the Rapid-Q IDE. All these files must reside in the same directory.

2.2 Using the Rapid-Q IDE
Unlike some IDEs that offer debugging options, the Rapid-Q IDE offers nothing more than an environment to write your programs, run them, and provide run-time command options. It has primitive error checks, I say primitive, because the IDE doesn't do the error checking at all, (RC.EXE) the compiler does all of it. It's just that the Rapid-Q IDE interfaces nicely with RC.EXE so you don't really notice that. It also provides syntax highlighting which makes using the Rapid-Q language much easier.
    What are its limitations:
  • Not all components are available in the form designer
  • When running files, that file is automatically saved
  • All files are compiled before they are executed
I can't speak for everybody, but the Rapid-Q IDE is a good tool to use when starting out to learn the Rapid-Q language, but as you become more accustomed to the language, most people would switch to their favourite text editor. I prefer writing my programs in DOS (EDIT.COM). That is not to say that you should abandon using the Rapid-Q IDE altogether, if you feel comfortable using it, by all means, stick with it.

2.3 Compiling and Running a Simple Application
Wait a minute, we haven't even covered the BASICs on writing a simple application yet. Don't worry, we'll get to that, it's better to know how to compile and run it first before doing anything else. Here is a very simple GUI application that you can type in and compile for yourself.
            DIM MainForm AS QFORM
            MainForm.ShowModal
If you're using the Rapid-Q IDE, just type in that code (or cut & paste if you like). Click on the Run Menu, and select Run. If all goes well, you should see an empty Window at the top left hand corner of the screen. Close it and return to your IDE. If you prefer the command line approach of compiling, then load up your favourite editor, copy the above code and save it to a file (Forms.BAS). Then to compile it, you type in:
          RC Forms.BAS
If all goes well, you should have a Forms.EXE file in the current directory. Just type Forms to run it. If all goes well, continue reading. If not, then something is amiss, in which case, see the Trouble Shooting section.

2.4 Command line switches for RC.EXE
I will only discuss the 3 more important ones:
      -I[Path] Change Include Path
      -L[Path] Change Library Path
      -G[File] Icon file
The compiler by default looks in the current directory for the .LIB files and any include files. You can override this by specifying the above command line switches. Since we're talking about C type parameters, there are a few niceties you have to know about, first, the paths should be specified like so:
      RC -Ic:/rapidq/includes
You can use \ instead of / but there's a reason why / is preferred, consider this:
      RC -I"c:\rapidq long dir\includes\"
If you never used C (or C++) you'll not likely see what I mean. If you prefer the above command line, you have to add an extra \ to the end (or drop it entirely), like so:
      RC -I"c:\rapidq long dir\includes\\"
or
      RC -I"c:\rapidq long dir\includes"
This is because C translates \" into " which is obvious to any C programmer. Also, long file names must be enclosed in quotations. Those are the catches, so now you know (or already knew).
Now, to change the default icon for your .EXE file, you can use the -G command switch:
      RC -Gzip.ico zipview.bas
When your ZIPVIEW.EXE file is generated, the file "zip.ico" will replace the default icon. Please note that your icon must be 32x32 and 16 colors (also 766 bytes).

2.5 General Structure of a Rapid-Q Program
There really is no pre-defined structure of a BASIC program, but there is a general form that most people conform to.
    Directives
    Declarations
    Global Variables
    Main Program
This is only a general form, your Rapid-Q applications can be structured in a variety of ways. Some of which will have similar results, and some will have devasting or more customized results. For example, $INCLUDE is a directive to import a file at that position. So if you use $INCLUDE somewhere in your main program, it would have a different result than if you included it at the beginning of your program.

2.6 How close to the BASIC Language is Rapid-Q?
Very close, all the familiar commands like DIM, PRINT, MID$, etc. are inherited. That does not mean you'll be able to port your DOS based QBasic programs to Rapid-Q without any modification. Since Rapid-Q is Windows based, providing primitive support for CONSOLE, it's a safe bet you won't directly convert your QBasic applications to Rapid-Q without a 50-90% rewrite of your source code (depending on what the code does). Comments in Rapid-Q begin with the ' symbol, just like QBasic, or you can use REM instead. You can also separate lines by using the colon : symbol. This has the same effect as starting a new line.
             PRINT "Hello" : PRINT "World"
         or
             PRINT "Hello"
             PRINT "World"
Most BASIC programmers will become very accustomed to the language once they use it. However, Rapid-Q does not inherit the properties of Visual Basic. For example, there's no SUB MAIN procedure, nor is there any public or private identifiers used in Rapid-Q. Your entire program is considered the MAIN program. Going from Rapid-Q to Visual Basic probably requires a bit more effort than the reverse.


Chapter 3: Rapid-Q Language Guide

Rapid-Q Documentation by William Yu (c)1999 Chapter 3

3. Rapid-Q Language Guide

In this chapter, I'll go through the language of BASIC, specifically Rapid-Q. Since Rapid-Q is derived from the BASIC language, most experienced BASIC programmers can skim this section if you so choose. There's a few new concepts that is not part of the BASIC language like infinite parameter passing and using the '-' operator on strings.

3.1 Rapid-Q Directives
Directives are used in Rapid-Q to tell the compiler how, and what kind of code is to be generated. Rapid-Q supports the following directives, which are usually included at the beginning of your programs.

 $APPTYPE
[ CGI | CONSOLE | GUI ] Default is GUI
$APPTYPE is used to tell the compiler what kind of application you want generated. Although the default is GUI, if no $APPTYPE directive is used, Rapid-Q will detect what kind of application your program is just by looking at the source code. To override this feature, include the $APPTYPE directive at the beginning of your source code.
Usage: $APPTYPE CONSOLE

$TYPECHECK
[ OFF | ON ] Default is OFF
$TYPECHECK is used to tell the compiler whether you want the source code parsed using strict type checking ON (all variables must be declared), or relaxed type checking OFF like traditional BASIC where you don't need to declare your variables. Note, you can turn ON or OFF type checking at anytime, so you can type check a portion of your code and turn it OFF afterwards.
Usage: $TYPECHECK ON

$INCLUDE
[ FileName ]
Using $INCLUDE has the same effect as importing your file directly into your program at the point of call. You can use $INCLUDE anywhere in your program, except in a SUB or FUNCTION, but is most often included at the beginning of your source code.
Usage: $INCLUDE "RAPIDQ.INC"

$RESOURCE
Handle AS FileName
Most Windows programming languages include support for Resource files. In Rapid-Q, this is somewhat different. In Rapid-Q, Resource files are just a collection of graphics files. There is no such thing as resource strings in Rapid-Q. Anyway, what's great about Resource files is that they are embedded into your applications. So if you're using 10 different bitmaps, you don't need to include them in your .ZIP distribution because it's already embedded into the .EXE.
Usage: $RESOURCE RES_BMP1 AS "CLOUDS.BMP"

$DEFINE
NewDefinition [OldDefinition]
When you feel like redefining or creating new keywords/tokens, use this directive. You cannot construct a series of tokens to be redefined. You cannot redefine operators or punctuations. $DEFINE cannot be used to define a function (like in C). The OldDefinition parameter is optional, so you can do this just fine: $DEFINE NEWDEF
Usage: $DEFINE INT16 SHORT

$UNDEF
DefName [, DefName]
To undefine a previous call of define, use $UNDEF. You can specify multiple instances on the same line, separated with commas.
Usage: $UNDEF INT16, INT32

$IFDEF
Definition
This directive is used to specify whether a piece of code should or should not be compiled. It is used in conjunction with $DEFINE. If the Definition has been defined, the code within the $IFDEF..$ENDIF statement will be compiled, otherwise it is skipped entirely.
Usage:
    $IFDEF INT16
    ' if INT16 has been defined
    ' compile this portion
    $ELSE
    ' if INT16 has not been defined
    ' compile this portion
    $ENDIF

$IFNDEF
Definition
$IFNDEF has the opposite effect as $IFDEF.
Usage:
    $IFNDEF INT16
    ' if INT16 has not been defined
    ' compile this portion
    $ELSE
    ' if INT16 has been defined
    ' compile this portion
    $ENDIF

$OPTION
OptionName [Parameters]
BYREF, DECIMAL, EXPLICIT, and GTK are valid OptionNames.
Usage:
    $OPTION BYREF
    This changes the way variables are
    passed. By default, Rapid-Q passes variables
    by value. This option reverses that.
    Use with caution.

    $OPTION DECIMAL ","
    $OPTION DECIMAL 64
    This changes the default decimal
    character for use in VAL.
    The default decimal character is the period.

    $OPTION EXPLICIT
    Same as using TYPECHECK ON
    Maintained for compatibility with VB

    $OPTION GTK
    Uses GTK instead of XFORMS
    Make sure you have the proper files

$OPTIMIZE
[ OFF | ON ] Default is OFF
$OPTIMIZE can be used to reduce the byte code size by eliminating unnecessary instructions. If you use this option, make sure it's one of the first things you call.
Usage: $OPTIMIZE ON

$ESCAPECHARS
[ OFF | ON ] Default is OFF
If $ESCAPECHARS is turned ON, you can use escape sequences in your strings. Escape sequences can either be character or numeric escapes. Note that case is sensitive.
Usage: $ESCAPECHARS ON
Escape sequence Details
\a
\b
\f
\n
\r
\t
\v
\\
\"
\###
\xHH
 Alarm bell
Backspace
Form feed
New line
Carriage return
Horizontal Tab
Vertical Tab
Backslash
Double quote
### is any number 0..255
HH is a hexidecimal value 00..FF
Examples:
    PRINT "\""
    Output is "

    PRINT "\x41"
    Output is A

    PRINT "\t\65\66\67\t\68\69\70
    Output is ABC       DEF

    PRINT "Hey\r\n";
    Output is Hey with newline

3.2 Variables and Assignments
Variables are stored in main memory, and stay there for the entire duration of your program. In Rapid-Q, type checking is very relaxed. Which means you can assign a string to an integer variable. The result is undefined, but will most likely return 0. Same goes with assigning a number to a string variable, the result is an empty string. Type checking is really done at the interpreter level in Rapid-Q, but since you don't want error messages popping up everywhere, I have disabled the check entirely. What this ultimately means is that you should be very very careful in assigning values to your variables, since you won't get any warnings from Rapid-Q. The only strict type checking done is for QObjects. You cannot assign a number or string to a variable expecting an Object for its value. Some examples of valid assignments:
         A% = "Hello" > "World"
         A$ = "Hi World!"
         A# = 34 + 34 - 324 * 3 / (34 / 5 + 5)
If you've never programmed in BASIC before, you're probably wondering what all those symbols after the A mean. Well, since most implementations of BASIC does not restrict you to define your variables before you use them, you can define them by using these symbols:
         ?, ??, ???, %, &, !, #, $
They represent BYTE, WORD, DWORD, SHORT, LONG or INTEGER, SINGLE, DOUBLE, and STRING, respectively. Of course, if you didn't put any symbol in front of your undeclared variable, it's automatically assumed that the variable is a DOUBLE. That is the implementation used in Rapid-Q, for other languagues, the default maybe SINGLE, LONG, or what have you. Here's a table for your viewing pleasure:
    Type       ID  Size  Range
    --------- ---- ---- -------------
    Byte        ?   1   0..255
    Word       ??   2   0..65535
    Dword     ???   4   Only Linux version for now...
    Short       %   2   -32768..32767
    Integer     &   4   -2147483648..2147483647
    Long        &   4   -2147483648..2147483647
    Single      !   4   1.5 x 1045..3.4 x 1038
    Double      #   8   5.0 x 10324..1.7 x 10308
If you didn't like the way that was done, you could also use DIM to declare your variables, like so:
            DIM Number AS INTEGER
            DIM S AS STRING
            DIM B AS BYTE
Well, you get the idea. If you turned $TYPECHECK ON, then you will be forced to declare your variables like that. It's a nice habit to pick up, especially if you wanted to switch to languages like C or Pascal. You will be forced to declare all your variables before you use them. Here's something that's valid in Rapid-Q, but can confuse the daylights out of people:
            DIM Num$ AS INTEGER
Yes, try to avoid obfuscated code like that.

 3.3 Rapid-Q Components/Objects
Rapid-Q offers reuseable components (or objects) which assists the programmer in developing Windows applications. Most RAD (Rapid Application Development) Programming languages offer this. For Visual C++, it's MFC, and for Java, it's JFC Swing. So what are components? They're basically just wrapper code that implement all the features of the Windows API control without all the headaches involved in using the Windows API directly. For example, you can create windows using pure Windows API calls only, but this can run down for pages. In Rapid-Q, all this has been wrapped up into a component called QFORM. So instead of having to first register your class window, then display it and handle all the callbacks, all you do in Rapid-Q is:
             DIM Form AS QFORM
             Form.ShowModal
Comparing this to a C/C++ program, it's much cleaner, and easier to understand. There are a lot of supported components in Rapid-Q, like QBUTTON, QIMAGE, QFILESTREAM, etc. There are also some which aren't supported, that's the restriction involved in using Rapid-Q. Components are created exactly the same way you create variables, by using DIM. Each component has its own properties, methods and events. Properties are like the component's attributes. For example, Left, Top, Width, and Height are properties common to all visible controls, which define its placement within the form or Window. Caption is a property of type STRING. For a QFORM component, the Caption property defines the title of that form. Caption for a QBUTTON defines the text of that button. Caption for something like QFILESTREAM does not exist, since a QFILESTREAM isn't a visible component. It has its own properties. For a complete guide of the properties, methods and events for all components, please check the Appendix section. Here's a quick example of how you can assign properties to your components:
                 DIM Form AS QFORM
                 Form.Caption = "My Application"
                 Form.Left = 100
                 Form.Top = 100
Becareful to know which properties are Read-Only, and which ones are Write-Only. An example of a read-only property is the ITEMCOUNT property of a QLISTBOX. An example if a write-only property is the ICON property of a QFORM, used to specify the location of an icon to use as the default. Reading the Write-Only values, or Writing to Read-Only values have no defined meaning, and may result in a compile error or more seriously, your program crashing.

3.4 Component Methods & Events
Well, we've covered only the properties so far, but methods aren't much different. What exactly is a method you ask? It's really just a SUBROUTINE or FUNCTION. It's called a method, because the SUBROUTINE or FUNCTION only refers to that component. This is harder to explain than to understand. Here's an example of a method:
              DIM Form AS QFORM
              Form.Center
              Form.ShowModal
We used 2 methods here, Center, and ShowModal. The Center method is a SUBROUTINE that accepts no parameters. What it does is center the form on your desktop. ShowModal is actually a FUNCTION, but we ignore the return value in this case. It's a method used to Display your form, and wait for the user to close it. Note: Unlike some BASIC implementations, a FUNCTION can be called like a SUBROUTINE in Rapid-Q, you just ignore the return value. This is similar to C/C++. Other methods that you see may require some extra parameters, and some even accept an infinite number of parameters. You can also write these in Rapid-Q yourself, but I'll cover that topic later. So basically, methods are functions which perform a specific task on that component. In our above example, we're centering the form, and then displaying it.
All right, now what about events? Well, this can be a confusing subject if we were talking in terms of message passing and callbacks. Well, luckily, we can take a much higher level look at it. An Event occurs whenever something happens. This is very vague, something happening could be anything from time elasping, user clicking the mouse, user pressing a key, etc. Rapid-Q can't trap all these events, but the most important ones are. For example, if a user clicked on a button, you'd want to write some code to perform that task. We have to define a CALLBACK function to handle it. For each event which occurred, you want to direct that event to a subroutine you wrote to handle the event. Here's how:
       SUB ButtonClicked
          PRINT "Button was clicked"
       END SUB

       DIM Button AS QBUTTON
       DIM Form AS QFORM

       Button.Parent = Form            '' Property
       Button.OnClick = ButtonClicked  '' Event
       Form.ShowModal                  '' Method
Seems easy enough right? It really is. Whenever an "OnClick" message/event occurs, the program jumps into your subroutine ButtonClicked and executes the code you have waiting in there. The above program is complete, so you can try it out yourself. For a list of all events that a particular component can receive, just look at the Appendix section.

3.5 Rapid-Q Subroutines & Functions
There are some GOTCHAS associated with Rapid-Q SUBs and FUNCTIONs. The first, and most important, is that all values passed are passed by VALUE (except for objects and arrays). To pass a variable by reference, you need to prepend an @ symbol. The second catch is that you can't pass/accept User Defined Types. There's no difference in the way you create SUBs or FUNCTIONs in Rapid-Q (as compared to other BASIC languages like QBasic/PB):
    FUNCTION FindMax (X AS INTEGER, Y AS INTEGER) AS INTEGER
      IF X > Y THEN
        FindMax = X      '' Return value is X
      ELSE
        FindMax = Y      '' Return value is Y
      END IF
    END FUNCTION
The above code is valid, as is the following:
    FUNCTION FindMax (X%, Y%) AS INTEGER
      IF X% > Y% THEN
        FindMax = X%      '' Return value is X
      ELSE
        FindMax = Y%      '' Return value is Y
      END IF
    END FUNCTION
However, as you may notice, you can't have FindMax% without attaching an AS INTEGER to the end of the function. To pass a variable by reference, attach an @ symbol in front of your variable:
    SUB StrCat (Source AS STRING, Text AS STRING)
        Source = Source + Text
    END SUB

    A$ = "Hello"
    StrCat(@A$, " World!")
    PRINT A$                '-- Should print: Hello World!
Or if you prefer, you can also attach a BYREF keyword in your parameter list like so:
    SUB StrCat (BYREF Source AS STRING, Text AS STRING)
        Source = Source + Text
    END SUB

    A$ = "Hello"
    StrCat(A$, " World!")
    PRINT A$                '-- Should print: Hello World!
Yet another approach you can use instead (note that this is the "old" way, maintained for compatibility reasons):
    SUB Strcat (A$, B$)
       A$ = A$ + B$
    END SUB

    A$ = "Hello"
    Strcat(A$, " world!")
    A$ = STACK.STR(0)
    PRINT A$
The stack contains an array of integers and strings, to access the correct parameter, you have to specify the number (from left to right). The first element being 0. You can also pass QObjects, but you can't use it as a return value.
    SUB (Button AS QButton)
        Button.Left = 100
    END SUB
All components/QObjects are passed by reference.

3.6 Rules of Scope
Rapid-Q is not like BASIC in this case. Since Rapid-Q is a simple top-down one-pass compiler, the scope is very similar to that of Pascal. Here's what I mean:

       SUB Test
          DIM I AS INTEGER
          I = 100
          PRINT I
       END SUB

       DIM I AS INTEGER
       I = 10

       SUB Test2
         PRINT I
       END SUB

       Test    '' Call Subroutine
       Test2
Here's how the scope works, for the SUB Test, the LOCAL variable I only extends down as far as the end of that SUB block. The variable I in the main program extends down all the way to the end of your program. That means SUB Test2 can use the global variable I because it's within its scope. You can also redeclare the variable I in SUB Test2, in which case the local I is used instead of the global I.


Chapter 4: Writing your first Rapid-Q Application

Rapid-Q Documentation by William Yu (c)1999 Chapter 4

4. Writing your first Rapid-Q Application

Let's jump right into writing Windows applications in Rapid-Q! There will be a simple step-by-step guide, along with the complete source code listing at the end of this chapter.

4.1 Deciding on what to write
We're not going to write a simple "Hello World!" demo, nor are we going to write a web browser, we'll start with something meaningful, yet simple to write. Let's write a simple form based database type program. Some of the concepts we'll learn is form handling, event handling, and using the components, QEDIT, QBUTTON, QFORM, QLABEL, and QLISTBOX. Here's what our finished application should look like, you can modify the interface to your liking (if you're comfortable you know what you're doing).

It may look like a lot, but honestly, the source code is less than 100 lines! Most of the time spent is used designing the layout.

4.2 Designing the form
You can almost see the components that we'll need. One QFORM, 2 QBUTTONs, 4 QEDITs, 4 QLABELs, and finally 1 QLISTBOX. First of all, we need a Window (that's our QFORM). So let's type that in:
           DIM MainForm AS QFORM

           MainForm.Center
           MainForm.Caption = "My First Application"
           MainForm.Height = 340
           MainForm.Width = 350
           MainForm.ShowModal    '-- Display form
If you entered all this correctly, you should see an empty Window, with the same geometry as the above diagram. One thing to notice is that we're not using MainForm.Left or MainForm.Top because when the MainForm is centered, it is automatically calculated for us. All we really need is to supply the width and height of our Window.
All right, now that we have our Window, we'll have to add controls to it. You should place the following code BEFORE the line MainForm.ShowModal. For the sake of argument, let's begin by adding some labels to our Window.
       DIM NameLabel AS QLABEL, AddrLabel AS QLABEL
       DIM CityLabel AS QLABEL, PhLabel AS QLABEL

           NameLabel.Parent = MainForm
           NameLabel.Caption = "Name:"
           NameLabel.Top = 13
           NameLabel.Left = 25
           AddrLabel.Parent = MainForm
           AddrLabel.Caption = "Address:"
           AddrLabel.Top = 38
           AddrLabel.Left = 25
           CityLabel.Parent = MainForm
           CityLabel.Caption = "City:"
           CityLabel.Top = 63
           CityLabel.Left = 25
           PhLabel.Parent = MainForm
           PhLabel.Caption = "Phone #:"
           PhLabel.Top = 88
           PhLabel.Left = 25
We're creating 4 label components, and we're going to use MainForm as our container for these components, hence the Parent = MainForm association. If for example, we created a QPANEL on our form, it can also act as a container for any of our controls. But we won't get into that until later. For the moment, take some time to digest the above code and add it to our previous listing.
We now have our Window, our 4 labels, now let's add the 4 edit controls to our application.
       DIM NameEdit AS QEDIT, AddrEdit AS QEDIT
       DIM CityEdit AS QEDIT, PhEdit AS QEDIT

           NameEdit.Parent = MainForm
           NameEdit.Left = 70
           NameEdit.Top = 10
           NameEdit.Width = 230
           AddrEdit.Parent = MainForm
           AddrEdit.Left = NameEdit.Left
           AddrEdit.Width = NameEdit.Width
           AddrEdit.Top = 35
           CityEdit.Parent = MainForm
           CityEdit.Left = NameEdit.Left
           CityEdit.Width = NameEdit.Width
           CityEdit.Top = 60
           PhEdit.Parent = MainForm
           PhEdit.Left = NameEdit.Left
           PhEdit.Width = NameEdit.Width
           PhEdit.Top = 85
Looks familar doesn't it? It's the same idea as our QLABELs, the biggest thing is correct placement on the form. In the above example, we're aligning all the QEDIT controls just after the QLABELs. Again, take some time to digest the above code and add it to our existing code.
All that's left is to add our 2 buttons and one listbox control. Here's how we do that:
       DIM AddButton AS QBUTTON, ClearButton AS QBUTTON
       DIM ListBox AS QLISTBOX

           AddButton.Parent = MainForm
           AddButton.Left = 70
           AddButton.Top = 115
           AddButton.Width = 110
           AddButton.Caption = "&Add to Database"
           ClearButton.Parent = MainForm
           ClearButton.Left = 190
           ClearButton.Top = 115
           ClearButton.Width = 110
           ClearButton.Caption = "&Clear Database"

           ListBox.Parent = MainForm
           ListBox.Top = 150
           ListBox.Left = 70
           ListBox.Width = 230
           ListBox.Height = 150
Cut & Paste, and voila! Wow, we now have a form which looks exactly like the diagram above (section 4.1). Run it, fool around with it for a while, then return back, there's still two more things to implement.

 4.3 Handling Events
As you can see, the above code just flashes us with a nice user interface, but nothing to back it up with. If you tried clicking on the buttons, they do nothing. You'll have to write your event handler to handle a button click. Here's how:
           AddButton.OnClick = AddButtonClick
That it? Well, that's part of it, the OnClick event handler will transfer execution to the subroutine we named AddButtonClick. Now we'll have to go and write our subroutine. Just make sure you include the subroutine below, before adding the above code.
           SUB AddButtonClick
               IF ListBox.ItemCount > 0 THEN
                  '-- Add a nice separator
                  ListBox.AddItems "--------------------------"
               END IF
               ListBox.AddItems NameEdit.Text, AddrEdit.Text, _
                                CityEdit.Text, PhEdit.Text
           END SUB
Well, now we're getting somewhere. Whenever the user clicks on the add button, the code above gets executed. As you can see, all it does is add the text fields to our listbox. If you didn't already know, the underscore '_' character can be used in Rapid-Q to split up long lines. We're almost done, now we'll add an event handler for the other button.
           SUB ClearButtonClick
               ListBox.Clear
           END SUB

           ClearButton.OnClick = ClearButtonClick
Whew, if you counted all the lines, it is well below 100! Our application is now complete, you can play with it, add stuff to it, and generally learn from it.

4.4 Source code listing, in its entirety
DIM MainForm AS QFORM
DIM NameEdit AS QEDIT, AddrEdit AS QEDIT, _
    CityEdit AS QEDIT, PhEdit AS QEDIT
DIM NameLabel AS QLABEL, AddrLabel AS QLABEL, _
    CityLabel AS QLABEL, PhLabel AS QLABEL
DIM ListBox AS QLISTBOX
DIM AddButton AS QBUTTON, ClearButton AS QBUTTON

SUB AddButtonClick
  IF ListBox.ItemCount > 0 THEN
    '-- Add a nice separator
    ListBox.AddItems "--------------------------------"
  END IF
  ListBox.AddItems NameEdit.Text, AddrEdit.Text, _
                   CityEdit.Text, PhEdit.Text
END SUB

SUB ClearButtonClick
  ListBox.Clear
END SUB

NameLabel.Parent = MainForm
NameLabel.Caption = "Name:"
NameLabel.Top = 13
NameLabel.Left = 25
AddrLabel.Parent = MainForm
AddrLabel.Caption = "Address:"
AddrLabel.Top = 38
AddrLabel.Left = 25
CityLabel.Parent = MainForm
CityLabel.Caption = "City:"
CityLabel.Top = 63
CityLabel.Left = 25
PhLabel.Parent = MainForm
PhLabel.Caption = "Phone #:"
PhLabel.Top = 88
PhLabel.Left = 25

NameEdit.Parent = MainForm
NameEdit.Left = 70
NameEdit.Top = 10
NameEdit.Width = 230
AddrEdit.Parent = MainForm
AddrEdit.Left = NameEdit.Left
AddrEdit.Width = NameEdit.Width
AddrEdit.Top = 35
CityEdit.Parent = MainForm
CityEdit.Left = NameEdit.Left
CityEdit.Width = NameEdit.Width
CityEdit.Top = 60
PhEdit.Parent = MainForm
PhEdit.Left = NameEdit.Left
PhEdit.Width = NameEdit.Width
PhEdit.Top = 85

AddButton.Parent = MainForm
AddButton.Left = 70
AddButton.Top = 115
AddButton.Width = 110
AddButton.Caption = "&Add to Database"
AddButton.OnClick = AddButtonClick
ClearButton.Parent = MainForm
ClearButton.Left = 190
ClearButton.Top = 115
ClearButton.Width = 110
ClearButton.Caption = "&Clear Database"
ClearButton.OnClick = ClearButtonClick

ListBox.Parent = MainForm
ListBox.Top = 150
ListBox.Left = 70
ListBox.Width = 230
ListBox.Height = 150

MainForm.Center
MainForm.Caption = "My First Application"
MainForm.Height = 340
MainForm.Width = 350
MainForm.ShowModal


Chapter 5: Introduction to forms

Rapid-Q Documentation by William Yu (c)1999 Chapter 5

5. Introduction to forms

The basic concept of forms are introduced in this chapter. The example program in the previous chapter will definitely help you understand the concepts a little better. I will use the terms form and windows interchangeably.

5.1 What's in a form?
A form (or window), is a generic container that can be displayed on your desktop. It is like a panel (see QPANEL). A form can have many appearences. In Rapid-Q, the only forms which are valid, are:
The default form is bsSizeable. What exactly is bsNone good for? Games :-) That's right, if the form is maximized, you can utilize the whole screen for your game. It can serve other purposes as well... MSIE uses it for a full screen web browser. Looks ugly though. If you're not sure how all these variables come from, take a look at RAPIDQ.INC bsNone = 0, bsSingle = 1, etc... these variables just make programming easier, so you don't need to remember the exact number, just the variable name to use.
          $INCLUDE "RAPIDQ.INC"

          DIM Form AS QFORM
          Form.BorderStyle = bsDialog
          Form.ShowModal
For bsSingle, the form looks exactly like bsSizeable, except that you cannot resize the form. In many cases, the only two useful forms are bsSizeable, and bsDialog.

5.2 Adding components to a form
If you followed closely the example in the previous chapter, you can add components onto the form simply by assigning the Parent property for that component.
        DIM Form AS QForm
        DIM Button AS QButton

        Button.Parent = Form       '' Add button to form
If you're wondering why that is, just consider a program with multiple forms. All visible components must have a Parent property. Components, such as QMENUITEM, or QTIMER do not have a parent property. Even though QMENUITEM is considered a "visible" component, its parent can only be a QMAINMENU or QPOPUPMENU. But instead of assigning a Parent property, you have to Add/Insert the items to the menu. If no Parent is given, the component remains hidden. In the case of QCANVAS or QIMAGE, you will get error messages if you try to draw on the components. This is because you can't draw on something not visible. In most cases, the Parent property should be the first property you assign before doing anything else. To hide components, you can use the Visible property.

5.3 Tracking the mouse position on a form
Sometimes it's useful to track the mouse position on a form, for an example, see the TIC-TAC-TOE game demonstration. Whether your mouse moves across a component, it doesn't matter, the mouse will be tracked relative to the position of the form. Multiple forms are handled the same way, Rapid-Q will recognize the new form, and the mouse will track its position relative to that form. To get these values, just use the internal variables MouseX, and MouseY
      X = MouseX
      Y = MouseY
Remember, the mouse position is relative to your form, not your entire desktop. So MouseX = 0, and MouseY = 0 means the upperleft hand corner of your form.

5.4 Special events for forms
There are a few special events that only forms can handle. The most important is the OnResize event. This occurs whenever the user has clicked on the maximize button or manually resizes your form. Your program should almost always capture this event and update the size of your controls appropriately. Imagine if your MSIE browser window was 320x200, and when you resized the application to 640x480, the browser window was still 320x200. Looks ugly, because it is. If you don't want anyone resizing your form, just use a different BorderStyle as mentioned earlier.
Another special event is key presses. I suggest using OnKeyDown instead of OnKeyPress. The difference is that OnKeyDown can handle extended keys, and can detect Shift, Alt, and Ctrl states. If your application does not need to handle extended keys, then by all means, use OnKeyPress instead. Keyboard handling is useful for many applications that require it, like a typing tutor, games, etc... What might be confusing is the fact that OnKeyPress and OnKeyDown return extra parameters that you can use. This deviates from most of our understanding of Events. So far we've only covered simple events that don't require any special processing.
      SUB AddButtonClick
        '' Do stuff
      END SUB

      AddButton.OnClick = AddButtonClick
A simple click only passes a simple message to our button control, telling it that a click was received. Well, for key presses, this is more complicated. It's not enough to say that a key was pressed, we have to know what key was pressed, so we have to grab this extra message.
      SUB KeyPressed(Key AS WORD)
        '' Do stuff
        PRINT Key
      END SUB

      Form.OnKeyPress = KeyPressed
The key pressed is returned in the variable Key. You can name this anything you want, but your SUB must have at least that one parameter. Rapid-Q won't complain if you added more parameters, nor does it complain if you don't supply any parameters. It's up to you to make sure. For OnKeyDown, there's two parameters that are passed:
      SUB KeyDown(Key AS WORD, Shift AS INTEGER)
        '' Do stuff
        PRINT Key;" ";Shift
      END SUB

      Form.OnKeyDown = KeyDown
There are 3 shift states, ShiftDown, AltDown, and CtrlDown. Be careful of the ShiftDown state. Unlike OnKeyPress which handled all the Shiftdown states for you, OnKeyDown will not. This means if you pressed SHIFT+i you'll have to go UCASE$(Key). Extended keys are much different in Rapid-Q than what you'd expect in a QBasic program. For example, in QBasic, the arrow keys are easy to decode:
    DO
      A$=INKEY$
      IF A$=CHR$(0)+"H" THEN PRINT "Up arrow key pressed"
    LOOP
By using the OnKeyDown the virtual key code is returned, which is not a 2 byte code. The up arrow is Key = 38, left arrow Key = 37, right arrow Key = 39, and down arrow Key = 40

5.5 Dialog Boxes
A special type of form is a simple dialog box. Dialog boxes are usually extra interfaces to your main form. You don't usually implement a dialog box as your main form. For example, consider a main form where you have 3 choices:

Well, for each choice (except maybe for the last), you should create dialog boxes to handle the user's input. When the user clicks on the first button, a dialog box like this should appear:

The nice buttons are custom buttons. See RAPIDQ.INC for all the values.
     OKButton1.Kind = bkOK
     CancelButton1.Kind = bkCancel
Fine, but how do you know if the user pressed OK or CANCEL? There's actually two ways to do this, both involve using the ModalResult property. Remember how you called your dialog box:
   IF Dialog1.ShowModal = mrOK THEN
      '' User pressed OK
   ELSE
      '' User cancelled
   END IF
The ModalResult is a property of both the QButtons, and QForms. When we did this:
     OKButton1.Kind = bkOK
We also automatically did this:
     OKButton1.ModalResult = mrOK
What this means is that whenever you pressed the OK Button, the ModalResult returned is mrOK. This result automatically closes your Dialog1 form as well. Another less elegant approach is just to assign the ModalResult to your form. For example, let's assume this scenario:
      SUB ButtonClick
          Dialog1.ModalResult = mrOK
      END SUB

      OKButton1.ModalResult = mrNone   '' No result
      OKButton1.OnClick = ButtonClick
In the above scenario, clicking on the button will transfer control to the ButtonClick SUB. In this SUB, the ModalResult property of the Dialog1 form is set, which is doing exactly the samething as our previous example.

5.6 Using the CREATE Method
In most cases, using CREATE is preferred over DIM, this is because it saves you a lot of typing, and provides a cleaner look to your source code. For starters, let's just look at how much typing it could save you:
        DIM MainForm AS QForm
            MainForm.Left = 100
            MainForm.Top = 50
            MainForm.Height = 300
            MainForm.Width = 400
            MainForm.Caption = "Hello world!"
Well, here's what the above code looks like using CREATE:
        CREATE MainForm AS QForm
           Left = 100
           Top = 50
           Height = 300
           Width = 400
           Caption = "Hello world!"
        END CREATE
As you can see, you don't need to type MainForm each time, since the compiler will know exactly how you want the fields to be parsed.

5.7 Embedding CREATEs
Here's where using the CREATE method over DIM will save you time and confusion. This is what I mean about "encapsulation" of your controls:
        CREATE MainForm AS QForm
           Center
           CREATE Button1 AS QButton
              Left = 10: Top = 10: Height = 20: Width = 20
           END CREATE
           ShowModal
        END CREATE
You'll probably notice that we don't need the Parent property. This is because the compiler realizes that you want to include a Button to the MainForm (due to an embedded CREATE), so it automatically generates a Button1.Parent = MainForm for you. As you can also see, it looks much better, and you can visually see what components belong to want form/container. Rapid-Q can store up to 25 layers, in the above example, we only need one layer. I don't believe people need more than 4 or 5 layers (at most), but I set 25 as the maximum just to please the 1% who really want it. As you maybe able to figure out, components without a Parent property (non-visible components) are invalid in an Embedded CREATE.

5.8 Creating Menus
Creating menus using the CREATE method is no different:
        CREATE MainForm AS QForm
           Center
           CREATE MainMenu AS QMainMenu
              CREATE FileMenu AS QMenuItem
                Caption = "&File"
                CREATE OpenItem AS QMenuItem
                  Caption = "&Open"
                END CREATE
                CREATE SaveItem AS QMenuItem
                  Caption = "&Save"
                END CREATE
              END CREATE
           END CREATE
           ShowModal
        END CREATE
Instead of the Parent property, we're saving ourselves from using AddItems. This is probably easier to understand than using DIM to define all your menus.


Chapter 6: Writing Console Applications

Rapid-Q Documentation by William Yu (c)1999 Chapter 6

6. Writing Console Applications

Console applications are as easy to create as Windowed applications. Whenever you feel like creating text-based applications, just compile as CONSOLE instead of GUI. As you may find, it's easier to learn the fundamentals of Rapid-Q (or the BASIC language in general) by creating simple console applications and testing your routines. It can also act as a debugging tool for your GUI applications.

6.1 Overview of console functions
A console application is a text-based application capable of writing to and accepting input from the console. A console application, in Rapid-Q, consists of one visible screen, and 7 off screen buffers. Here's an overview of some console functions:
   CLS    - Clear console screen
   PRINT  - Write output to screen (visible/offscreen)
   INPUT  - Accept input from user
   PCOPY  - Used to copy to and from the screen buffers
   LOCATE - Position cursor
   POS(0) - Get current cursor column
   CSRLIN - Get current cursor row
   COLOR  - Change color attribute of text
   POKE   - Put attribute/char on screen
   PEEK   - Get attribute/char from screen
   SLEEP  - Delay
   INKEY$ - Non-blocking keyboard check
These functions mimic the ones you would see under QBasic. PEEK and POKE operate the same way, SLEEP is more precise than QBasic's (ie. you can specify a fraction of a second, like in PowerBASIC). Notice that you don't require any DEF SEG statements, since this is Windows.

6.2 Hello world example
Rapid-Q is like most BASIC languages, you can create a hello world program in just one line:
     PRINT "Hello World!"
Compile and run, you've just created your first useless console application for Windows! Let's move on to something more interesting, copying to and from screen buffers.
   CLS
   PRINT "This is page 1"

   PCOPY 0, 1    '-- Copy visible page 0, to off screen page 1

   CLS
   PRINT "Press any key to see page 1"

   DO:LOOP UNTIL INKEY$<>""

   PCOPY 1, 0    '-- Copy off screen page 1, to visible page 0
As you can see, our visible page is always 0. Our off screen pages range from 1-7. PCOPY just copies the whole buffer and places it into another. You can even copy an off screen buffer to another off screen buffer like so:
    PCOPY 1,5
The contents in buffer 1, is now copied to buffer 5. There's nothing new introduced here that you wouldn't have found in QBasic. One new feature is that you can now write to any offscreen page:
   PRINT #1, "Hi World!"       '-- Write to page 1
The above example will write the string "Hi World!" to the offscreen page 1. Make sure you use the pound sign '#' else it will be treated as a number. To see it, use PCOPY 1, 0. LOCATE and COLOR have the same effect on the offscreen pages. You can also PEEK from and POKE to the offscreen pages, just supply an additional parameter, the first being the page number to write/read from.

6.3 Using PEEK and POKE
If you've never used PEEK and POKE before, it's not a big deal. In Rapid-Q, PEEK and POKE have the same functionality of QBasic (except for the additional feature to PEEK/POKE to any offscreen page). Addresses range from 0 to 3999. This is because the screen size is restricted to 80x25 in Rapid-Q. But if 80x25 = 2000, what's the extra 2000 for?
    POKE 0, ASC("A")
    POKE 1, 15
If you run this code, you'll see a white letter 'A' displayed at the upperleft corner of your console. One thing you should note is that a "byte" on the screen contains a character and its attribute. All even numbered address contain the character, all odd numbered addresses contain the attribute. If you don't exactly know what an attribute is, it's just a combination of the foreground color and background color all in one byte (8-bits). The lower 4 bits is reserved for the foreground color, and the upper 4 bits is reserved for the background color. If you know anything about bits and bytes, you can easily calculate the attribute:
    B? = &H07       '-- 0 = background, 7 = foreground
Yes, you can have high intensity background colors. Blinking is not supported yet.

6.4 Trapping Extended Keys
It is not possible to trap extended keys using INKEY$ (Windows only, you can trap extended keys under Linux/Unix). There is a dirty trick you can use to trap any key combination, but it's not something you'd normally want to do. Since QForm has the event OnKeyDown, we can trap all our keys that way. The only problem is that the form must be visible for events to take place. We can hide the form by setting the dimensions to zero, and BorderStyle to bsNone. Note, sample only, there's no useful purpose for this:
   $APPTYPE CONSOLE
   $INCLUDE "RAPIDQ.INC"

   DIM Form AS QForm

   SUB KeyDown(Key AS BYTE, Shift AS INTEGER)
     PRINT "Key: ";Key; "  Shift: "; Shift
   END SUB

   Form.OnKeyDown = KeyDown

   Form.BorderStyle = bsNone
   Form.Width = 0
   Form.Height = 0
   Form.Enabled = True
   Form.Visible = True

   DO
     DoEvents       '-- Process events
   LOOP
You'll probably notice that the console screen is disabled, but normal input and output can still continue. Just type some keys to test it out. Don't click on the disabled console screen (until you feel like stopping), else the program stops working. Press CTRL+C to exit the program.

6.5 Mixing CONSOLE with GUI
As you've noticed in the above example, we've mixed some CONSOLE operations with GUI ones. This is perfectly valid as long as you've compiled your application as CONSOLE. Under Linux/Unix there are some strange differences, please refer to the compatibilty guide for more information. For example, a GUI application for Linux/Unix can perform some CONSOLE operations such as PRINT, INPUT, and CLS without being compiled as CONSOLE.

6.6 Linux/Unix Console
Since most terminals are different, some console features will not work. If your terminal does not support color, none will be displayed. You don't need to worry about these issues, as Rapid-Q performs all proper error checking for you. The same can be said for extended keys, some terminals don't support certain keys. However, most terminals do support the arrow keys and Page up/down keys. You're almost guaranteed that those keys will work for most terminals.


Chapter 7: Introduction to streams

Rapid-Q Documentation by William Yu (c)1999 Chapter 7

7. Introduction to streams

Rapid-Q supports file streams instead of the standard OPEN command used in BASIC. It has the same functionality, but is called differently. What's great about streams is that it's unlimited in size, and you can copy to and from different streams (ie. File to Memory).

7.1 File streams
File streams are used to create, read and write to files. All streams are opened as binary, with no locking capabilities (ie. all files you open are shared). Please familiarize yourself with these file modes:
     fmCreate    - Create file (read/write), truncate if file exists
     fmOpenRead  - Open file for reading only
     fmOpenWrite - Open file for writing only
     fmOpenReadWrite - Open file to reading & writing
To open a file you need to pass the filename, and provide one of the above file modes.
     DIM File AS QFileStream

     File.Open("Test.txt", fmOpenRead)
This will open Test.txt for reading only. To read data, you use the methods ReadNum and ReadStr. See RAPIDQ.INC for valid numbers.
     PRINT File.ReadNum(Num_SINGLE)   '-- Read 4 bytes as a SINGLE number
     PRINT File.ReadStr(1024)         '-- Read 1024 bytes
You must implement your own ReadLine and WriteLine methods, but it's only a formality. After you're done with the file, make sure you close the handle. You can then reuse your file stream and open up another file. Since there is no EOF function, to test if you've reached the end of the file, you'll have to compare File.Position with File.Size. So long as File.Position is less than File.Size, you haven't reached the end of the file. There are actually 2 ways to test if a file exists:
     IF FileExists("Test.txt") <> FALSE THEN
       File.Open("Test.txt", fmOpenRead)
     END IF
However, it's better just to cut this down to:
     IF File.Open("Test.txt", fmOpenRead) = FALSE THEN
        ShowMessage("Could not open file")
     END IF
File.Open will return a non-zero number if the file was successfully opened, 0 otherwise.

7.2 Memory streams
A memory stream is created whenever you DIM it. It's similar to file streams, all the methods are the same, such as ReadNum, WriteNum, etc... The only difference is that memory streams are stored in memory, which can grow/shrink with no upper bounds. It's even possible to store arrays of numbers in memory stream (see ARRAYS.BAS example). Memory streams serve many purposes, let your imagination take over. One useful purpose might be to store temporary data, such as copying a file to a memory stream and manipulating the data that way. So how can I copy from one stream to another? Quite easily, you can copy between different streams (ie. File to Memory) or of the same kind (ie. Memory to Memory).
    DIM File AS QFileStream
    File.Open("test.txt", fmOpenRead)

    DIM Memory AS QMemoryStream
    Memory.CopyFrom(File, File.Size)  '-- Copy everything
As you can see, we've just copied the entire contents of our file "test.txt" to our memory stream. Now you can manipulate your memory stream without affecting the file.


Chapter 8: Using Image Resources

Rapid-Q Documentation by William Yu (c)1999 Chapter 8

8. Using Image Resources

Most Windows programming languages offer support for .RES (Resource) files. A Resource file is nothing more than a collection of images (plus resource strings and data). In this chapter, you'll learn about Image lists, how to embed resources in your executable, and how to properly use them in your applications.

8.1 Supported RESOURCES
Rapid-Q only "directly" supports image resources, ie. just Icons and Bitmaps. Under Linux/Unix, resources has not yet been implemented. So what exactly is the difference between loading a picture at run-time, or loading resource handles? For one thing, whenever you declare a resource handle, that picture file is automatically embedded within your executable. Here's an example:
     $RESOURCE ICO_TEST AS "C:\ICONS\TEST.ICO"

     DIM Form AS QForm

     Form.ICOHandle = ICO_TEST
     'Form.Icon = "C:\ICONS\TEST.ICO"
The file C:\ICONS\TEST.ICO is embedded within your executable, which means you don't need to include TEST.ICO if you plan on distributing your .EXE program. Rapid-Q doesn't generate .RES files for you, and it can't handle other people's .RES files either. Most languages you'll see have a .RES file, but you can't use them in Rapid-Q, you'll have to extract the pictures within it, and use the $RESOURCE handle directive to include them in your application. It is also possible to do this:
     Form.ICOHandle = ICO_TEST

     DIM Image AS QImage

     Image.Icon = Form.Icon
Image.Icon normally accepts a string value, but if no string is specified, it'll read the previously cached icon. In this case, we're loading Form.Icon to our "cache" and Image.Icon will read from it. So what does this do?
     Image.Icon = Form.Icon + Form2.Icon
This will load Form2.Icon into the cache, so Image.Icon will copy Form2.Icon. However, please note that you can't assign Icon Handles, for example:
     Image.IcoHandle = Form.IcoHandle
The parser will try to look for a resource handle, but won't find one.

8.2 Introduction to Image lists
You may want to refer to the Appendix on the properties, and methods of QImageList. An Image list is an array of icons and/or bitmaps. They are ordered from 0 to N. The first image you add will be index 0, the next index 1, etc... an image list store images of FIXED width and height. Anytime you change the Width or Height property, you're ultimately clearing the entire array. Note, this does not mean you can't add a 100x100 BMP file when your image list width is 32. It just means your BMP will be resized, whether you wanted that or not.
    DIM ImageList AS QImageList
        ImageList.Width = 32
        ImageList.Height = 32
        ImageList.AddICOFile("app.ico")
        ImageList.AddBMPFile("app.bmp", 0)
You can add icons or bitmaps in any order. As before, you can also add images from the "cache" if no filename was specified. As before:
    ImageList.AddICOFile(Form.Icon)
    ImageList.AddICOFile(ImageList.GetICO(0))

8.3 Other kinds of Resources
You can include any kind of resource to your Rapid-Q program, but how can you use these other kinds? For example, if I include a .WAV file as a resource, how can I use it in my PLAYWAV routine? Well, since PLAYWAV doesn't take resource handles, you'll have to extract your resource. You're probably wondering what's the point of doing that, why not just include the .WAV file in your distribution and forget about it. Well, in essence this is what you're doing, but since resources are bundled within your .EXE, it can provide an illusion. Obviously this technique fails miserably if your application is running off a non-writable disk drive, such as a write-protected floppy disk or CD-ROM, but there's always some tricks you can use (ie. extract to the user's WINDOWS directory or some other writeable drive). Okay, enough of the introduction, how does one extract resources?
    $RESOURCE Bomb_WAV AS "BOMB.WAV"

    ExtractResource(Resource(0), "temp.wav")
    PlayWav("temp.wav", 1)    '-- 1 = background play

    SLEEP 5                   '-- Wait until wav is finished
    KILL "temp.wav"           '-- Remove the file
As you can see, we can easily extract a resource, and after we're done using it, we can simply delete them. Unfortunately with playing .WAV files, you'll have to wait a while until it's finished playing then you can permanently remove them. There are a wide range of uses for extracting resources, you can even use this technique in an installation program. For more information on EXTRACTRESOURCE, RESOURCE, and RESOURCECOUNT, please see Appendix C: Other reserved keywords


Chapter 9: SUBI, FUNCTIONI, and DLLs

Rapid-Q Documentation by William Yu (c)1999 Chapter 9

9. SUBI, FUNCTIONI, and DLLs

You'll learn all there needs to know about creating your own SUB/FUNCTIONs with variable number of parameters. If you know a little about C, you'll probably know about the most popular command printf. Well, it's actually possible to implement your own printf in Rapid-Q!

9.1 SUB/FUNCTIONs with variable parameters
Traditional SUBs or FUNCTIONs have a fixed number of parameters we can pass, but SUBI and FUNCTIONI can accept an infinite number (255) of variable parameters. You're probably wondering how we can retrieve these parameters, well, they are actually stored in an internal stack. So what you'll have to do is probe this stack for the correct parameter. Here are the keywords used to do that:
   ParamStr$()   - Array of string parameters
   ParamVal()    - Array of numeric parameters
   ParamValCount - Number of numeric parameters passed
   ParamStrCount - Number of string parameters passed
As a simple example, we'll just test to see that it works:
    SUBI TestSUBI (...)
       PRINT "String Parameters:  "; ParamStrCount
         FOR I = 1 TO ParamStrCount
           PRINT I;" "; ParamStr$(I)
         NEXT I
       PRINT "Numeric Parameters: "; ParamValCount
         FOR I = 1 TO ParamValCount
           PRINT I;" "; ParamVal(I)
         NEXT I
    END SUBI

    TestSUBI "Hello", 1234, "Hmmm", "Yeah...", 9876, 1*2*3*4, UCASE$("Last one")
You'll probably notice that the ParamStr$() and ParamVal() arrays aren't zero-based (ie. their first value starts at 1). This may seem strange, since everything in Rapid-Q is zero-based. Anyway, besides that, something equally strange is the use of (...) in replace of parameter names. It doesn't really matter what you put in the brackets, as long as it's a valid token (one word). Try creating a FUNCTIONI, it's no different from creating a standard FUNCTION except you replace your formal parameter names with (...).

9.2 More on FUNCTIONI
To expand our knowledge, let's do more examples, here's one that will find the maximum number from the parameters you provide it.
   FUNCTIONI FindMax (...) AS DOUBLE

     DIM Largest AS DOUBLE
     DIM I AS BYTE

     Largest = -999999999999

     FOR I = 1 TO ParamValCount
       IF ParamVal(I) > Largest THEN
          Largest = ParamVal(I)
       END IF
     NEXT

     FindMax = Largest         ' or Result = Largest
   END FUNCTIONI
The function goes through the entire list of numeric parameters and checks which one is the largest. Any string parameters are properly ignored. Now let's test it:
   PRINT "Largest number is: "; FindMax(523, 12.4, 602, 45, -1200)
   PRINT "Largest number is: "; FindMax(523, 12.4, FindMax(602, 45, -1200))
You can comfortably embed your FUNCTIONI if you like. There's really nothing to it. Just remember the keywords you need to access the internal stack, and away you go!

9.3 Introduction to DLLs
Before we get into this deep subject, please note that Rapid-Q only handles simple DLLs. That is, it can only pass at most 2 parameters. (Actually, by October 7, 1999, Rapid-Q can now handle any number of parameters, but the most stable still remains 2). Which means you'll have a hard time accessing the Windows API (DLLs) with Rapid-Q without another level of indirection. It's possible to write C (or other) code to interface with Rapid-Q's lack of DLL support. For example, write some C code that accesses the Windows API, and create a DLL, which Rapid-Q can call, from it. This is probably too much work, but could be your last resort. Anyway, what is a DLL? It's a Dynamic Link Library. DLLs can only be dynamically linked at run-time (ie. executed at run-time).

9.4 How to call a DLL
There is an example called DLL.BAS included in your Rapid-Q distribution. Included is also a DLL called PASCAL.DLL. You may want to take a look at it. To call DLLs in Rapid-Q is almost identical to the way you call DLLs in PowerBASIC or VisualBASIC. It may look nasty, but I've decided to conform to that standard... One thing to note is that CASE MATTERS! Yes, that's right, if you miscapitalized your function, ka-boom! Oops, not to confuse you even more, but there's actually 2 functions. One which you will call in your program, and the other is the one contained in the DLL. These two functions/subs must have matching parameters, or ka-boom!
    DECLARE SUB Test LIB "TEST.DLL" ALIAS "MyFunc" (S AS STRING)
So you must be wondering, which is case sensitive, Test or MyFunc. Well, Test is the one you'll be calling in your own program, so you know that can't be it, MyFunc is the one contained in the DLL, so make sure you typed that in correctly! The above SUB will point to the memory address of your DLL (when loaded), and execute the code within. As you can see, there's only one parameter for our MyFunc routine. There are only 2 extra keywords introduced here, LIB and ALIAS. After LIB should be a string corresponding to the path of your DLL. If your DLL resides in your $PATH setting, you don't need to specify any path (ie. if your TEST.DLL resides in C:\WINDOWS\SYSTEM). The second keyword ALIAS is to specify the function/subroutine you can execute in that DLL. Make sure you check your case, this is very important. If you're not sure of the case, you can use a DLL viewer (such as Quick View, more on this later). What are the valid datatypes to pass?
SHORT/WORD, INTEGER/LONG/DWORD, DOUBLE, STRING, QRECT, QNOTIFYICONDATA, and more to be expanded...
Unlike some implementations which force you to pass your STRING as a pointer, Rapid-Q will do all this for you, so you need not worry. Whenever you see LPZSTR as a parameter, that just means Long Pointer Zero-Terminated String. You can safely pass any string variable. You may notice that some BASIC languages (like VB) will ignore ALIAS whenever the function matches the same function you're declaring. For example:
    DECLARE SUB MyFunc LIB "TEST.DLL"
As long as your function matches that of the DLL function, you can ignore using ALIAS. However, this DOES NOT apply to Rapid-Q, you can't do this, so don't even try.
Calling a DLL function or calling your own function is exactly the same, there's nothing more you need to know:
    MyFunc("Hello")

 9.5 Using Quick View
As mentioned before, if you're not sure of the exact case of your function, it's a good idea to take a look using Quick View.
Quick View is included with Windows (you don't need to download it). To invoke Quick View, load up Windows Explorer (or click on "My Computer"), then find a .DLL file, right click on it, and select Quick View from the menu. Look for an Export Table, that's where you'll find all the available functions. There are probably better DLL viewers available, but I won't advertise them here. Most of the time, Quick View is all you'll need.

9.6 Writing your own DLLs
As of this writing, it's not possible to write DLLs in Rapid-Q. Most languages are capable of creating DLLs, just remember the special cases if you want it to be callable from Rapid-Q: the stability and only simple data types, SHORT, WORD, INTEGER, LONG, DWORD, DOUBLE, STRING, QRECT, QNOTIFYICONDATA.

9.7 Using unsupported types in DLL call
THIS SECTION IS NULL AND VOID WITH THE INTRODUCTION OF STRUCT, BUT CAN STILL BE USED IF YOU LIKE. Rapid-Q has a different storage mechanism for user defined TYPEs which renders it useless for DLL calls that require certain TYPE parameters. However, all is not lost. There is a cheap workaround which works just fine, but does need a little getting used to. DLL functions that require TYPE parameters need to be passed a pointer to that TYPE, so how is this accomplished? Let's look at an example of a DLL function which requires a TYPE parameter:
    DECLARE FUNCTION GetWindowRect LIB "USER32" ALIAS "GetWindowRect" _
                     (hWnd AS LONG, lpRect AS RECT) AS LONG
RECT is a structure of the form:
    TYPE RECT
        Left AS LONG
        Top AS LONG
        Right AS LONG
        Bottom AS LONG
    END TYPE
Naturally, you would like this to work:
    DIM R AS RECT

    GetWindowRect(MainForm.Handle, R)
YES, THIS WORKS NOW. However, Rapid-Q stores user defined types noncontiguously, ie. not as one whole block as required by the DLL call, so this call is invalid. So what does work? A simple workaround is necessary, using the ever useful QMEMORYSTREAM component:
    '' Notice the change in lpRect
    DECLARE FUNCTION GetWindowRect LIB "USER32" ALIAS "GetWindowRect" _
                     (hWnd AS LONG, lpRect AS LONG) AS LONG

    DIM R AS RECT
    DIM M AS QMEMORYSTREAM

    M.WriteUDT(R)
    GetWindowRect(MainForm.Handle, M.Pointer)
    M.Position
    M.ReadUDT(R)
The first thing we do is change the parameters of the DLL Function. We just changed the type of lpRect to LONG. This is because we want to pass a pointer (which is just a number). Here we use QMEMORYSTREAM to store the user defined type (using M.WriteUDT) in one contiguous block for our DLL call. All we have to do is pass the pointer to this block of memory and the DLL will read from this memory location. After calling the function we should retrieve the returned data (if necessary, in this case GetWindowRect returns the rect structure of the Window). This is rather simple, but what if there are nested TYPEs within a TYPE?
     TYPE Struct1
         A AS INTEGER
     END TYPE

     TYPE Struct2
         S AS Struct1
         I AS INTEGER
     END TYPE
If a DLL call requires a TYPE, which may have nested TYPEs, then you can do the same kind of conversion:
     TYPE Struct1
         A AS INTEGER
     END TYPE

     TYPE Struct2
         S AS LONG
         I AS INTEGER
     END TYPE

     DIM S1 AS Struct1
     DIM S2 AS Struct2

     DIM M1 AS QMEMORYSTREAM
     DIM M2 AS QMEMORYSTREAM

     M1.WriteUDT(S1)
     S2.S = M1.Pointer
     M2.WriteUDT(S2)

    '' Call DLL function...
Now the last case we have to consider is strings within TYPEs. We can't just declare a string anymore, we have to declare a pointer to a string, for example:
     TYPE TStruct
         ST AS STRING
         Other AS INTEGER
     END TYPE
This would not be valid since ST would be passed by value (in which case it can consume any number of bytes in memory). However, most DLL calls want strings passed by reference (ie. just give it the pointer to the string). A conversion is necessary, using VARPTR:
     TYPE TStruct
         ST AS LONG
         Other AS INTEGER
     END TYPE

     DIM Struct AS TStruct
     DIM S AS STRING

     S = SPACE$(100) '' Allocate some space for string
     Struct.ST = VARPTR(S)

    '' To get back the string use VARPTR$
    S = VARPTR$(Struct.ST)
Please note that this string conversion is only necessary for TYPEs and not necessary for normal DLL calls. For normal DLL calls which have STRING as parameters, just pass the string and not the pointer, since Rapid-Q will translate this automatically for you. You can, of course, do the conversion yourself, just remember to change the STRING parameter to something like LONG, and pass VARPTR(S$) instead of the actual string S$.


Chapter 10: Creating Custom Components

Rapid-Q Documentation by William Yu (c)1999 Chapter 10

10. Creating Custom Components

Creating your own custom components may be helpful when you want to have a custom look and feel to your forms (among other things). For example, instead of the the standard Windows checkboxes, you may want to create diamond like checkboxes (complete listing at end of chapter). By the end of this chapter, you'll be able to create your own fully reuseable components, even custom forms! We will start with a simple example of a diamond checkbox.

10.1 Introduction to object creation
You won't exactly be reinventing the wheel when you create your own custom objects. The way you create your own objects is to EXTEND a component (like QCanvas). What this means is that you'll inherit all its properties, methods, and events. After that, you may choose to override its properties, and/or methods, or create new properties and methods. The concept is really easy to understand, once you get the hang of things. Rapid-Q's component creation method doesn't resemble any language per se, but it doesn't look too foreign either. Since object creation is not something newbies should step right into, you should familiarize yourself with the concept of properties, methods, and events. You also need a good understanding of TYPEs, since events/methods within types is something new. Do not get confused with other OOP languages, Rapid-Q does not adopt overloading, protected or virtual members. Rapid-Q's OCC (Object Component Creation) paradigm doesn't model any language, but does take several ideas from other OOP languages like Delphi, C++ and Java.

10.2 Extending QCanvas
QCanvas is a very useful "blank sheet" component. It allows you to draw whatever you want on it, making this the most useful component to extend. First of all, how exactly do we extend it?
     TYPE QDiamondBox EXTENDS QCanvas
     END TYPE
Wow, that was easy. The above code is perfectly valid, although it doesn't do anything useful. What that did was create a new object called QDiamondBox which inherited all the properties, methods, and events of QCanvas. So we can now DIM it and assign values to it:
     DIM DBox AS QDiamondBox
         DBox.Top = 10
Okay, that's not very useful. Sometimes we would like to add properties to our existing component, and in our above example, we probably need a Caption property, and maybe a Checked property (since we're going to implement a checkbox type component). Adding properties is nothing new:
     TYPE QDiamondBox EXTENDS QCanvas
        Caption AS STRING
        Checked AS INTEGER
     END TYPE
As you can see, it looks like any UDT (user defined types) that most BASIC programmers are familiar with. So now we've added 2 additional properties to our new component, we'd access them like we would any property. Okay, but what if you want the values to be initialized to something when it gets created? Not a problem, you don't need a constructor procedure like in C++, you just embed this information like so:
     TYPE QDiamondBox EXTENDS QCanvas
        Caption AS STRING
        Checked AS INTEGER

        CONSTRUCTOR
          Caption = "DiamondBox"
          Checked = 0
        END CONSTRUCTOR
     END TYPE
After each DIM (that is, when you create the object), the default values are initialized. Rapid-Q does not require DESTRUCTORs though, as everything is automatically cleaned up for you when your program terminates. If you're not convinced this worked, test it out:
     DIM DBox AS QDiamondBox

     ShowMessage(DBox.Caption)
If it doesn't return 'DiamondBox' then something is wrong, check your spelling, and turn $TYPECHECK ON.

10.3 Adding/Overriding Methods
For users who are familiar with OOP, there is no such thing as protected members in Rapid-Q, all methods (including properties) are virtual (ie. they can be overridden). The concept of overriding properties or methods is simple enough, instead of using the inherited properties, we can just redefine them instead.
     TYPE QDiamondBox EXTENDS QCanvas
        Left AS STRING
        Top AS BYTE

        SUB Pset
        END SUB
     END TYPE
In the above example, we've overriding 2 properties of QCanvas, and 1 method. Overriding methods and properties have many useful purposes. Consider a filter listbox. You can override the AddItems method, and create one yourself, but filtering out certain keywords you don't want included. It's also useful when you're porting your Windows code to Linux and vice versa. This way, you can have your own "standard" template for both versions. In any event, we won't cover this topic any further. Let's now move on to creating new methods for our components:
     TYPE QDiamondBox EXTENDS QCanvas
       Caption AS STRING
       Checked AS INTEGER

       FUNCTION TextSize AS INTEGER
         Result = LEN(QDiamondBox.Caption)
         'QDiamondBox.TextSize = LEN(QDiamondBox.Caption)
       END FUNCTION
     END TYPE
The above example is a good place to start. We've just defined a new method for our QDiamondBox component. As you've noticed, we have to embed our FUNCTIONs or SUBs in our TYPE declaration. This is called INLINE code, you should be familiar with this if you've used C++ or any other OOP language. Rapid-Q requires INLINE code, you cannot define your SUB and then have the SUB sitting outside our TYPE definition. Okay, the only thing that stands out is QDiamondBox.Caption, which does what exactly? Well, you're probably wondering why we couldn't just say
      Result = LEN(Caption)
Well, this doesn't help, since in our FUNCTION, we could have easily added
      DIM Caption AS INTEGER
Then Rapid-Q would be confused... huh? Which one should I use, the local Caption variable, or the new property one? To ease the pain, when you want to use a property, or method you must also reference them as you would normally. Our object in this case is QDiamondBox, and we want to reference the property Caption. Since the above method is pretty much useless in our component, we'll just drop it from our design. What we really need is a method to draw our component, so here we go:

  SUB DrawComponent
    IF QDiamondBox.Checked THEN
      QDiamondBox.Line(QDiamondBox.Height/2,0,0,QDiamondBox.Height/2,0)
      QDiamondBox.Line(0,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,QDiamondBox.Height,QDiamondBox.Height/2,0)
      QDiamondBox.Line(QDiamondBox.Height,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Paint(QDiamondBox.Height/2, QDiamondBox.Height/2, QDiamondBox.HiLightColor, 0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,QDiamondBox.Height,QDiamondBox.Height/2,&HFFFFFF)
      QDiamondBox.Line(QDiamondBox.Height,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,&HFFFFFF)
    ELSE
      QDiamondBox.Line(QDiamondBox.Height/2,0,0,QDiamondBox.Height/2,0)
      QDiamondBox.Line(0,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,QDiamondBox.Height,QDiamondBox.Height/2,0)
      QDiamondBox.Line(QDiamondBox.Height,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Paint(QDiamondBox.Height/2, QDiamondBox.Height/2, &HBBBBBB, 0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,0,QDiamondBox.Height/2,&HFFFFFF)
      QDiamondBox.Line(0,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,&HFFFFFF)
    END IF
    QDiamondBox.TextOut(QDiamondBox.Height + 5, QDiamondBox.Height/2-QDiamondBox.Height/4, QDiamondBox.Caption, 0, -1)
  END SUB
It may look nasty, but further investigation proves it's just long lines that appear cryptic. What the above code will do is draw a diamond and properly size your component so that it looks nice whenever you resize your component. This is very important, since you don't want your component to look like a miniature when your user specified Height = 100, Width = 100, etc... Just insert the above code inside our TYPE declaration. We also need to define another property HiLightColor. Whenever our check box is checked, we probably want our component to change color to notify the user that the box has been checked.

10.4 Defining Events
It's not possible to define new events for our components, so any events that our components have are inherited. Luckily, we have all we need for our QDiamondBox component, OnPaint, and OnClick. So why exactly do we need to define events? Don't we just let the user do that? Yes, but since this is our custom component, we want things to happen. For example, the QCheckBox component automatically becomes checked and unchecked when we click on it, we didn't need to write our own event handler to do that. This is that samething we want to happen for our own custom component. For starters, we'll need our OnPaint event. This event is called each time the form/component is updated.
     TYPE QDiamondBox EXTENDS QCanvas
       'Properties here

       'Our DrawComponent Method here

       EVENT OnClick
         IF QDiamondBox.Checked THEN
           QDiamondBox.Checked = 0
         ELSE
           QDiamondBox.Checked = 1
         END IF
         QDiamondBox.DrawComponent
       END EVENT

       EVENT OnPaint
         QDiamondBox.DrawComponent
       END EVENT
     END TYPE
Fairly straightforward, we've already covered why you'd reference DrawComponent like so, but the EVENT identifier is new. All that says is we're creating an EVENT handler for our component. Write your code like you would normally. Whenever we create (DIM) our new component, the events are automatically registered for us. They are called whenever that event happens. Fair enough, but what if I need to write a new event handler? In our QDiamondBox example, we're definitely going to need to redefine OnClick, since we want to know whether the user has checked or unchecked the DiamondBox. This is probably where it gets naughty. Since we don't actually want to discard our previous declaration of OnClick, we'll have to inherit it.
     DIM DBox AS QDiamondBox

     SUB NewDBoxOnClick
         DBox.InheritOnClick
         ' do you stuff here
     END SUB

     DBox.OnClick = NewDBoxOnClick
As you can see, if we wanted to inherit the OnClick event, we reference it by using QObject.Inherit<EventName> Where EventName is the event we want inherited. It's actually possible to Inherit OnPaint in our above example, but that would serve no purpose. If the Inherited event is not found (ie. there was no previous declaration of it), you will get a compiler ERROR message.

10.5 Adding components to our component
In our example, there's really no need to include components to our new QDiamondBox component, but since this topic is useful for many purposes, it's covered in this section. You can only add Rapid-Q components, not ones you've created yourself. As before, there's nothing new to the way we add components or properties:
     TYPE QGenericForm AS QForm
       Panel AS QPanel
     END TYPE

     DIM GF AS QGenericForm
         GF.Panel.Left = 123
Notice how we reference an object within an object. First period is to reference our Panel object, and the second period is to reference the Panel's properties or methods. If you wanted your panel to have some default values, you use the CONSTRUCTOR method as before:
     TYPE QGenericForm AS QForm
       Panel AS QPanel

       CONSTRUCTOR
          Panel.Parent = QGenericForm
          Panel.Width = QGenericForm.ClientWidth
          Panel.Height = QGenericForm.ClientHeight
       END CONSTRUCTOR
     END TYPE
You'll probably notice that even though we've somewhat implied that the Panel will be a part of the form, we still need to assign its Parent property, or else the panel won't show up. Simple enough, but how about defining its EVENTs? Okay, no problem:
     TYPE QGenericForm AS QForm
       Panel AS QPanel

       EVENT Panel.OnClick
         ShowMessage("User clicked on panel")
       END EVENT

       EVENT OnClick
         ShowMessage("User clicked on form")
       END EVENT
     END TYPE
Notice the extra reference (period). If you ignored that, the OnClick EVENT will be attached to your QGenericForm instead. As before, to inherit EVENTs, you'll have to do something like:
     GF.Panel.OnClick = GF.Panel.InheritOnClick
Most of the time, you never really want to access the components within a component directly. For example, you can create your own custom form, with close buttons, resize buttons etc... none of which you want to rewrite event handlers for.

10.6 Extending an empty Component
There may be cases when you don't need to extend any component, and you just want to write your own custom interface object. A good example is implementing a QIniFile interface object. Perhaps provide properties and methods to easily access and write to your own custom .INI file or however you want to do it. To do this, there is an empty object provided in Rapid-Q:
    TYPE QIniFile EXTENDS QObject
       Size AS INTEGER
       FileName AS STRING

       SUB SaveINI
       END SUB
       SUB LoadINI
       END SUB
    END TYPE
This kind of object acts like QSocket. ie. It's not a visible component, it's mainly an interface type object. Objects provide a cleaner interface, and is more elegant (well, I don't really care myself). In conclusion, this is basically all you need to know about adding your own components to Rapid-Q, it's fairly easy to grasp.

10.7 Public/Private properties and methods
All properties and methods are PUBLIC by default. Here's how you can define the scope of your properties and methods:
     TYPE QText EXTENDS QObject
       PUBLIC:
         I AS INTEGER
         X AS INTEGER

       PRIVATE:
         Y AS INTEGER

       PUBLIC:
         SUB Test
            QText.X = QText.Y + 1
         END SUB
     END TYPE
Properties I and X are PUBLIC, meaning they can be used outside their scope (ie. outside TYPE). Same with method Test. However, property Y is PRIVATE, so you can not use the property Y outside its scope. Since SUB Test is still inside the scope of Y (ie. inside TYPE), you can use it there. You can define PROTECTED properties and methods, but they act exactly like PUBLIC properties and methods, since (as of this writing) you can't extend a type of your own. For those who don't have any OOP background, the reason you have PUBLIC and PRIVATE members is mainly for your end-user's sake. Obviously you'll know what members shouldn't be used outside its scope, but by defining PRIVATE members you tell your end-users not to touch these in your program since they are used "internally."

10.8 Summary of Creating Custom Components
As you can see, creating reusable components like that can be very useful. It's relatively painless, just a few special cases that you need to know. I guess the most damaging is the fact you need to Inherit the event whenever you want to redefine the event. What this ultimately means is that if you distribute your custom component to other users, they'll have to know which events are inheritable, and ones that are not. It's a good idea to document this in your source code. You can also add QObjects to your custom components, so you can create a component which already contains components, neat. I hope you have fun creating your own Rapid-Q components!

10.9 QDiamondBox Source Code Listing
$APPTYPE GUI
$TYPECHECK ON

TYPE QDiamondBox EXTENDS QCanvas     '' You can extend any QObject
  '-- New Properties, you can also add components
  Caption AS STRING
  Checked AS INTEGER
  HiLightColor AS INTEGER

  '-- There are no protected methods, but you should let the user know anyway.
  '-- PROTECTED (meaning you shouldn't directly call it in your program).
  SUB DrawComponent
    IF QDiamondBox.Checked THEN
      QDiamondBox.Line(QDiamondBox.Height/2,0,0,QDiamondBox.Height/2,0)
      QDiamondBox.Line(0,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,QDiamondBox.Height,QDiamondBox.Height/2,0)
      QDiamondBox.Line(QDiamondBox.Height,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Paint(QDiamondBox.Height/2, QDiamondBox.Height/2, QDiamondBox.HiLightColor, 0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,QDiamondBox.Height,QDiamondBox.Height/2,&HFFFFFF)
      QDiamondBox.Line(QDiamondBox.Height,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,&HFFFFFF)
    ELSE
      QDiamondBox.Line(QDiamondBox.Height/2,0,0,QDiamondBox.Height/2,0)
      QDiamondBox.Line(0,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,QDiamondBox.Height,QDiamondBox.Height/2,0)
      QDiamondBox.Line(QDiamondBox.Height,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,0)
      QDiamondBox.Paint(QDiamondBox.Height/2, QDiamondBox.Height/2, &HBBBBBB, 0)
      QDiamondBox.Line(QDiamondBox.Height/2,0,0,QDiamondBox.Height/2,&HFFFFFF)
      QDiamondBox.Line(0,QDiamondBox.Height/2,QDiamondBox.Height/2,QDiamondBox.Height,&HFFFFFF)
    END IF
    QDiamondBox.TextOut(QDiamondBox.Height + 5, QDiamondBox.Height/2-QDiamondBox.Height/4, QDiamondBox.Caption, 0, -1)
  END SUB

  '-- Inherited Events (sorry, can't create any new events)
  '-- The user can still override these events, but it's not a good idea.
  EVENT OnClick
    IF QDiamondBox.Checked THEN
      QDiamondBox.Checked = 0
    ELSE
      QDiamondBox.Checked = 1
    END IF
    QDiamondBox.DrawComponent
  END EVENT

  EVENT OnPaint
    QDiamondBox.DrawComponent
  END EVENT

  '-- Default values
  CONSTRUCTOR
    Height = 30
    Width = 100
    HiLightColor = &H00FF00
    Caption = "DiamondBox"
    Checked = 0
  END CONSTRUCTOR
END TYPE

'----- Test our new component

DECLARE SUB DBox2Click

DIM Font AS QFont
    Font.Name = "Arial"
    Font.Size = 10

CREATE Form AS QForm
  Center
  Height = 120
  Caption = "Custom Check Boxes"
  CREATE DBox1 AS QDiamondBox
    Caption = "Diamond Box 1"
    Left = 100
    Height = 20
  END CREATE
  CREATE DBox2 AS QDiamondBox
    Caption = "Diamond Box 2"
    Top = 30
    Left = 100
    Height = 20
    Width = 140
    HiLightColor = &H0000FF
    Font = Font
    ShowHint = 1 ' True
    Hint = "Click me"
    OnClick = DBox2Click
  END CREATE
  CREATE DBox3 AS QDiamondBox
    Caption = "Diamond Box 3"
    Top = 60
    Left = 100
    Height = 20
  END CREATE
  ShowModal
END CREATE

SUB DBox2Click
  DBox2.InheritOnClick    '' Inherit event
  ShowMessage("Diamond Box 2 clicked")
END SUB


Chapter 11: Using function pointers

Rapid-Q Documentation by William Yu (c)1999 Chapter 11

11. Using Function Pointers

Didn't think you'd see function pointers in a BASIC programming language did you? Well, in Rapid-Q function pointers are a bit different from what most people are used to. There are a few oddities I guess, but most of the important features are there, like redefining function pointers, and dynamic function pointers. Unfortunately (as of this writing), you can't pass function pointers as arguments.

11.1 Introduction to the concept
Great, so what are function pointers? I know a lot people are tired of terminology, only because the definition is probably a lot easier to understand/grasp. It helps to understand how things are stored in memory and addressed. For example, a function (ie. SUB or FUNCTION) occupies space in some address space somewhere. A pointer to that function is just the address of it. So if I know the address of the function, I can jump into that "process space" and execute the code within. This is the low level way of thinking, first push the parameters, and then jump to (ie. CALL) the function. So if pointers are only numbers, how do we find the address of the function? This is the question that will be considered next.

11.2 Defining function pointers
If you have prior experience with function pointers (ie. in C) there are a few differences you'll have to get accustomed to. In Rapid-Q, since function pointers are just numbers, you can use any valid numeric datatype to define your function pointers. Seems odd, yes, but pointers are only numbers. Try avoiding BYTE, since the address of your function may be greater than 255, using BYTE may not be large enough. I suggest sticking with INTEGER/LONG.
    DECLARE SUB Test (I AS INTEGER)

    DIM FPtr AS INTEGER

    BIND FPtr TO Test
Well, we use BIND in Rapid-Q to bind our variable FPtr to the function Test. This will do 2 things, obviously FPtr will point to the address space of Test, but it also binds the number of parameters to FPtr, this is important for the compiler so that it knows how many parameters to pass/accept. To call our function, we have to use the reserved word CALLFUNC:
    CALLFUNC(FPtr, 120)
This calls our SUB Test with 1 parameter. Obviously this isn't a very useful example, so consider when it is useful...
    DECLARE SUB Test1 (I AS INTEGER)
    DECLARE SUB Test2 (I AS INTEGER)

    DIM FPtr(1 TO 2) AS INTEGER

    BIND FPtr(1) TO Test1
    BIND FPtr(2) TO Test2
When you're binding arrays, please note that the first function that is bound will be the TEMPLATE for all your other elements. Confusing? Okay, let me put this into words people can understand. :) Our array is FPtr, our BIND bounds FPtr(1) to SUB Test1. FPtr is now BOUND. What this means is that if you BIND any other FPtr(i), the function MUST HAVE MATCHING NUMBER OF PARAMETERS. Maybe an example would help:
    DECLARE SUB Test1 (I AS INTEGER)
    DECLARE SUB Test2 (I AS INTEGER, J AS STRING)

    DIM FPtr(1 TO 2) AS INTEGER

    BIND FPtr(1) TO Test1
    BIND FPtr(2) TO Test2
The second BIND is incorrect, since Test2 does not have matching parameters with Test1. You will receive an error message if you do this. Notice that I say matching NUMBER of parameters, you really don't need matching TYPE parameters. Don't do this though, results may vary.

11.3 Using function pointers properly
It will be clear (once you've used function pointers for a while) that there are times when using function pointers is necessary, and times when they're not. I think every situation is different, but consider this situation:
     SELECT CASE I
       CASE 1
         Process1("1", 44)
       CASE 2
         Process2("2", 55)
       CASE 3
         Process3("3", 66)
       CASE 4
         :
         :
      etc...
You can generalize this situation, for example, a menu with several options, or perhaps a parser (yes Rapid-Q does use function pointers to parse your code). As you may notice, that's a lot of comparisons, especially if you're writing a parser where there's so many keywords (over 50 say). We can easily eliminate these comparisons by using function pointers, consequently speeding up your program. See FUNCPTR.BAS for a concrete example.
     BIND FPtr(1) AS Process1
     BIND FPtr(2) AS Process2
     BIND FPtr(3) AS Process3
     BIND FPtr(4) AS Process4
     BIND FPtr(5) AS Process5
     BIND FPtr(6) AS Process6
     BIND FPtr(7) AS Process7

     x = VAL(INPUT$(1))
     CALLFUNC(FPtr(x), 33)
None of the code you see above is executable as is, but I think you get the general idea. We don't need any case statements as you can see (this is assuming you've partitioned your function pointers properly).

11.4 What is not supported in Rapid-Q
Function pointers as arguments is not supported. As funny as that sounds, this is actually very useful. Unfortunately I didn't get a chance to implement this (yet). You can pass the function pointer value as an argument, but as you can see, you won't be able to call your function. The only way would be to define a global function pointer as your template, and then assign that to your argument. It's easier to see with an example:
     DECLARE FUNCTION MyFuncTemp (X AS LONG) AS LONG
     DECLARE FUNCTION Func1 (X AS LONG) AS LONG
     DECLARE FUNCTION Func2 (X AS LONG) AS LONG

     DIM Template AS INTEGER
     DIM I(100) AS INTEGER

     BIND Template TO MyFuncTemp
     BIND I(1) TO Func1
     BIND I(2) TO Func2

     SUB Test (FPtr AS INTEGER)
        Template = FPtr
        PRINT CALLFUNC(Template, 10)
     END SUB

     Test I(1)
That's about the only way you can work around this limitation.


Chapter 12: Graphics under Windows

Rapid-Q Documentation by William Yu (c)1999 Chapter 12

12. Graphics under Windows

Most of the information contained in this chapter will not apply to the Linux/Unix version, except for the first few sections. If you're a DOS programmer converting your skills to Windows, there are some differences in the way you display graphics, mostly introduced by the concept of events and the multi-tasking nature of Windows.

12.1 Graphics under DOS versus Windows
If you're familiar with DOS programming and not so familiar with Windows programming, you'll probably notice some major differences in the nature of Graphics programming under the two OSes. Under DOS it's much simpler since you don't have to worry about other "programs" interrupting your program. This means what you display/draw on the screen won't erase itself magically, you only worry about what to draw next. However, there is a slight difference under Windows. Although it's perfectly safe to draw on your form, it has several consequences. The most obvious is that another program may "interrupt" the execution/display of your program. Think about minimizing the form or have it hidden under another window. How will Windows know what to redraw once your program gains refocus? You would think that Windows is smart enough to redraw the part that was hidden, but unfortunately we're not that lucky. Your program must tell Windows what to redraw. Windows will tell you that your form requires redrawing by sending messages to your form. In particular, the OnPaint (WM_PAINT) message is sent to the window which requires repainting. It is then your responsibility to provide an OnPaint procedure to your component/form that requires it.

12.2 What components require painting?
All visible components actually, but fortunately most of the work is done by Windows. For example, there's no need to provide an OnPaint method for the QButton class since it's already implemented for you. You can of course write your own Button class as you may have learned in Chapter 10, in which case you'll be writing the OnPaint method for the user. The QForm and QCanvas components are the two most obvious candidates to do graphics on. You can think of QCanvas as your basic DOS graphics screen, what you want drawn should be written inside the OnPaint procedure:
    DECLARE SUB CanvasPaint (Sender AS QCanvas)

    CREATE Form AS QForm
        CREATE Canvas AS QCanvas
            OnPaint = CanvasPaint
        END CREATE
        ShowModal
    END CREATE

    SUB CanvasPaint (Sender AS QCanvas)
        Sender.FillRect(10,10,100,100,&HFF0000)      '-- Blue box
    END SUB
If you try hiding the form under another Window and then refocus the program, the blue box will still appear. Now try writing something that doesn't utilize the OnPaint procedure:
    CREATE Form AS QForm
        CREATE Canvas AS QCanvas
            FillRect(10,10,100,100,&HFF0000)      '-- Blue box
        END CREATE
        Form.ShowModal
    END CREATE
Notice anything? Exactly, there is no blue box. The paint message was sent when your form first appears on your desktop, and since you didn't write any OnPaint procedure, there's nothing to draw. So what really happens to that FillRect code? Nothing really, it's still executed, but the next paint message offset it. To understand this better, try this code which will display the blue box when your press the button, but try hiding the window again or minimizing it. Redisplay your window and see what happens:
    DECLARE SUB ButtonClick

    CREATE Form AS QForm
        CREATE Button AS QButton
          OnClick = ButtonClick
        END CREATE
        CREATE Canvas AS QCanvas
        END CREATE
        ShowModal
    END CREATE

    SUB ButtonClick
        Canvas.FillRect(10,10,100,100,&HFF0000)
    END SUB
When you click your button the blue box will be drawn, however, once you hide part of the window and redisplay your window, you'll probably notice that your blue box has dissappeared.

12.3 Drawing graphics dynamically
As you may have already noticed, if all your graphics are contained in your OnPaint procedure, how do you draw on it dynamically without it erasing itself magically? For this purpose, you'll have to draw on an off-screen graphics bitmap and then in your OnPaint procedure, you just use the Draw method to display the graphic. You can use the QBITMAP component as your off-screen graphics page. Here's some sample code for you to test:

DECLARE SUB CanvasPaint (Sender AS QCanvas)
DECLARE SUB ButtonClick (Sender AS QButton)

' Create bitmap for off-screen use
DIM BitMap AS QBITMAP
    BitMap.Height = 100
    BitMap.Width = 100
    BitMap.Paint(0,0,0,0)

CREATE Form AS QForm
    Center
    Caption = "Simple graphics demonstration"
    CREATE Canvas AS QCanvas
        OnPaint = CanvasPaint
    END CREATE
    CREATE SquareButton AS QButton
        Caption = "Draw Square"
        OnClick = ButtonClick
        Left = 150
    END CREATE
    CREATE CircleButton AS QButton
        Caption = "Draw Circle"
        OnClick = ButtonClick
        Left = 150
        Top = 50
    END CREATE
    CREATE LineButton AS QButton
        Caption = "Draw Line"
        OnClick = ButtonClick
        Left = 150
        Top = 100
    END CREATE
    ShowModal
END CREATE

SUB CanvasPaint (Sender AS QCanvas)
    Sender.Draw(0,0,Bitmap.BMP)
END SUB

SUB ButtonClick (Sender AS QButton)
    SELECT CASE Sender.Caption
        CASE "Draw Square"
            Bitmap.FillRect(10,10,50,50,&HFF0000)
        CASE "Draw Circle"
            Bitmap.Circle(10,60,50,110,&H0000FF,&H0000FF)
        CASE "Draw Line"
            Bitmap.Line(50,50,90,90,&H00FF00)
    END SELECT
    Canvas.Repaint       '-- Tell Canvas to repaint itself.
END SUB
Sample Output:
Output

Code Details:
Much of the code is self explanatory. The first bit of code creates and initializes the Bitmap component. Since QBitmap is a non-visible component, it does not receive paint messages, so anything you draw on the Bitmap will stay. Now that we have our Bitmap ready, our OnPaint procedure for QCanvas can use the Draw method to paint the Bitmap onto the Canvas. This is what you call double buffering, a similar technique is utilized in DirectX.

12.4 Ownerdraw List and Combo Boxes (including QStringGrid)
Ownerdrawn ListBoxes and ComboBoxes allow you to override the default paint method somewhat. It doesn't really let you redraw the entire interface of a list or combo box, since that's probably not what you want anyway. What it does allow you to do is override the paint method for the data. So instead of just displaying the text fields in your list or combo boxes, you can actually draw pictures in them and/or change the font/color for each individual item. There are 2 types of ownerdraw list/combo boxes.
  • 1. OwnerDrawFixed
  • 2. OwnerDrawVariable
A fixed ownerdrawn list/combo box means that all your items will have a fixed predetermined height. So let's consider the case where one of your pictures is 100 pixels high and another which is only 10 pixels high. If you specify an ItemHeight of say 10, the 100 pixel high picture will actually overlap some of your items since it doesn't have enough room for itself (this can be avoided if you use CopyRect instead of Draw). But in any event, it would have been much better to create variable sized item fields, so you'd use OwnerDrawVariable instead. The only problem with OwnerDrawVariable list/combo boxes is that it requires the programmer to specify the height of each item, it doesn't automatically calculate this field for you. In most cases this isn't that big of a problem, but nonetheless you'll have to store this extra information for each field. How you do this is entirely up to you. To see a working example of ownerdrawn list/combo boxes, look at LISTBOX.BAS included in EXAMPLES.ZIP. You can rewrite the code to work with ComboBoxes. You may notice that you don't implement any OnPaint event, but an OnDrawItem event.

Code Details:
  SUB ListBoxDrawItem(Index AS INTEGER, State AS BYTE, Rect AS QRECT)
    IF State = 0 THEN
      '-- Selected
      ListBox.FillRect(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom, &H00FF00)
    ELSE
      ListBox.FillRect(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom, &HFFFFFF)
    END IF
    ListBox.TextOut(100, Rect.Top+(Rect.Bottom-Rect.Top)/4, ListBox.Item(index), 0, -1)
    ListBox.Draw(Rect.Left, Rect.Top, Bitmap(Index).BMP)
  END SUB
Hopefully the code is self explanatory, but a few things you may notice is that you don't paint the entire listbox (ie. all items), but rather a paint message is sent everytime an item is changed. This item occupies a rectangular region in your listbox, so what the OnDrawItem sends to you is the region of this item (this is the Rect parameter). You should not overstep this bound that has been given to you (ie. don't try to draw outside this region, it's not yours to draw on!). I have not covered QStringGrid in this section, but the same idea persists. You'll have to implement the OnDrawCell event, which is similar to the way you handle OnDrawItem in list/combo boxes.

12.5 Using DirectX
Why is DirectX so popular? This question can be summed up quite frankly without going into much detail. It's faster than Windows GDI (and OpenGL in most cases), it supports most graphics cards, it's free to use, and it provides a lot of the most necessary graphics commands that programmers are looking for without implementing it themselves. Not to mention that it's widely supported and (to some people) easy to use. As you may note, this is not my general opinion about DirectX, but the general public opinion.
Does everyone have DirectX installed? In most cases, yes, it depends what version though. Not everyone will have the latest version, but that usually doesn't matter. DirectX for Rapid-Q only requires v5.0 and may even work for version v3.0 and up (untested). Rapid-Q does not yet support all the features of DirectX, like joystick or 3D programming.
To use DirectX under Rapid-Q, you'll have to know 2 things.
  • 1. All drawing is done on the off-screen page
  • 2. You need to FLIP to this page everytime you want it displayed
In essence, you can think of this off-screen page as already implemented for you (like in the above example where we had to use QBitmap as our off-screen page). You can think of the FLIP operation as a repaint operation just like in the above example. After you understand these 2 concepts, everything else is basically the same. You draw on the DirectX Screen like you would a QCanvas or QBitmap, then FLIP pages when you're ready to display your graphics. It is easier to look at some examples rather than for me to explain it. There is however, one more important topic, that is QDXTimer.
QDXTimer is a specialized timer specifically for DirectX, it controls the frame rate so that your program doesn't run too fast or too slow. In most cases it will decrease your frame rate if your program is running too fast, but can't do much if your program is chugging along at 5 or 6 frames per second. Please use QDXTimer instead of the standard Windows timer QTimer when animating graphics in DirectX.


Chapter 13: Direct3D for Rapid-Q

Rapid-Q Documentation by William Yu (c)1999 Chapter 13

13. Direct3D for Rapid-Q

This is only an introduction to using Direct3D with Rapid-Q. Since most of the Direct3D components have not yet been finalized under Rapid-Q, this chapter will deal mostly with what can be done.

13.1 Requirement specifications
The most basic requirement is that you have the DirectX 6.0 runtimes. If you're unsure what version you have, type DXDIAG at the command prompt, or find the file under C:\WINDOWS\SYSTEM. If you don't have DXDIAG then you'll definitely need to upgrade. You can download the runtime files at http://msdn.microsoft.com/directx/
Just the runtime files, you don't need the SDK, but if you want, no one is stopping you from downloading it. The SDK does contain an important file CONV3DS.EXE which is necessary to convert different 3D models for use with your programs. However, I have posted a link to this file so it's not necessary for you download the entire SDK just for that one file.

    Other nice things to have:
  • 3D accelerated video card
  • A 3D modeler (like 3D Studio)
  • OpenGL (some 3D modelers use this)
Even if you don't have any of the above, this shouldn't matter. A 3D card is not necessary, but you'll find that running your programs can be 5 to 10 times slower, but still manageable if you have a good Pentium. I don't have a 3D card, and only get about 5-10 fps on my P200, but it doesn't bother me. If you don't have a 3D modeling program don't worry, there's some free 3D modelers on the internet. I find that Anim8or is pretty good, for something that's completely free there's nothing to complain about. It's only a 500KB download, which is very small compared to other 3D modeling programs I've seen. It does require OpenGL, but check your C:\WINDOWS\SYSTEM directory for OPENGL32.DLL. If you have it, you're in good shape, if not, just download it off the web at http://www.opengl.org/
    Nice links to have:
  • Anim8or homepage good 3D modeler
  • DOGA Homepage another good free 3D modeler
  • CONV3DS.EXE converts .3DS files to .X files
  • 3DCafe.com thousands of free 3D models available
  • Microsoft's DirectX homepage learn more, download their SDK documentation

13.2 Using Anim8or to create 3D models
If you already have a good understanding of how to create 3D models, you can skip this section. I will be using Anim8or to demonstrate simple 3D modeling which you can quickly use in your Rapid-Q programs. If you haven't already downloaded Anim8or's HTML documentation, I suggest you do that. I won't cover all there is to know about Anim8or, just the basics.

    Step by step introduction
  • Load Anim8or
  • Click on a polygon object
  • To draw this object, just click and drag your mouse on the main grid
  • Make sure to also center the object (not necessary but a good thing anyway). To do this, just select the object you want centered, then select from the menu: Edit|Locate|Center about origin
  • Make sure you haven't drawn an overly big polygon, perhaps the size of your pinky is good enough.
  • Now to export your object, select from the menu: Object|Export Just make sure to save as a .3DS file.
  • Let's just say you named your file poly.3ds then from the command prompt type in:
       CONV3DS -m poly.3ds
    I assumed you downloaded CONV3DS.EXE (copy this to your Windows directory if you want).
  • Once converted, you should have a poly.x file, this object file can now be used in your Rapid-Q program!
If you don't like doing your own 3D models you can always download pre-made 3D models from www.3dcafe.com and other websites like it. However, it's always nice to customize your objects, so learning to use a 3D modeling program wouldn't hurt. The optional parameter -m is used to create a single mesh for use with MeshBuilder. Without -m, your .X file is saved as a frame so you would have to use QD3DFrame to load your .X file.

13.3 Loading/Using .X Files
Simply loading an .X file is easy enough, to make sure you have this much working, copy and paste this code:
' Simply places an object on the scene

$TYPECHECK ON

CONST alClient = 5

'-- Light Types
CONST D3DRMLIGHT_AMBIENT = 0
CONST D3DRMLIGHT_POINT = 1
CONST D3DRMLIGHT_SPOT = 2
CONST D3DRMLIGHT_DIRECTIONAL = 3
CONST D3DRMLIGHT_PARALLELPOINT = 4

DECLARE SUB DXInitialize(Sender AS QDXScreen)
DECLARE SUB DXTimerExpired

DIM DXTimer AS QDXTimer
    DXTimer.Enabled = 1
    DXTimer.Interval = 0
    DXTimer.Activeonly = 0
    DXTimer.OnTimer = DXTimerExpired

CREATE Form AS QForm
    Caption = "Direct 3D Example"
    Center
    CREATE DXScreen AS QDXScreen
        Init(320,240)
        Align = alClient
        Use3D = 1
        UseHardware = 0        '' This is for non-3D accelerated video cards.
                               '' 3D will be emulated using software, which
                               '' is much slower.
        OnInitialize = DXInitialize
    END CREATE
    ShowModal
END CREATE

SUB DXInitialize(Sender AS QDXScreen)
   DIM Light AS QD3DLight
   DIM LightFrame AS QD3DFrame, MeshFrame AS QD3DFrame
   DIM MeshBuilder AS QD3DMeshBuilder

   DXScreen.CreateFrame(LightFrame)
   DXScreen.CreateFrame(MeshFrame)

   '-- Need light, else object would be completely hidden
   DXScreen.CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, 0.9, 0.9, 0.9, Light)
   LightFrame.AddLight(Light)

   DXScreen.SetCameraPosition(-5, 10, 0)
   DXScreen.SetCameraOrientation(0.35, -0.65, 1.0, -0.15, 1.0, 0.5)

   MeshFrame.SetPosition(0, 0, 15)
   MeshFrame.SetOrientation(0, 0, 1, 0, 1, 0)
   MeshFrame.SetRotation(0, 0, 0, 0.05)     '-- Angle of rotation = 0.05

   DXScreen.CreateMeshBuilder(MeshBuilder)  '-- Create object

   MeshBuilder.Load("poly.x")               '-- Load your object
   MeshFrame.AddVisual(MeshBuilder)         '-- Add object to frame
END SUB

SUB DXTimerExpired
   DXScreen.ForceUpdate(0,0,50,50)   '-- Updates FPS Text
   DXScreen.Render
   DXScreen.TextOut(10,10,"FPS: "+STR$(DXTimer.FrameRate), &HFFFFFF, -1)
   DXScreen.Flip
END SUB
If everything worked, you should obtain some output that looks like this:
If you understood the example, it's quite easy to add more objects to the scene, just create another MeshFrame and load another object file. Play around with the code until you're satisfied.

13.4 Wrapping textures around an object
Now that we have the basics, time to wrap textures around our object. To do this, all we need is a .BMP file for our texture. There's a few important points to note, First, width and height of bitmap must be equal, and secondly, they must be powers of 2 (ie. 32x32, 256x256, etc.). This is obviously for optimization reasons, but don't ask me, I didn't create Direct3D. Anyway, to wrap this texture around our object, we just need to modify the above code a bit (changes are noted in Blue):
' Wrap textures around 3D object

$TYPECHECK ON

CONST alClient = 5

'-- Light Types
CONST D3DRMLIGHT_AMBIENT = 0
CONST D3DRMLIGHT_POINT = 1
CONST D3DRMLIGHT_SPOT = 2
CONST D3DRMLIGHT_DIRECTIONAL = 3
CONST D3DRMLIGHT_PARALLELPOINT = 4

'-- Wrap Types
CONST D3DRMWRAP_FLAT = 0
CONST D3DRMWRAP_CYLINDER = 1
CONST D3DRMWRAP_SPHERE = 2
CONST D3DRMWRAP_CHROME = 3
CONST D3DRMWRAP_SHEET = 4
CONST D3DRMWRAP_BOX = 5

CONST WrapType = D3DRMWRAP_SPHERE     '-- You can modify this

DECLARE SUB DXInitialize(Sender AS QDXScreen)
DECLARE SUB DXTimerExpired

DIM DXTimer AS QDXTimer
    DXTimer.Enabled = 1
    DXTimer.Interval = 0
    DXTimer.Activeonly = 0
    DXTimer.OnTimer = DXTimerExpired

CREATE Form AS QForm
    Caption = "Direct 3D Example"
    Center
    CREATE DXScreen AS QDXScreen
        Init(320,240)
        Align = alClient
        Use3D = 1
        UseHardware = 0        '' This is for non-3D accelerated video cards.
                               '' 3D will be emulated using software, which
                               '' is much slower.
        OnInitialize = DXInitialize
    END CREATE
    ShowModal
END CREATE

SUB DXInitialize(Sender AS QDXScreen)
   DIM Light AS QD3DLight
   DIM LightFrame AS QD3DFrame, MeshFrame AS QD3DFrame
   DIM MeshBuilder AS QD3DMeshBuilder
   DIM Texture AS QD3DTexture
   DIM Wrap AS QD3DWrap
   DIM Mesh AS QD3DMesh

   DXScreen.CreateFrame(LightFrame)
   DXScreen.CreateFrame(MeshFrame)

   DXScreen.CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, 0.9, 0.9, 0.9, Light)
   LightFrame.AddLight(Light)

   DXScreen.SetCameraPosition(-5, 10, 0)
   DXScreen.SetCameraOrientation(0.35, -0.65, 1.0, -0.15, 1.0, 0.5)

   MeshFrame.SetPosition(0, 0, 15)
   MeshFrame.SetOrientation(0, 0, 1, 0, 1, 0)
   MeshFrame.SetRotation(0, 0, 0, 0.05)       ' Angle of rotation = 0.05

   DXScreen.CreateMeshBuilder(MeshBuilder)

   MeshBuilder.Load("poly.x")            '-- Egg object

   MeshBuilder.LoadTexture("back.bmp")   '-- New lines
   MeshBuilder.CreateMesh(Mesh)

   MeshFrame.AddVisual(Mesh)

   DXScreen.CreateWrap(WrapType, 0,0,0, 0,0,1, 0,1,0, 0,0, 1,1, Wrap)
   Wrap.Apply(Mesh)

END SUB

SUB DXTimerExpired
   DXScreen.ForceUpdate(0,0,50,50)
   DXScreen.Render
   DXScreen.TextOut(10,10,"FPS: "+STR$(DXTimer.FrameRate), &HFFFFFF, -1)
   DXScreen.Flip
END SUB
Again, if everything worked, you should obtain some output that looks like this (depending on what texture file you used of course):

As you can see, it doesn't take much to add textures to our objects. The only problem is you lose a few frame rates by doing this.

13.5 Rotating/Moving objects
Unfortunately as of this writing, there is no support for Animation sets, but that will be worked on later. You can do simple rotations and scene movements just by calling the method Move or manually setting the camera angles and positions. Using the example from above, add this extra code:

   DXScreen.ForceUpdate(0,0,50,50)
   DXScreen.Move(1)            '-- Add this line
   DXScreen.Render
This moves the camera position by the amount specified. The affect is a rotation about angle Theta. This Theta was specified on the line:
   MeshFrame.SetRotation(0, 0, 0, 0.05)       ' Angle of rotation = 0.05
DXScreen.Move animates the entire scene, to just animate a certain frame, you can use MeshFrame.Move(1).


Chapter 14: Programming in MySQL

Rapid-Q Documentation by William Yu (c)1999 Chapter 14

14. Programming in MySQL

This chapter is a quick overview of what you can do with the QMYSQL component. It does not teach you about SQL or how to construct proper queries. It is assumed you have some prior knowledge of SQL, but not necessarily with MySQL.

14.1 Quick Introduction
MySQL is basically free for Unix and OS/2 platforms, but Rapid-Q only supports MySQL for Linux and Windows since my resources are limited to such machines. Under Windows, if you like MySQL, then you are required to pay a license fee after a 30 day trial period. Not to be confused with paying me of course, but if you want, I'll oblige. Why did I choose MySQL over other database servers? The reason is fairly simple, yet deserves some explanation anyway. MySQL is free, mostly, and it's multiplatform, which fits into Rapid-Q quite nicely. It's also easier for me to test, and quite simple to implement under Rapid-Q. It's fairly lightweight, fast, robust, and did I mention free? Perhaps in the future, other database servers will be supported, ie. through MyODBC or Window's ODBC.
    Required files:
  • MySQL server version 3.22.xx or better
  • Rapid-Q MySQL Libraries
  • MySQL Client if you don't want to run a server
After installing the MySQL server, test it to make sure it works (read their nice documentation and help files), you'll also need to copy LIBMYSQL.DLL (under Windows) and libmysqlclient.* (under Linux) to your library path directory. C:\WINDOWS\SYSTEM under Windows, and maybe /usr/lib under Linux (you can also just add a library path to the file instead of moving it). These library files are required by Rapid-Q, they should have come with your MySQL distribution, probably in C:\MYSQL\LIB and /usr/local/lib/mysql depending on your installation. If you already have MySQL installed, which is possible, make sure it's up to date, or if you have an SQL Administrator, check with the that person.

14.2 Connecting to MySQL
The introduction assumed that you wanted to install a MySQL server on your machine, but you can access a MySQL database from anywhere, as long as you have access of course. If you don't want to install a MySQL server (why wouldn't you?) then make sure you have the proper client libraries, ie. LIBMYSQL.DLL. To begin with, I'll assume you have the MySQL server installed. To connect to your local MySQL server is simple enough:
            DIM MySQL AS QMYSQL

            Host$ = ""
            User$ = ""
            Password$ = ""
            MySQL.Connect(Host$, User$, Password$)

            IF MySQL.Connected THEN PRINT "Successfully connected"
Change User$ and Password$ to suit your needs. Host$ can also take the value of "localhost" but is not necessary in this case. Now to connect to a remote MySQL server located, say, in allsql.com
            DIM MySQL AS QMYSQL

            Host$ = "allsql.com"
            User$ = "anonymous"
            Password$ = "guest"
            MySQL.Connect(Host$, User$, Password$)

            IF MySQL.Connected THEN PRINT "Successfully connected"
Most servers will use the standard MySQL port 3306, but if you know the exact port, then you can use the method RealConnect.
            DIM MySQL AS QMYSQL

            Host$ = "allsql.com"
            User$ = "anonymous"
            Password$ = "guest"
            Port% = 12345
            MySQL.RealConnect(Host$, User$, Password$, "", Port%, "", 0)

            IF MySQL.Connected THEN PRINT "Successfully connected"
See appendix section for the parameters of QMYSQL.RealConnect. It is suggested by the MySQL documentation that you use RealConnect instead of the using Connect.

14.3 How to perform queries and obtain the results
Write your queries like you would normally, for example, if you want to select everything from a certain table, say you have a table named user, then you can do this:
            DIM MySQL AS QMYSQL

            '' First connect to server

            '' Use database
            MySQL.SelectDB("mysql")

            '' Perform query
            MySQL.Query("select * from user")
The result of this query is stored internally, and sequentially. To obtain the result, you'll need to Fetch it. You can visualize a 2 dimensional table:
Since the result is stored sequentially, you have to fetch each row one at a time (not necessarily true, but assume we have no other choice). To do this is quite simple:
            WHILE MySQL.FetchRow       '' Get next row
                MySQL.FieldSeek(0)     '' Reset field position
                FOR I = 0 TO MySQL.FieldCount-1
                    PRINT MySQL.Row(I) '' Read current row element I
                NEXT
            WEND
MySQL.FetchRow fetches the next row. As long as there are still rows available to fetch, MySQL.FetchRow returns TRUE (non-zero number). MySQL.FieldCount is used to count how many fields per row there are in the current table. The rest is self explanatory.

14.4 Interfacing QMYSQL with QSTRINGGRID
As you may notice, it would be nice if the results could just be preloaded into a string grid instead of having to fetch everything and doing it manually. Unfortunately I haven't got any motivation to do this right now, but you can use this simple code until I get off my butt and implement it internally:
            SUB ExecuteQuery(MySQL AS QMYSQL, Grid AS QSTRINGGRID, Query AS STRING)
                IF MySQL.Query(Query) = 0 THEN
                   '' Failed to execute
                   EXIT SUB
                END IF

                DEFINT I = 0, J

                ''-- Write header
                Grid.ColCount = MySQL.FieldCount
                WHILE MySQL.FetchField
                   Grid.Cell(I,0) = MySQL.Field.Name
                   I++
                WEND

                Grid.RowCount = MySQL.RowCount+1
                J = 1
                WHILE MySQL.FetchRow       '' Get next row
                   MySQL.FieldSeek(0)      '' Reset field position
                   FOR I = 0 TO MySQL.FieldCount-1
                      Grid.Cell(I,J) = MySQL.Row(I)
                   NEXT
                   J++
               WEND
            END SUB

            ''-- Example
            ExecuteQuery(MySQL, MyGrid, "select * from user")
Obviously, you can interface QMYSQL with any component, or components, you want.

14.5 Storing and retrieving blobs
Blobs are just binary data that require special processing. Since blobs can contain NULL characters and other special characters that affect MySQL and Rapid-Q, you'll need to do some special processing with your binary data. Please note that blob sizes vary, depending on the field type. A LONGBLOB, by default can hold up to 65535 bytes. If you want to change the buffer size, you'll have to read up on it (max_allowed_packet). In most cases, ie. storing images, the 64KB limit is not sufficient. Anyway, let's assume we never exceed that limit, now to store binary data, like images, you'll have to preprocess certain characters before you can send it over to your MySQL database.
            $INCLUDE "RAPIDQ.INC"

            DIM MySQL AS QMYSQL

            ''-- Connect to database code, etc...

            DIM File AS QFILESTREAM
            File.Open("test.bmp", fmOpenRead)

            ''-- Read file as binary, preserves NULL chars
            Buffer$ = File.ReadBinStr(File.Size)

            ''-- Here's the special processing
            ''-- Converts NULLs to \0 and others
            ProcessedBuffer$ = MySQL.EscapeString(Buffer$, File.Size)

            ''-- Insert blob in our table
            MySQL.Query("insert into MyImageTable values('Label 1', '" + _
                        ProcessedBuffer$ + "')")

            File.Close
            MySQL.Close
Since we're dealing with binary data, you have to be aware that we don't use LEN() or any other STRING processing functions with our binary data. Note that we can store text data in blob fields, in which case you can use any STRING processing functions you want. You may notice that MySQL.EscapeString converts the binary data to a usable format that can be passed to the MySQL database. Basically all it does is convert NULLs to '\0', ' to \', " to \", and CRLF to \r and \n respectively. Once parsed, the new string is returned which you can use in a query. So far so good, now we consider retrieving our blobs:
            $INCLUDE "RAPIDQ.INC"
            $INCLUDE "MYSQL.INC"

            DIM MySQL AS QMYSQL

            ''-- Connect to database code, etc...

            DIM File AS QFILESTREAM
            File.Open("out.bmp", fmCreate) ''-- Create new file

            ''-- Your query here
            MySQL.Query("select * from MyImageTable")

            WHILE MySQL.FetchRow
                MySQL.FieldSeek(0)
                MySQL.FetchLengths ''-- Required for binary data
                FOR I = 0 TO MySQL.NumField-1
                    MySQL.FetchField
                    IF MySQL.Field.Type = FIELD_TYPE_BLOB THEN
                        ''-- Read binary data from table
                        Buffer$ = MySQL.RowBlob(I, MySQL.Length(I))
                        File.WriteBinStr(Buffer$, MySQL.Length(I))
                    ELSE
                        Buffer$ = MySQL.Row(I)
                    END IF
                NEXT
            WEND

            File.Close
            MySQL.Close
Retrieving blobs from the database is a little more confusing than storing blobs. The first thing you have to note is that reading binary data and text strings are 2 different operations. Since text strings are NULL terminated, you don't have to worry about how many bytes to read, this is automatically calculated for you. However, since binary data can contain NULL characters, this makes reading blobs a little bit tricky. You have to fetch the lengths of each field, since we have blobs in our table, this is done by calling MySQL.FetchLengths for each row. Then to find out the length of each field, you use the internal array MySQL.Length(index%) which returns the length for field index%. Why do we have to do this? Because we need to know the size of our blob before we can read it in. To read binary data from our database, you use the specialized function MySQL.RowBlob(Row%, Bytes%) which returns a binary string. With this binary string, you can write the data to a file or memory, or manipulate the data directly. In the above example, we're just writing the data to a file.

14.6 Using LOADBLOB and SAVEBLOB
In the previous section, we uncovered the natural way of storing and retrieving blobs (binary data). However, there is an easier and faster way of doing the samething.
            ''-- Recall the natural way
            ProcessedBuffer$ = MySQL.EscapeString(Buffer$, File.Size)
            MySQL.Query("insert into MyImageTable values('Label 1', '" + _
                        ProcessedBuffer$ + "')")

            ''-- Using LOADBLOB instead
            ProcessedBuffer$ = MySQL.LoadBlob("test.bmp")
            MySQL.Query("insert into MyImageTable values('Label 1', '" + _
                        ProcessedBuffer$ + "')")
Using LOADBLOB eliminates the use of MySQL.EscapeString since it is just implemented internally for you. It simply takes a single argument (the name of the file to include), and returns the processed string. To retrieve a blob from the database and save it to a file, you can try this:
            WHILE MySQL.FetchRow
                MySQL.FieldSeek(0)
                '' MySQL.FetchLengths
                FOR I = 0 TO MySQL.NumField-1
                    MySQL.FetchField
                    IF MySQL.Field.Type = FIELD_TYPE_BLOB THEN
                        ''-- Save data to file
                        MySQL.SaveBlob(I, "temp.bmp")
                    ELSE
                        Buffer$ = MySQL.Row(I)
                    END IF
                NEXT
            WEND
In this instance we can ignore using MySQL.FetchLengths since it is, again, implemented internally for you. MySQL.SaveBlob takes two arguments. The first is the index (or field number if you will), and the second argument is the name of the file to save to. There are no return values associated with this function.

14.7 In conclusion
Using MySQL can save you a lot of time and effort, since you don't need to design your own database file structure, and searching is quite fast. Not to mention that MySQL is multiplatform, so you can use MySQL with Windows and Linux. If you already have prior knowledge with programming in MySQL, you'll probably notice some differences. For example,
            I = MySQL.SelectDB("mysql")
Under Rapid-Q, this function returns 0 if database cannot be opened, and a non-zero number otherwise. However, if you've used LIBMYSQL.DLL before, this function (called mysql_select_db) returns 0 on success and -1 on failure. So basically, just reverse your way of thinking when using Rapid-Q.


Appendix A: CLIPBOARD

Rapid-Q Documentation by William Yu (c)1999 Appendix A: CLIPBOARD

CLIPBOARD Component

This object is global, and need not be created.

ClipBoard Properties
Field | Type | R/W | Default
Text | STRING | RW

ClipBoard Methods
Method | Type | Description | Params
Clear | SUB | Clear clipboard | 0
Close | SUB | Free clipboard for other processes | 0
GetAsHandle | FUNCTION (Format%) AS INTEGER | Returns handle of specified format | 1
GetAsText | FUNCTION (length%) AS STRING | Returns text of length% | 1
HasFormat | FUNCTION (Format%) AS BYTE | Returns true or false if the format exists or not | 1
Open | SUB | Begin critcal section | 0
SetAsHandle | SUB (Format%, Handle&) | Set handle and format | 2
SetAsText | SUB (Text$) | Set text of clipboard | 1

ClipBoard Examples
ClipBoard.Open
PRINT ClipBoard.Text
ClipBoard.Close


Appendix A: PRINTER

Rapid-Q Documentation by William Yu (c)1999 Appendix A: PRINTER

PRINTER Component

This object is global, and need not be created. Please note that some printers do not support Draw or CopyRect. The printer component is mainly used for graphics, although it may also be suitable for text, please refer to LPRINT for text-only printing.

Printer Properties
Field | Type | R/W | Default
Aborted | INTEGER | R
Capabilities.Copies | INTEGER | R
Capabilities.Orientation | INTEGER | R
Capabilities.Collate | INTEGER | R
Copies | INTEGER | RW
CopyMode | INTEGER | RW | cmBlackNess
Font | QFONT | W
Fonts | ARRAY of STRING | R
FontsCount | INTEGER | R
Handle | INTEGER | R
Orientation | INTEGER | RW
PageHeight | INTEGER | R
PageNumber | INTEGER | R
PageWidth | INTEGER | R
PrinterIndex | INTEGER | RW
Printers | ARRAY of STRING | R
PrintersCount | INTEGER | R
Printing | INTEGER | R
Title | STRING | RW

Printer Methods
Method | Type | Description | Params
Abort | SUB | Abort printing the document | 0
BeginDoc | SUB | Starts new document to print | 0
EndDoc | SUB | Nothing is printed until this is called | 0
NewPage | SUB | Start printing on a new page | 0
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3
Draw | SUB (x%, y%, BMP) | Draw Bitmap on Canvas | 3
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4
Pset | SUB (x%, y%, c%) | Pixel plot | 3
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to printer | 5

Printer Examples
DECLARE SUB ButtonClick

SUB ComboBoxChange(Sender AS QComboBox)
  Printer.PrinterIndex = Sender.ItemIndex   '-- Change default printer
END SUB

DIM Font AS QFont
    Font.Color = &HFF0000
    Font.Name = "Arial"
    Font.Size = 20
DIM Bitmap AS QBitmap
Bitmap.BMP = "rapidq.bmp"

CREATE Form AS QForm
  CREATE ComboBox AS QComboBox
    Left = 5
    Top = 5
    Width = 150
    OnChange = ComboBoxChange
  END CREATE
  CREATE Button AS QButton
    Caption = "&Print"
    Top = 3
    Left = 180
    OnClick = ButtonClick
  END CREATE
  CREATE GroupBox AS QGroupBox
    Caption = "Print Preview..."
    Top = 35
    Width = Form.ClientWidth
  END CREATE
  Center
END CREATE

FOR I = 0 TO Printer.PrintersCount-1
  ComboBox.AddItems(Printer.Printers(I))    '-- Add printer list to combobox
NEXT
ComboBox.ItemIndex = Printer.PrinterIndex

Form.ShowModal

SUB ButtonClick
  Printer.Orientation = 1   ' Landscape
  Printer.BeginDoc
  Printer.TextOut(1000,1000,"Hi World!",0,-1)
  Printer.Font = Font
  Printer.TextOut(10,10,"Does this print?",0,-1)
  Printer.Line(10,10,500,500,0)
  Printer.EndDoc
END SUB


Appendix A: QBITMAP

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QBITMAP

QBITMAP Component

QBitmap is a non-visible component, used to store/retrieve BMP images.

QBitmap Properties
Field | Type | R/W | Default | Support
BMP | STRING | W | W
BMPHandle | RESOURCE | W | W
CopyMode | INTEGER | RW | cmBlackness | W
Empty | INTEGER | R | W
Font | QFONT | W | W
Handle | INTEGER | RW | W
Height | INTEGER | RW | WG
Monochrome | INTEGER | RW | W
Pixel | 2D ARRAY of INTEGER | RW | WG
PixelFormat | INTEGER | RW | pfDevice | W
Top | INTEGER | RW | WG
Transparent | INTEGER | RW | False | W
TransparentColor | INTEGER | RW | W
TransparentMode | INTEGER | RW | 0 | W
Width | INTEGER | RW | WG

QBitmap Methods
Method | Type | Description | Params | Support
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6 | WG
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3 | W
Draw | SUB (x%, y%, BMP) | Draw Bitmap on Canvas | 3 | WG
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5 | WG
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5 | WG
LoadFromFile | SUB (FileName$) | Load BMP from a file | 1 | W
LoadFromStream | SUB (Stream) | Load BMP from a stream | 1 | W
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4 | WG
Pset | SUB (x%, y%, c%) | Pixel plot | 3 | WG
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5 | WG
Rotate | SUB (xOrigin%, yOrigin%, Angle%) | Rotates entire bitmap at specified origin | 3 | W
SaveToFile | SUB (FileName$) | Save BMP to a file | 1 | W
SaveToStream | SUB (Stream) | Save BMP to a stream | 1 | W
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2 | W
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1 | W
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1 | W
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6 | W
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to image | 5 | WG

QBitmap in detail
QBitmap.BMP
Use BMP to assign a new bitmap file, or store the BMP in the image cache.
Example 1:
DIM Bitmap AS QBITMAP
Bitmap.BMP = "C:\WINDOWS\CLOUDS.BMP"
Example 2:
DIM Bitmap1 AS QBITMAP
Bitmap1.BMP = "C:\WINDOWS\CLOUDS.BMP"
DIM Bitmap2 AS QBITMAP
Bitmap2.Draw(0,0,Bitmap1.BMP)
QBitmap.BMPHandle
Use BMPHandle to assign a new bitmap resource, same as using BMP except this searches your EXE for the resource.
Example:
$RESOURCE NEWBMP AS "C:\IMAGES\TEST.BMP"
DIM Bitmap AS QBITMAP
Bitmap.BMPHandle = NEWBMP
QBitmap.Empty
Empty specifies whether the bitmap object contains a bitmap.
Description:
Use Empty to determine if a bitmap has been loaded into the bitmap object. Empty is True (non-zero number) if the bitmap object already contains a bitmap image, and False (0) if it does not.
QBitmap.TransparentMode
TransparentMode determines whether the TransparentColor property's value is automatically calculated or stored with the bitmap object.
tmAuto = 0, tmFixed = 1
Description:
If TransparentMode is set to tmAuto, the TransparentColor property returns the color of the bottom-leftmost pixel of the bitmap image. Otherwise, if TransparentMode is set to tmFixed, the TransparentColor property refers to the color stored in the bitmap object.

QBitmap Examples
DIM BitMap AS QBitMap

BitMap.BMP = "close.bmp"

CREATE Form AS QForm
  CREATE Image1 AS QImage
    Left = 100
    Draw 5, 5, BitMap.BMP
  END CREATE
  Center
  ShowModal
END CREATE


Appendix A: QBUTTON

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QBUTTON

QBUTTON Component

QButton is a general purpose button control.

QButton Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
BMP | STRING | W | W
BMPHandle | RESOURCE | W | W
Cancel | INTEGER | RW | False | W
Caption | STRING | RW | WXG
Color | INTEGER | RW | WX
Cursor | INTEGER | RW | crDefault | W
Default | INTEGER | RW | False | W
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | W
Handle | INTEGER | R | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Kind | INTEGER | RW | bkCustom | W
Layout | INTEGER | RW | blBMPLeft | W
Left | INTEGER | RW | 0 | WXG
ModalResult | INTEGER | RW | mrNone | W
NumBMPs | INTEGER | RW | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | WXG
Spacing | INTEGER | RW | 4 | W
TabOrder | INTEGER | RW | W
Top | INTEGER | RW | 0 | WXG
Width | INTEGER | RW | WXG
Visible | INTEGER | RW | True | WXG

QButton Methods
Method | Type | Description | Params | Support
StartDrag | SUB | Allows Button to be dragged | 0 | W

QButton Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicked on the button | 0 | WXG
OnKeyDown | SUB (Key AS Word, Shift AS INTEGER) | Key held down | 2 | W
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1 | W
OnKeyUp | SUB (Key AS Word, Shift AS INTEGER) | User releases a key | 2 | W
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4 | WXG
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3 | WXG
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4 | WXG
WndProc | SUB (Hwnd%, Msg%, wParam%, lParam%) | Messages sent to Button | 4 | W

QButton Examples
  '-- A drag button

  DIM Form AS QForm
  DIM Button AS QButton

  SUB MouseDown
      Button.StartDrag
      SHOWMESSAGE STR$(Button.Left)+", "+STR$(Button.Top)
  END SUB

  Button.Parent = Form
  Button.OnMouseDown = MouseDown

  Form.ShowModal


Appendix A: QCANVAS

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QCANVAS

QCANVAS Component

QCanvas is an empty image for painting on. Instead of loading your images, you must draw them on the QCanvas.

QCanvas Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
ClientHeight | INTEGER | RW | W
ClientWidth | INTEGER | RW | W
Color | INTEGER | RW | WXG
CopyMode | INTEGER | RW | cmBlackness | W
Cursor | INTEGER | RW | crDefault | W
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | W
Left | INTEGER | RW | 0 | WXG
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
Pixel | 2D ARRAY of INTEGER | RW | WXG
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | W
Top | INTEGER | RW | 0 | WXG
Width | INTEGER | RW | WXG
Visible | INTEGER | RW | True | WXG

QCanvas Methods
Method | Type | Description | Params | Support
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6 | WXG
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3 | W
Draw | SUB (x%, y%, BMP) | Draw Bitmap on Canvas | 3 | WG
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5 | WXG
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5 | WXG
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4 | WXG
Pset | SUB (x%, y%, c%) | Pixel plot | 3 | WXG
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5 | WXG
Repaint | SUB | Force repainting | 0 | W
Rotate | SUB (xOrigin%, yOrigin%, Angle%) | Rotates entire canvas at specified origin | 3 | W
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw image and stretch to fit inside Rect | 2 | W
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1 | W
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1 | W
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6 | W
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to image | 5 | WXG

QCanvas Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicked on canvas | 0 | WXG
OnDblClick | VOID | User double clicked on canvas | 0 | W
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4 | WXG
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3 | WXG
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4 | WXG
OnPaint | VOID | Receives WM_PAINT message | 0 | WXG

QCanvas Examples
'  Pixel by pixel credit scroller for Rapid-Q by William Yu

DIM Canvas AS QCanvas
DIM Form AS QForm
DIM Timer1 AS QTimer
DIM Font AS QFont
DIM Y AS INTEGER
    Y = -20

SUB Resize
  Canvas.Height = Form.ClientHeight
  Canvas.Width = Form.ClientWidth
END SUB

SUB Paint
  Canvas.Textout (65,Y-30,"Beware the power of Rapid-Q!", &H00FF00, 0)
  Canvas.Textout (30,Y,"Credit Scroller written in Rapid-Q by William Yu", &HFFFFFF, 0)
END SUB

SUB TimerOver
  Timer1.Interval = 1  '' Can't go any lower!
  Y = Y + 1            '' Pixel by pixel!
  Paint
END SUB

Form.Width = 400
Form.Height = 200
Form.Center
Form.Color = 0

Font.Name = "Arial"
Font.Size = 12
Font.Color = &H00FF00
Canvas.Parent = Form
Canvas.Font = Font
Canvas.Color = 0
Canvas.OnPaint = Paint

Timer1.Interval = 1
Timer1.OnTimer = TimerOver

Form.Onresize = Resize
Form.ShowModal


Appendix A: QCHECKBOX

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QCHECKBOX

QCHECKBOX Component

QCheckbox is a wrapper for Window's check box control

QCheckbox Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Caption | STRING | RW | WXG
Checked | INTEGER | RW | False | WXG
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Left | INTEGER | RW | 0 | WXG
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | WXG
TabOrder | INTEGER | RW | W
Top | INTEGER | RW | 0 | WXG
Visible | INTEGER | RW | True | WXG
Width | INTEGER | RW | WXG

QCheckbox Methods
Method Type Description Params Support

QCheckbox Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicked check box | 0 | WXG

QCheckbox Examples
  DIM Form AS QForm
  DIM Checkbox as QCheckBox

  SUB Check
    IF CheckBox.Checked THEN
       SHOWMESSAGE "Checked!"
    END IF
  END SUB

  CheckBox.Parent = Form
  CheckBox.OnClick = Check

  Form.ShowModal


Appendix A: QCOMBOBOX

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QCOMBOBOX

QCOMBOBOX Component

QCombobox implements a simple pull down listbox. The first item in any combobox is 0, the next is 1, and so on...

QCombobox Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Color | INTEGER | RW | W
CopyMode | INTEGER | RW | cmBlackness | W
Cursor | INTEGER | RW | crDefault | W
DropDownCount | INTEGER | RW | 8 | W
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Item | ARRAY of STRING | RW | WXG
ItemCount | INTEGER | R | WXG
ItemIndex | INTEGER | RW | -1 | WXG
Left | INTEGER | RW | 0 | WXG
MaxLength | INTEGER | RW | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | WXG
Sorted | INTEGER | RW | False | WG
Style | INTEGER | RW | csDropDown | W
TabOrder | INTEGER | RW | W
Text | STRING | RW | W
Top | INTEGER | RW | 0 | WXG
Visible | INTEGER | RW | True | WXG
Width | INTEGER | RW | WXG

QCombobox Methods
Method | Type | Description | Params | Support
AddItems | SUBI | Add items to combobox | STRINGs, Infinite | WXG
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6 | W
Clear | SUB | Clears entire Combobox | 0 | WXG
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3 | W
DelItems | SUBI | Delete items by their index | Index #s, Infinite | WXG
Draw | SUB (x%, y%, BMP) | Draw Bitmap at (X,Y) | 3 | W
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5 | W
InsertItem | SUB (Index%, String$) | Insert item at Index% | 2 | WXG
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5 | W
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4 | W
Pset | SUB (x%, y%, c%) | Pixel plot | 3 | W
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5 | W
Repaint | SUB | Force repainting of combobox | 0 | W
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2 | W
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1 | W
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1 | W
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6 | W
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to image | 5 | W

QCombobox Events
Event | Type | Occurs when... | Params | Support
OnChange | VOID | User selects a different item | 0 | WXG
OnDrawItem | SUB (Index%, State%, R AS QRect) | Items are redrawn for ownerdraw comboboxes | 3 | W
OnMeasureItem | SUB (Index%, Height%) | Calculate Height for ownerdraw variable comboboxes | 3 | W

QCombobox Examples
  DIM Form AS QForm
  DIM ComboBox AS QComboBox

  SUB ItemChanged
    PRINT ComboBox.Item(ItemIndex)
  END SUB

  ComboBox.Parent = Form
  ComboBox.OnChange = ItemChanged
  ComboBox.AddItems "1. Apples", "2. Oranges", "3. Bananas"

  Form.ShowModal


Appendix A: QCOMPORT

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QCOMPORT

QCOMPORT Component

QComPort provides an easy to use interface to communicate with the com ports. This component was made possible by Dejan Crnila. This component is currently being tested for stability, more functionality is expected in the future.

QComPort Properties
Field | Type | R/W | Default
BaudRate | INTEGER | RW | br110
Connected | INTEGER | R
DataBits | INTEGER | RW | 8
Handle | INTEGER | R
InQue | INTEGER | R
OutQue | INTEGER | R
Parity | INTEGER | RW | prNone
PendingIO | INTEGER | R
Port | INTEGER | RW | 1
ReadBufSize | INTEGER | RW | 1024
StopBits | INTEGER | RW | sbOneStopBit
WriteBufSize | INTEGER | RW | 1024

QComPort Methods
Method | Type | Description | Params
AbortAllIO | SUB | Aborts all asynchronous read/write operations | 0
Close | SUB | Closes communication port | 0
Open | SUB | Opens communication port | 0
PurgeIn | SUB | Clears input buffer and stops all input functions | 0
PurgeOut | SUB | Clears output buffer and stops all output functions | 0
Read | SUB Read(QFile/QMemoryStream, Count%, Wait%) | Reads stream data from com port, Count% < 32000 | 3
ReadString | FUNCTION ReadString$(Count%, Wait%) | Returns a string representation bytes read from comport | 2
WaitForLastIO | SUB | Blocks until last IO is completed | 0
Write | SUB Write(QFile/QMemoryStream, Count%, Wait%) | Writes stream to com port, Count% < 32000 | 3
WriteString | SUB WriteString(Str$, Wait%) | Writes string to communication port | 2

QComPort Events
Event | Type | Occurs when... | Params
OnBreak | VOID | A line break is detected, input and output is suspended until break is cleared | 0
OnClose | VOID | Com port is closed | 0
OnError | VOID | A line error occurs | 0
OnOpen | VOID | Com port is successfully opened | 0
OnRing | VOID | A ring signal is detected, used only with modems. | 0
OnRxChar | SUB (InQue AS INTEGER) | A character(s) arrives in the input buffer. | 1
OnTxEmpty | VOID | Output buffer is flushed | 0

QComPort Examples
$TYPECHECK ON

CONST sbOneStopBit = 0
CONST prNone = 0

DECLARE SUB CommRxChar (InQue AS INTEGER)
DECLARE SUB OpenClick
DECLARE SUB SendClick
DECLARE SUB FormClose

DIM Comm AS QComPort
    Comm.OnRxChar = CommRxChar
    Comm.DataBits = 8
    Comm.StopBits = sbOneStopBit
    Comm.Parity = prNone

CREATE Form AS QFORM
    Caption = "Form1"
    Width = 302
    Height = 240
    Center
    CREATE Label1 AS QLABEL
        Caption = "Com Port:"
        Left = 5
        Top = 9
        Width = 51
    END CREATE
    CREATE ComboBox1 AS QCOMBOBOX
        AddItems "COM1", _
                 "COM2", _
                 "COM3", _
                 "COM4"
        Left = 55
        Width = 65
        Top = 5
        ItemIndex = 0
    END CREATE
    CREATE ComboBox2 AS QCOMBOBOX
        AddItems "110", "300", "600", "1200", "2400", "4800", "9600", _
                 "14400", "19200", "38400", "56000", "57600", "115200"
        Left = 130
        Width = 70
        Top = 5
        ItemIndex = 0
    END CREATE
    CREATE OpenButton AS QBUTTON
        Caption = "&Open"
        Left = 210
        Top = 4
        OnClick = OpenClick
    END CREATE
    CREATE Edit1 AS QEDIT
        Text = ""
        Left = 12
        Top = 40
        Width = 186
    END CREATE
    CREATE SendButton AS QBUTTON
        Caption = "&Send"
        Left = 210
        Top = 38
        Enabled = 0
        OnClick = SendClick
    END CREATE
    CREATE RichEdit1 AS QRICHEDIT
        Left = 11
        Top = 73
        Width = 274
        Height = 132
        PlainText = 1
        ReadOnly = 1
        ScrollBars = 3
        WordWrap = 0
    END CREATE
    OnClose = FormClose
END CREATE

SUB OpenClick
    IF Comm.Connected THEN
       PRINT Comm.InQue
       EXIT SUB
    END IF
    Comm.Port = ComboBox1.ItemIndex + 1
    Comm.BaudRate = ComboBox2.ItemIndex
    Comm.Open
    IF Comm.Connected THEN
       SendButton.Enabled = 1
    ELSE
       ShowMessage("Cannot open port, try another")
    END IF
END SUB

SUB SendClick
    Comm.WriteString(Edit1.Text+CHR$(13)+CHR$(10), 1)
    Comm.WaitForLastIO
END SUB

SUB CommRxChar (InQue AS INTEGER)
    RichEdit1.AddStrings(Comm.ReadString(InQue, 1))
END SUB

SUB FormClose
    IF Comm.Connected THEN
       Comm.Close
    END IF
END SUB

Form.ShowModal


Appendix A: QCOOLBTN

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QCOOLBTN

QCOOLBTN Component

QCoolbtn is an extension of QButton, but allows Flat buttons, and toggle buttons (via GroupIndex).

QCoolbtn Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
AllowAllUp | INTEGER | RW | False | W
BMP | STRING | W | WX
BMPHandle | RESOURCE | W | W
Caption | STRING | RW | WXG
Cursor | INTEGER | RW | crDefault | W
Down | INTEGER | RW | False | WX
Enabled | INTEGER | RW | True | WXG
Flat | INTEGER | RW | False | WX
Font | QFONT | W | W
GroupIndex | INTEGER | RW | 0 | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Layout | INTEGER | RW | blBMPLeft | W
Left | INTEGER | RW | 0 | WXG
NumBMPs | INTEGER | RW | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
ShowHint | INTEGER | RW | False | WXG
Spacing | INTEGER | RW | W
TabOrder | INTEGER | RW | W
Top | INTEGER | RW | 0 | WXG
Width | INTEGER | RW | WXG
Visible | INTEGER | RW | True | WXG

QCoolbtn Methods
Method | Type | Description | Params | Params
StartDrag | SUB | Allows Button to be dragged | 0 | W

QCoolbtn Events
Event | Type | Occurs when... | Params
OnClick | VOID | User clicked on the button | 0 | WXG
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4 | WX
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3 | WX
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4 | WX

QCoolbtn Examples
  '-- An example of toggle buttons (via GroupIndex)

  CONST False = 0: CONST True = 1

  DIM Form AS QForm
  DIM Cool1 AS QCoolbtn
  DIM Cool2 AS QCoolbtn

  Cool1.Parent = Form
  Cool1.GroupIndex = 1       '' Must be > 0
  Cool1.Down = True          '' Button initially down
  Cool2.Parent = Form
  Cool2.GroupIndex = 1       '' Same group as Cool1
  Cool2.Left = 40

  Form.ShowModal


Appendix A: QDIRTREE

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QDIRTREE

QDIRTREE Component

QDirTree is a custom component used to provide users with a Windows Explorer like directory list. It eats up a lot of resources, so use with caution. You don't usually need more than one of these.

QDirTree Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
BorderStyle | INTEGER | RW | bsSingle
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Directory | STRING | RW | False
Enabled | INTEGER | RW | True
FastLoad | INTEGER | RW | False
Font | QFONT | W
Height | INTEGER | RW
HideSelection | INTEGER | RW | False
Hint | STRING | RW
InitialDir | STRING | RW
Left | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ReadOnly | INTEGER | RW | False
ReadOnStart | INTEGER | RW | False
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
Top | INTEGER | RW | 0
Width | INTEGER | RW
Visible | INTEGER | RW | True

QScrollBar Methods
Method | Type | Description | Params
AddDirTypes | SUB | Add directory types | 0
AddDriveTypes | SUB | Add drive types | 0
DelDirTypes | SUB | Del directory types | 0
DelDirTypes | SUB | Del drive types | 0
FullCollapse | SUB | Collapse entire directory list | 0
FullExpand | SUB | Expand entire directory list (slow!) | 0
Reload | SUB | Re-read directories | 0

QScrollBar Events
Event | Type | Occurs when... | Params
OnChange | VOID | Current directory changes | 0

QDirTree Examples
'' A Directory Tree like Windows Explorer.
'' QDIRTREE Component courtesy of Markus Stephany.
'' I took out removable drives because it doesn't work properly.
'' So you won't be able to view your floppy disk drives.  CD-ROM drives
'' are fine, as far as I know...

$TYPECHECK ON

DECLARE SUB ChangeDirectory

CREATE Form AS QForm
  Caption = "Directory Tree"
  Center
  CREATE DirTree AS QDirTree
    InitialDir = CURDIR$
    Width = Form.ClientWidth
    Height = Form.ClientHeight
    OnChange = ChangeDirectory
  END CREATE
  ShowModal
END CREATE

SUB ChangeDirectory
  ShowMessage DirTree.Directory
END SUB


Appendix A: QEDIT

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QEDIT

QEDIT Component

QEdit is a single-line edit control. More or less used to take input from user.

QEdit Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
AutoSize | INTEGER | RW | W
BorderStyle | INTEGER | RW | bsSingle | W
CharCase | INTEGER | RW | ecNormal | W
Color | INTEGER | RW | W
EditText | STRING | RW | W
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | W
Handle | INTEGER | R | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
InputMask | STRING | RW | W
IsMasked | INTEGER | RW | False | W
Left | INTEGER | RW | 0 | WXG
MaxLength | INTEGER | RW | 0 | WXG
Modified | INTEGER | RW | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PasswordChar | INTEGER | RW | W
PopupMenu | QPOPUPMENU | W | W
ReadOnly | INTEGER | RW | False | WXG
SelLength | INTEGER | RW | W
SelStart | INTEGER | RW | W
SelText | STRING | RW | W
ShowHint | INTEGER | RW | False | WXG
TabOrder | INTEGER | RW | W
Text | STRING | RW | WXG
Top | INTEGER | RW | 0 | WXG
Visible | INTEGER | RW | True | WXG
Width | INTEGER | RW | WXG

QEdit Events
Event | Type | Occurs when... | Params | Support
OnChange | VOID | Text changed | 0 | WXG
OnKeyDown | SUB (Key AS WORD, Shift AS INTEGER) | Key held down | 2 | W
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1 | W
OnKeyUp | SUB (Key AS Word, Shift AS INTEGER) | User releases a key | 2 | W
WndProc | SUB (Hwnd%, Msg%, wParam%, lParam%) | Messages sent to QEdit | 4 | W

QEdit Examples
  DIM Form AS QForm
  DIM Edit1 AS QEdit

  Edit1.Parent = Form

  Edit1.Text = "Hello"   '' Set as default text
  Form.ShowModal
QEdit Input Masks
 !	If a ! character appears in the mask, optional characters are represented
        in the EditText as leading blanks. If a ! character is not present, optional
        characters are represented in the EditText as trailing blanks.
 >	If a > character appears in the mask, all characters that follow are in
        uppercase until the end of the mask or until a < character is encountered.
 <      If a < character appears in the mask, all characters that follow are in
        lowercase until the end of the mask or until a > character is encountered.

 <>     If these two characters appear together in a mask, no case checking is
        done and the data is formatted with the case the user uses to enter the data.
 \	The character that follows a \ character is a literal character. Use this
        character to use any of the mask special characters as a literal in the data.
 L	The L character requires an alphabetic character only in this position.
        For the US, this is A-Z, a-z.
 l	The l character permits only an alphabetic character in this position, but
        doesn't require it.

 A	The A character requires an alphanumeric character only in this position.
        For the US, this is A-Z, a-z, 0-9.
 a	The a character permits an alphanumeric character in this position, but
        doesn't require it.
 C	The C character requires an arbitrary character in this position.
 c	The c character permits an arbitrary character in this position, but
        doesn't require it.
 0	The 0 character requires a numeric character only in this position.
 9	The 9 character permits a numeric character in this position, but doesn't
        require it.

 #	The # character permits a numeric character or a plus or minus sign in
        this position, but doesn't require it.
 :	The : character is used to separate hours, minutes, and seconds in times.
        If the character that separates hours, minutes, and seconds is different
        in the regional settings of the Control Panel utility on your computer
        system, that character is used instead.
 /	The / character is used to separate months, days, and years in dates.
        If the character that separates months, days, and years is different
        in the regional settings of the Control Panel utility on your computer
        system, that character is used instead.

 ;	The ; character is used to separate the three fields of the mask.
 _	The _ character automatically inserts spaces into the text. When the
        user enters characters in the field, the cursor skips the _ character.


Appendix A: QFILELISTBOX

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QFILELISTBOX

QFILELISTBOX Component

Use QFileListBox when you want to maintain a listbox with all the files in a specific directory. It can also list directories as well.

QFileListBox Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Directory | STRING | RW
Drive | STRING | RW
Enabled | INTEGER | RW | True
ExtendedSelect | INTEGER | RW | True
Filename | STRING | RW
Font | QFONT | W
Height | INTEGER | RW
Hint | STRING | RW
Item | ARRAY of STRING | RW
ItemCount | INTEGER | RW
ItemHeight | INTEGER | RW
ItemIndex | INTEGER | RW
Left | INTEGER | RW | 0
Mask STRING RW *.*
MultiSelect | INTEGER | RW | False
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
Selected | ARRAY of INTEGER | RW
ShowHint | INTEGER | RW | False
ShowIcons | INTEGER | RW | False
TabOrder | INTEGER | RW
TopIndex | INTEGER | RW
Top | INTEGER | RW | 0
Width | INTEGER | RW
Visible | INTEGER | RW | True

QFileListBox Methods
Method | Type | Description | Params
AddFileTypes | SUBI | Add certain file types to list box | INTEGER, Infinite
DelFileTypes | SUBI | Remove certain file types from list | INTEGER, Infinite

QFileListBox Events
Event | Type | Occurs when... | Params
OnChange | VOID | Directory changes | 0
OnClick | VOID | File was clicked on | 0
OnDblClick | VOID | Selection was double clicked on | 0

QFileListBox Examples
'' Simple Application Launcher
'' How to use the File List Box as a Directory List Box in Rapid-Q by William Yu

$INCLUDE "RAPIDQ.INC"

DECLARE SUB ChangeDirectories
DECLARE SUB ExecuteApplication
DECLARE SUB ResizeForm

CREATE Form AS QForm
  Height = 300
  Width = 450
  CREATE DirList AS QFileListBox     '' Can double as a Directory list box
   ShowIcons = True
   Mask = "*.*"
   AddFileType(ftDirectory)          '' Add Directories
   DelFileType(ftNormal)             '' Remove files (see RAPIDQ.INC for values)
   OnDblClick = ChangeDirectories
   Height = Form.ClientHeight
   Width = 200
  END CREATE
  CREATE EXEList AS QFileListBox
   ShowIcons = True
   Mask = "*.EXE"
   OnDblClick = ExecuteApplication
   Left = 215
   Height = Form.ClientHeight
   Width = 225
  END CREATE
  Center
  Caption = DirList.Directory
  OnResize = ResizeForm
  ShowModal
END CREATE

SUB ChangeDirectories
  ChDir(DirList.Item(DirList.ItemIndex) - "[" - "]")
  DirList.Directory = CurDir$:  EXEList.Directory = CurDir$
  Form.Caption = CurDir$
END SUB

SUB ExecuteApplication
  RUN EXEList.FileName    ' Non-Blocking
'  SHELL EXEList.FileName  ' Blocks, until program terminates
                           ' Becareful running 16-bit applications
END SUB

SUB ResizeForm
  DirList.Height = Form.ClientHeight
  EXEList.Height = Form.ClientHeight
  EXEList.Width = Form.ClientWidth - 215
END SUB


Appendix A: QFILESTREAM

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QFILESTREAM

QFILESTREAM Component

QFilestream is Rapid-Q's way of handling files. It's more elegant than the GET, and PUT method of traditional BASIC.

QFilestream Properties
Field | Type | R/W | Default | Support
LineCount | INTEGER | R | WXG
Position | INTEGER | RW | WXG
Size | INTEGER | R | WXG

QFilestream Methods
Method | Type | Description | Params | Support
Close | SUB | Close the stream | 0 | WXG
CopyFrom SUB (Stream, Bytes%) Copy from another stream
Either QFileStream or QMemoryStream
If Bytes%=0 then the whole stream is copied 		2 W
Open | SUB (FileName$, Method%) | Open a file, Method% see RAPIDQ.INC | 2 | WXG
ReadLine | FUNCTION () AS STRING | Reads an entire line, supports UNIX files | 0 | WXG
ReadNum | FUNCTION (Size%) | Read Size% bytes, returns number | 1 | WXG
ReadBinStr | FUNCTION (Size%) | Read Size% bytes, returns the binary string | 1 | WXG
ReadStr | FUNCTION (Size%) | Read Size% bytes, returns the text string | 1 | WXG
ReadUDT | SUB (MyType) | Read and store data in a MyType structure | 1 | WXG
Seek | SUB (Position%, From%) | Seek to Position%, From% see RAPIDQ.INC | 2 | WXG
WriteLine | SUB (S AS STRING) | Writes string with CR+LF | 1 | WXG
WriteNum | SUB (number, bytes%) | Writes a number to file | 2 | WXG
WriteBinStr | SUB (string, bytes%) | Writes a binary string to file (slow) | 2 | WXG
WriteStr | SUB (string, bytes%) | Writes a text string to file (fast) | 2 | WXG
WriteUDT | SUB (MyType) | Write data stored in a MyType structure | 1 | WXG

QFileStream Examples
  $INCLUDE "RAPIDQ.INC"

  DIM File AS QFileStream

  File.Open("test.bas", fmOpenRead)
  File.ReadStr(S$, File.Size)         '' Read entire file
  PRINT S$                            '' print it
  File.Close

'------------------------------------------------------
  $INCLUDE "RAPIDQ.INC"

  TYPE MyType
      Name AS STRING*30
      Phone AS STRING*8
      Age AS INTEGER
  END TYPE

  DIM Person AS MyType
      Person.Name = "Joe"
      Person.Phone = "555-5555"

  DIM File AS QFileStream
      File.Open("test", fmCreate)
      File.WriteUDT(Address)


Appendix A: QFONT

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QFONT

QFONT Component

QFont is a component used to specify the font, color, and size for your text. It's not meant to be used as a stand-alone component, it has no effect until you assign a QFONT component to a component that uses it.

QFont Properties
Field | Type | R/W | Default | Support
Color | INTEGER | RW | W
FontCount | INTEGER | R | W
FontName | ARRAY of STRING | R | W
Name | STRING | RW | WX
Size | INTEGER | RW | WX

QFont Methods
Method | Type | Description | Params | Support
AddStyles | SUBI | Add styles [bold, italic, etc] | INTEGER, Infinite | W
DelStyles | SUBI | Delete styles [bold, italic, etc] | INTEGER, Infinite | W

QFont Examples
  $INCLUDE "RAPIDQ.INC"

  DIM Font AS QFONT
  DIM Label AS QLABEL

  Font.Name = "Arial"
  Font.AddStyles(fsBold, fsItalic)
  Label.Font = Font      '' Assign font values


Appendix A: QFONTDIALOG

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QFONTDIALOG

QFONTDIALOG Component

QFontDialog displays Window's font selection dialog

QFontDialog Properties
Field | Type | R/W | Default
Color | INTEGER | RW
FontCount | INTEGER | R
FontName | ARRAY of STRING | R
MaxFontSize | INTEGER | RW
MinFontSize | INTEGER | RW
Name | STRING | RW
Size | INTEGER | RW

QFontDialog Methods
Method | Type | Description | Params
AddStyles | SUBI | Add styles [bold, italic, etc] | INTEGER, Infinite
DelStyles | SUBI | Delete styles [bold, italic, etc] | INTEGER, Infinite
AddOptions | SUBI | Add options [fdLimitSize, fdNoSizeSel, etc.] | INTEGER, Infinite
DelOptions | SUBI | Delete options [fdNoStyleSel, fdScalableOnly, etc.] | INTEGER, Infinite
Execute | FUNCTION | Returns TRUE or FALSE | 0
GetFont | SUB GetFont(F AS QFONT) | Get font attributes | 1
SetFont | SUB SetFont(F AS QFONT) | Set font attributes | 1

QFontDialog Events
Event | Type | Occurs when... | Params
OnApply | VOID | User clicks on apply button | 0

QFontDialog Examples
  '-- Simple demo
  DIM FontDialog AS QFontDialog
  DIM Font AS QFont
      Font.Name = "Arial"

  FontDialog.GetFont(Font)
  IF FontDialog.Execute THEN
    ShowMessage "You selected "+FontDialog.Name
    FontDialog.SetFont(Font)
  END IF


Appendix A: QFORM

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QFORM

QFORM Component

QForm is a standard application Window. You can put any visible control component on a QForm, such as QEdit, QLabel, QButton, etc...

QForm Properties
Field | Type | R/W | Default | Support
AutoScroll | INTEGER | RW | True | W
Specify whether scroll bars should appear automatically on the form if it is not large enough to display all of its controls
BorderStyle | INTEGER | RW | bsSizeable | WXG
Change border style of your form, see RAPIDQ.INC for all the constants.
Caption | STRING | RW | WXG
ClientHeight | INTEGER | RW | WXG
ClientWidth | INTEGER | RW | WXG
Color | INTEGER | RW | W
Cursor | INTEGER | RW | crDefault | W
FormStyle | INTEGER | RW | fsNormal | W
Handle | INTEGER | R | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | W
IcoHandle | RESOURCE | W | W
Icon | STRING | W | W
Assign an icon filename to appear as the default for your form
KeyPreview | INTEGER | RW | False | W
Left | INTEGER | RW | 0 | WXG
ModalResult | INTEGER | W | W
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | W
Top | INTEGER | RW | 0 | WXG
Visible | INTEGER | RW | False | WXG
Width | INTEGER | RW | WXG
WindowState | INTEGER | RW | wsNormal | W

QForm Methods
Method | Type | Description | Params | Support
AddBorderIcons | SUBI | Add Border Icons | INTEGER, Infinite | W
Center | SUB | Used to center a form | 0 | WXG
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6 | W
Close | SUB | Close form | 0 | WXG
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3 | W
DelBorderIcons | SUBI | Remove Border Icons | INTEGER, Infinite | W
Draw | SUB (x%, y%, BMP) | Draw Bitmap on Canvas | 3 | W
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5 | W
HideTitleBar | SUB | Hides Caption | 0 | W
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draw line on form | 5 | W
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4 | W
Pset | SUB (x%, y%, c%) | Pixel plot | 3 | W
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5 | W
Repaint | SUB | Repaints the entire form | 0 | W
Show | SUB | Used to show form when hidden | 0 | WX
ShowModal | FUNCTION | Display form and wait for result | 0 | WXG
ShowTitleBar | SUB | Displays Caption | 0 | W
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2 | W
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1 | W
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1 | W
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6 | W
TextOut | SUB (x%, y%, s$, fc%, bc%) | Write text to form | 5 | W

QForm Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicks on open area of form | 0 | W
OnClose | SUB (Action AS INTEGER) | Form closes | 1 | W
OnKeyDown | SUB (Key AS Word, Shift AS INTEGER) | Key held down | 2 | W
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1 | W
OnKeyUp | SUB (Key AS Word, Shift AS INTEGER) | User releases a key | 2 | W
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4 | W
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3 | W
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4 | W
OnPaint | VOID | Form requires repainting | 0 | W
OnResize | VOID | Form is resized | 0 | W
OnShow | VOID | Form is displayed | 0 | W
WndProc | SUB (Hwnd%, Msg%, wParam%, lParam%) | Messages posted/sent to form | 4 | W
Only one WndProc per Form is allowed. So if you have multiple forms, only one may be able to receive messages at a time. (Future consideration to correct this)

QForm Examples
  DIM Form AS QForm
  DIM Button AS QBUTTON

  Button.Parent = Form     '' Add button to form container
  Form.Center
  Form.Caption = "Hello world!"

  IF Form.ShowModal THEN
    PRINT "Return result is TRUE"
  ELSE
    PRINT "Return result is FALSE"
  END IF


Appendix A: QGAUGE

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QGAUGE

QGAUGE Component

QGauge is a sophisticated progress monitor. Used visually to give users the progress of an operation.

QGauge Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
BackColor | INTEGER | RW
BorderStyle | INTEGER | RW | bsSingle
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
ForeColor | INTEGER | RW
Height | INTEGER | RW
Hint | STRING | RW
Kind | INTEGER | RW | gkHorizontalBar
Left | INTEGER | RW
Max | INTEGER | RW | 100
Min | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
Position | INTEGER | RW | 0
ShowHint | INTEGER | RW | False
ShowText | INTEGER | RW | True
Top | INTEGER | RW
Visible | INTEGER | RW | True
Width | INTEGER | RW

QGauge Examples
$INCLUDE "RAPIDQ.INC"

CREATE Form AS QForm
  Center
  CREATE Gauge AS QGauge
    Position = 20
    Kind = gkPie
  END CREATE
  ShowModal
END CREATE


Appendix A: QGLASSFRAME

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QGLASSFRAME

QGLASSFRAME Component

QGlassFrame is a 3rd party Rapid-Q component, that makes your form look transparent and shaded, made possible by Aleksey Xacker. No support is offered for this component, there are some special cases in using this component.

QGlassFrame Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
ClientHeight | INTEGER | RW
ClientWidth | INTEGER | RW
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Handle | INTEGER | RW
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW
Moveable | INTEGER | RW | True
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ShowHint | INTEGER | RW | False
Top | INTEGER | RW
Transparency | INTEGER | RW | 60
TransparentColor | INTEGER | RW | 0
Width | INTEGER | RW

QGlassFrame Methods
Method Type Description Params

QGlassFrame Examples
$INCLUDE "RAPIDQ.INC"

CREATE Form AS QForm
  Caption = "Transparent Form"
  Center
  CREATE GlassFrame AS QGlassFrame
      Align = alClient
  END CREATE
  ShowModal
END CREATE

'------- Weird transparency color error
$INCLUDE "RAPIDQ.INC"

CREATE Form AS QForm
  Caption = "Transparent Form"
  Center
  CREATE GlassFrame AS QGlassFrame
      Align = alClient
      TransparentColor = &HFF0000
  END CREATE
  Show
END CREATE

'-- I don't know what's wrong, but doing this seems to
'-- work better than using ShowModal when changing colors

DO
    DoEvents
LOOP UNTIL Form.Visible = 0


Appendix A: QGROUPBOX

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QGROUPBOX

QGROUPBOX Component

QGroupBox implements Window's group box.

QGroupBox Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
Caption | STRING | RW
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
Handle | INTEGER | R
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
Top | INTEGER | RW | 0
Visible | INTEGER | RW | True
Width | INTEGER | RW

QGroupBox Methods
Method | Type | Description | Params
Repaint | SUB | Repaint groupbox, and anything inside it | 0

QGroupBox Events
Event | Type | Occurs when... | Params
OnClick | VOID | User clicked on groupbox | 0
OnDblClick | VOID | User double clicked on groupbox | 0
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4

QGroupBox Examples
CREATE Form AS QForm
  CREATE GroupBox AS QGroupBox
    Caption = " Group Box "
    Left = 100
    CREATE Button AS QButton
      Caption = "Button"
    END CREATE
  END CREATE
  Center
  ShowModal
END CREATE


Appendix A: QHEADER

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QHEADER

QHEADER Component

QHeader is a set of column headers that the user can resize at runtime.

QHeader Internal Types
   TYPE SectionsType       '' ie. Header.Sections(0).Caption
     Alignment AS INTEGER  '' Default taLeftJustify
     AllowClick AS INTEGER '' True
     Caption AS STRING
     MaxWidth AS INTEGER   '' Default  10000
     MinWidth AS INTEGER   '' Default 0
     Style AS INTEGER      '' Default hsText
     Width AS INTEGER      '' Default 50
   END TYPE
QHeader Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
ClientHeight | INTEGER | RW
ClientWidth | INTEGER | RW
CopyMode | INTEGER | RW | cmBlackness
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
Handle | INTEGER | RW
Height | INTEGER | RW
Hint | STRING | RW
HotTrack | INTEGER | RW | False
Left | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
Pixel | 2D ARRAY of INTEGER | RW
PopupMenu | QPOPUPMENU | W
Sections | ARRAY of SectionsType | RW
SectionsCount | INTEGER | R
ShowHint | INTEGER | RW | False
Top | INTEGER | RW | 0
Width | INTEGER | RW
Visible | INTEGER | RW | True

QHeader Methods
Method | Type | Description | Params
AddSections | SUBI | Add new sections to header | STRING, Infinite
Clear | SUB | Clears all sections | 0
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3
Draw | SUB (x%, y%, BMP) | Draw Bitmap at (X,Y) | 3
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4
Pset | SUB (x%, y%, c%) | Pixel plot | 3
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5
Repaint | SUB | Force repainting of header | 0
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to image | 5

QHeader Events
Event | Type | Occurs when... | Params
OnDrawSection | SUB (Index%, Pressed%, Rect AS QRECT) | A header section needs to be redisplayed. Header section's Style property must be hsOwnerDraw | 3
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4
OnResize | VOID | Size of header control changes | 0
OnSectionClick | SUB (Index%) | Header section Index% is clicked | 1
OnSectionResize | SUB (Index%) | Header section is resized | 1
OnSectionTrack | SUB (Index%, Width%, State%) | Header section is dragged | 3

QHeader Examples
$TYPECHECK ON
$INCLUDE "RAPIDQ.INC"

DECLARE SUB DrawSection (Index AS INTEGER, Pressed AS INTEGER, Rect AS QRECT, Sender AS QHEADER)
DECLARE SUB SectionTrack (Index AS INTEGER, Width AS INTEGER, State AS INTEGER, Sender AS QHEADER)

CREATE Form AS QFORM
    Caption = "QHeader example"
    Center
    CREATE Header AS QHEADER
        AddSections "1", "2", "3"
        Sections(1).AllowClick = FALSE
        Sections(0).Style = hsOwnerDraw
        Sections(0).Width = 100
        Sections(1).Style = hsOwnerDraw
        Sections(2).Style = hsOwnerDraw
        OnDrawSection = DrawSection
        OnSectionTrack = SectionTrack
    END CREATE
    CREATE ListBox1 AS QLISTBOX
        Align = alLeft
        Width = 100
        AddItems "1. Rapid-Q", "2. Taxes"
    END CREATE
    CREATE StatusBar AS QSTATUSBAR
        SimplePanel = TRUE
        SimpleText = "Not moving"
    END CREATE
    ShowModal
END CREATE

SUB DrawSection (Index AS INTEGER, Pressed AS INTEGER, Rect AS QRECT, Sender AS QHEADER)
    Sender.TextOut(Rect.Left+5,Rect.Top+1, STR$(Index+1), &HFF0000, -1)
    SELECT CASE Index
        CASE 0
            Sender.FillRect(Rect.Left+20,Rect.Top+2,Rect.Right-20,Rect.Bottom-2, &H00FF00)
        CASE 1
            Sender.Circle(Rect.Left+20,Rect.Top+2,Rect.Right-20,Rect.Bottom-2, &HFF, &HFF)
        CASE 2
    END SELECT
END SUB

SUB SectionTrack (Index AS INTEGER, Width AS INTEGER, State AS INTEGER, Sender AS QHEADER)
    StatusBar.SimpleText = "Moving "+STR$(Width)
    SELECT CASE Index
        CASE 0
            ListBox1.Width = Width
    END SELECT
END SUB


Appendix A: QIMAGE

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QIMAGE

QIMAGE Component

QImage is used to display a graphical image (BMP/ICON). It can also be used to draw primitive graphics.

QImage Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
Autosize | INTEGER | RW | False
BMP | STRING | W
BMPHandle | RESOURCE | W
Center | INTEGER | RW | False
CopyMode | INTEGER | RW | cmBlackness
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
Handle | INTEGER | RW
Height | INTEGER | RW
Hint | STRING | RW
ICOHandle | RESOURCE | W
Icon | STRING | W
IncrementalDisplay | INTEGER | RW | False
Left | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
Pixel | 2D ARRAY of INTEGER | RW
PopupMenu | QPOPUPMENU | W
ShowHint | INTEGER | RW | False
Stretch | INTEGER | RW | False
Top | INTEGER | RW | 0
Transparent | INTEGER | RW | False
Width | INTEGER | RW
Visible | INTEGER | RW | True

QImage Methods
Method | Type | Description | Params
Center | SUB | Centers image | 0
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3
Draw | SUB (x%, y%, BMP) | Draw Bitmap at (X,Y) | 3
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4
Pset | SUB (x%, y%, c%) | Pixel plot | 3
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5
Repaint | SUB | Force repainting of image | 0
Rotate | SUB (xOrigin%, yOrigin%, Angle%) | Rotates entire image at specified origin | 3 | W
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to image | 5

QImage Events
Event | Type | Occurs when... | Params
OnClick | VOID | User clicked on image | 0
OnDblClick | VOID | User double clicked on image | 0
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4

QImage Examples
  '-- How to use a resource file

  CONST False = 0
  CONST True = 1

  $RESOURCE RES_BMP1 AS "C:\WINDOWS\CLOUDS.BMP"

  DIM Form AS QForm
  DIM Image AS QImage

  Image.Parent = Form
  Image.Autosize = True
  Image.BMPHandle = RES_BMP1
  Form.ShowModal


Appendix A: QIMAGELIST

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QIMAGELIST

QIMAGELIST Component

QImageList is an array of images, all of the same/fixed size.

QImageList Properties
Field | Type | R/W | Default
BkColor | INTEGER | RW | 0
BlendColor | INTEGER | RW | 0
Count | INTEGER | RW
DrawStyle | INTEGER | RW | dsNormal
Font | QFONT | W
GetBMP | ARRAY of IMAGES/BMP | R
GetICO | ARRAY of IMAGES/ICO | R
Handle | INTEGER | RW
Height | INTEGER | RW
ImageType | INTEGER | RW | itImage
Masked | INTEGER | RW | True
ShareImages | INTEGER | RW | False
Width | INTEGER | RW

QImageList Methods
Method | Type | Description | Params
AddBMPFile | SUB (FileName$, MaskColor%) | Add BMP file to Imagelist | 2
AddICOFile | SUB (FileName$) | Add Icon file to Imagelist | 1
AddBMPHandle | SUB (BMP_Resource, MaskColor%) | Add BMP to Imagelist | 2
AddICOHandle | SUB (ICO_Resource) | Add Icon to Imagelist | 1
Clear | SUB | Removes all images | 0
Delete | SUB (Index%) | Delete image at Index% | 1
InsertBMPFile | SUB (Index%, Filename$, Mask%) | Insert BMP file at Index% | 3
InsertICOFile | SUB (Index%, Filename$) | Insert Icon file at Index% | 2
InsertBMPHandle | SUB (Index%, BMP_Resource, Mask%) | Insert BMP at Index% | 3
InsertICOHandle | SUB (Index%, ICO_Resource) | Insert Icon at Index% | 2

QImageList Examples
' Imagelist demo

$resource bmp_handle as "nolight.bmp"
$resource ico_handle as "close.ico"

DIM ImageList AS QImageList
DIM Form AS QForm
DIM Button AS QButton

ImageList.Width = 9
ImageList.Height = 17
ImageList.AddBMPHandle bmp_handle,0
'ImageList.AddBMPFile "nolight.bmp", 0
ImageList.AddICOHandle ico_handle
'ImageList.AddICOFile "close.ico"

Button.Parent = Form
Button.BMP = Imagelist.GetBMP(0)

Form.Icon = ImageList.GetICO(1)

Form.Showmodal


Appendix A: QLABEL

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QLABEL

QLABEL Component

QLabel is a non-windowed control used to display text on a form/container.

QLabel Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Alignment | INTEGER | RW | taLeftJustify | W
Angle | INTEGER | RW | 0 | W
Autosize | INTEGER | RW | False | W
Caption | STRING | RW | WXG
Color | INTEGER | RW | WX
Cursor | INTEGER | RW | crDefault | W
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | W
Handle | INTEGER | R | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Layout | INTEGER | RW | W
Left | INTEGER | RW | 0 | WXG
LowerColor | INTEGER | RW | clBtnShadow | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | WXG
TextStyle | INTEGER | RW | lsNone | W
Top | INTEGER | RW | 0 | WXG
Transparent | INTEGER | RW | False | W
UpperColor | INTEGER | RW | clBtnHighlight | W
Visible | INTEGER | RW | True | WXG
Width | INTEGER | RW | WXG
Wordwrap | INTEGER | RW | False | W

QLabel Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicks on label | 0 | W
OnDblClick | VOID | User double clicked on label | 0 | W
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 3 | W
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 2 | W
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 3 | W
WndProc | SUB (Hwnd%, Msg%, wParam%, lParam%) | Messages sent to QLabel | 4 | W

QLabel Examples
  DIM Form AS QForm
  DIM Label1 AS QLabel

  Label1.Parent = Form

  Label1.Text = "Hello"
  Form.ShowModal

'--------------------------------------------------------

  ' Note that rotated labels only work with true type
  ' fonts, such as Arial and Courier New

  DIM Form AS QForm
  DIM Label1 AS QLabel
  DIM Font AS QFont

  Font.Name = "Arial"

  Label1.Parent = Form
  Label1.Font = Font
  Label1.Text = "Hello"
  Label1.Angle = 45
  Form.ShowModal


Appendix A: QLISTBOX

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QLISTBOX

QLISTBOX Component

QListbox implements a generic (veritcal scrolling) Windows listbox. The first item in any listbox is 0, the next is 1, and so on...

QListbox Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
BorderStyle | INTEGER | RW | bsSingle | W
Color | INTEGER | RW | WX
Columns | INTEGER | RW | 0 | W
CopyMode | INTEGER | RW | cmBlackness | W
Cursor | INTEGER | RW | crDefault | W
Enabled | INTEGER | RW | True | WXG
ExtendedSelect | INTEGER | RW | True | WX
Font | QFONT | W | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | 0 | WXG
Item | ARRAY of STRING | RW | WXG
ItemCount | INTEGER | R | WXG
ItemHeight | INTEGER | RW | W
ItemIndex | INTEGER | RW | -1 | WXG
Left | INTEGER | RW | 0 | WXG
MultiSelect | INTEGER | RW | False | WX
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
Selected | ARRAY of INTEGER | RW | WX
ShowHint | INTEGER | RW | False | WXG
Sorted | INTEGER | RW | False | WG
Style | INTEGER | RW | lbStandard | W
TopIndex | INTEGER | RW | W
TabOrder | INTEGER | RW | W
TabWidth | INTEGER | RW | 0 | W
Top | INTEGER | RW | 0 | WXG
Visible | INTEGER | RW | True | WXG
Width | INTEGER | RW | WXG

QListbox Methods
Method | Type | Description | Params | Support
AddItems | SUBI | Add items to listbox | STRINGs, Infinite | WXG
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6 | W
Clear | SUB | Clears entire listbox | 0 | WXG
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3 | W
DelItems | SUBI | Delete items by their index | Index #s, Infinite | WXG
Draw | SUB (x%, y%, BMP) | Draw Bitmap at (X,Y) | 3 | W
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5 | W
InsertItem | SUB (Index%, String$) | Insert item at Index% | 2 | WXG
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5 | W
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4 | W
Pset | SUB (x%, y%, c%) | Pixel plot | 3 | W
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5 | W
Repaint | SUB | Force repainting of listbox | 0 | W
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2 | W
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1 | W
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1 | W
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6 | W
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to image | 5 | W

QListbox Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicks on item | 0 | WXG
OnDblClick | VOID | User double clicks on an item | 0 | WXG
OnDrawItem | SUB (Index%, State%, R AS QRect) | Items are redrawn for ownerdraw listboxes | 3 | W
OnEnter | VOID | User presses enter to select item | 0 | W
OnMeasureItem | SUB (Index%, Height%) | Calculate Height for ownerdraw variable listboxes | 3 | W
WndProc | SUB (Hwnd%, Msg%, wParam%, lParam%) | Messages sent to Listbox | 4 | W

QListbox Examples
  DIM Form AS QForm
  DIM ListBox AS QListBox

  ListBox.Parent = Form
  ListBox.AddItems "1. Apples", "2. Oranges", "3. Bananas"
  ListBox.DelItems 1,2       '' Deletes Oranges and Bananas

  ListBox.Item(0) = "1. Strawberries"   '-- Change the first item

  Form.ShowModal


Appendix A: QLISTVIEW

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QLISTVIEW

QLISTVIEW Component

QListView provides 3 different ways of displaying items on a form. Items can be displayed in columns with column headers and sub-items, or individually with large/small icons.

QListView Internal Types
   TYPE ItemType           '' ie. ListView.Item(0).Caption
     Caption AS STRING
     ImageIndex AS INTEGER
     StateIndex AS INTEGER
   END TYPE

   TYPE ColumnType         '' ie. ListView.Column(0).Width
     Caption AS STRING
     Width AS INTEGER
   END TYPE
QListView Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
BorderStyle | INTEGER | RW | bsSingle
CheckBoxes | INTEGER | RW | False
Color | INTEGER | RW
Column | ARRAY of ColumnType | RW
ColumnClick | INTEGER | RW | True
ColumnsCount | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
GridLines | INTEGER | RW | False
Handle | INTEGER | R
Height | INTEGER | RW
Hint | STRING | RW
HotTrack | INTEGER | RW | False
Item | ARRAY of ItemType | RW
ItemCount | INTEGER | RW
ItemIndex | INTEGER | RW
LargeImages | QIMAGELIST | W
Left | INTEGER | RW | 0
MultiSelect | INTEGER | RW | False
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ReadOnly | INTEGER | RW | False
RowSelect | INTEGER | RW | False
SelCount | INTEGER | RW
Selected | ARRAY of INTEGER | RW
ShowColumnHeaders | INTEGER | RW | True
ShowHint | INTEGER | RW | False
SmallImages | QIMAGELIST | W
SortType | INTEGER | RW | stNone
StateImages | QIMAGELIST | W
SubItem | 2D ARRAY of STRING | RW
TabOrder | INTEGER | RW
Top | INTEGER | RW | 0
Width | INTEGER | RW
ViewStyle | INTEGER | RW | vsIcon
Visible | INTEGER | RW | True

QListView Methods
Method | Type | Description | Params
AddColumns | SUBI | Add column headers to listview | STRING, Infinite
AddItems | SUBI | Add items to listview | STRING, Infinite
AddSubItem | SUB (Index%, String$) | Add sub item to Index% | 2
Clear | SUB | Clear all items in listview | 0
ClearColumns | SUB | Clear all columns in listview | 0
DelItems | SUBI | Delete items from listview | INTEGER, Infinite
DelSubItem | SUB (Index%, SubIndex%) | Delete subitem from listview | 2
InsertItem | SUB (Index%, String$) | Insert item at Index% | 2
InsertSubItem | SUB (Index%, SubIndex%, String$) | Insert subitem | 3
SwapItem | SUB (Index1%, Index2%) | Swap items | 2

QListView Events
Event | Type | Occurs when... | Params
OnClick | VOID | Item was clicked on | 0
OnChange | SUB (Index%, Change AS BYTE) | Item changed (text, image, or state) | 2
OnColumnClick | SUB (Column%) | Column header was clicked | 1
OnDblClick | VOID | Selection was double clicked on | 0
OnKeyPressed | SUB (Key AS BYTE) | Key was pressed | 1

QListView Examples
' Simple .ZIP viewer (doesn't extract or anything useful like that).
' You're free to modify and distribute the code without restrictions.
' Written in Rapid-Q by William Yu
' Demonstrates QOpenDialog, QFileStream, QListView, QMainMenu, QMenuItem
'              and QImageList.

$APPTYPE GUI
$TYPECHECK ON
$INCLUDE "RAPIDQ.INC"

$RESOURCE ICO_ZIP AS "ZIP.ICO"
$RESOURCE ICO_APP AS "APP.ICO"

DECLARE SUB ZipView (ZIPFile AS STRING)
DECLARE SUB FormResize
DECLARE SUB OpenClick
DECLARE SUB ExitClick
DECLARE SUB IconClick
DECLARE SUB SmallIconClick
DECLARE SUB ReportClick
DECLARE SUB ItemDblClick

CONST SIG = &H04034B50         ' ZIP Signature/ID

TYPE ZFHeader
  Signature AS LONG
  Version AS WORD
  GPBFlag AS WORD              ' ?
  Compress AS WORD             ' Compression types
  DateTime AS LONG             ' Packed format
  CRC32 AS LONG
  CSize AS LONG                ' Compressed size
  USize AS LONG                ' Uncompressed size
  FileNameLen AS LONG
END TYPE

TYPE PackedDateType            ' I think this is it:
  Year AS SHORT                ' 7 bits
  Month AS BYTE                ' 4 bits
  Day AS BYTE                  ' 5 bits
  Hour AS BYTE                 ' 5 bits
  Minute AS BYTE               ' 6 bits
  Secs AS BYTE                 ' 5 bits
END TYPE                       ' Total = 32 bits

DIM CompType(0 TO 9) AS STRING
    CompType(0) = "Stored"
    CompType(1) = "Shrunk"
    CompType(2) = "Reduced1"
    CompType(3) = "Reduced2"
    CompType(4) = "Reduced3"
    CompType(5) = "Reduced4"
    CompType(6) = "Imploded"
    CompType(7) = "Defalted"
    CompType(8) = "DeflatN"      '' Could be DeflatX as well...
    CompType(9) = "DeflatX"

DIM OpenItem AS QMenuItem
    OpenItem.Caption = "&Open"
    OpenItem.OnClick = OpenClick
DIM BreakItem AS QMenuItem
    BreakItem.Caption = "-"
DIM ExitItem AS QMenuItem
    ExitItem.Caption = "E&xit"
    ExitItem.OnClick = ExitClick
DIM IconItem AS QMenuItem
    IconItem.Caption = "vs&Icon"
    IconItem.RadioItem = True
    IconItem.OnClick = IconClick
DIM SmallIconItem AS QMenuItem
    SmallIconItem.Caption = "vs&SmallIcon"
    SmallIconItem.RadioItem = True
    SmallIconItem.OnClick = SmallIconClick
DIM ReportItem AS QMenuItem
    ReportItem.Caption = "vs&Report"
    ReportItem.RadioItem = True
    ReportItem.Checked = True
    ReportItem.OnClick = ReportClick

DIM FileMenu AS QMenuItem
    FileMenu.Caption = "&File"
    FileMenu.AddItems OpenItem, BreakItem, ExitItem
DIM ViewMenu AS QMenuItem
    ViewMenu.Caption = "&View"
    ViewMenu.AddItems IconItem, SmallIconItem, ReportItem

DIM ImageList1 AS QImageList
    ImageList1.Height = 32
    ImageList1.Width = 32
    ImageList1.AddICOHandle ICO_APP
    ImageList1.AddICOHandle ICO_ZIP
DIM ImageList2 AS QImageList            ' Scale 16x16
    ImageList2.Height = 16
    ImageList2.Width = 16
    ImageList2.AddICOHandle ICO_APP
    ImageList2.AddICOHandle ICO_ZIP

CREATE Form AS QForm
  ICOHandle = ICO_ZIP
  Center
  OnResize = FormResize
  Height = 330
  Width = 525
  Caption = "Simple .ZIP Viewer for Rapid-Q"
  CREATE MainMenu AS QMainMenu
    AddItems FileMenu, ViewMenu
  END CREATE
  CREATE ListView AS QListView
    Width = Form.ClientWidth
    Height = Form.ClientHeight
    SmallImages = ImageList2
    LargeImages = ImageList1
    ViewStyle = vsReport
    AddColumns "FileName","Length","Method","Size","Rate","Date","Time","CRC-32"
    Column(0).Width = 200
    Column(4).Width = 40
    Column(5).Width = 70
    Column(7).Width = 70
    OnDblClick = ItemDblClick
  END CREATE
  ShowModal
END CREATE

'------------------------------------------------------------------

SUB ZipView (ZIPFile AS STRING)
  DIM Hdr      AS ZFHeader
  DIM ZF       AS QFileStream
  DIM PD       AS PackedDateType
  DIM FileName AS STRING
  DIM Index    AS INTEGER

  IF ZF.Open(ZIPFile, fmOpenRead) = False THEN
    ShowMessage("Problem with reading "+ZIPFile)
    EXIT SUB
  END IF

  ListView.Clear
  Hdr.Signature = ZF.ReadNum(4)

  Index = 0
  WHILE Hdr.Signature = SIG
    Hdr.Version  = ZF.ReadNum(2)
    Hdr.GPBFlag  = ZF.ReadNum(2)
    Hdr.Compress = ZF.ReadNum(2)
    Hdr.DateTime = ZF.ReadNum(4)
    Hdr.CRC32 = ZF.ReadNum(4)
    Hdr.CSize = ZF.ReadNum(4)
    Hdr.USize = ZF.ReadNum(4)
    Hdr.FileNameLen = ZF.ReadNum(4)

    FileName = ZF.ReadStr(Hdr.FileNameLen)

    PD.Year = ((Hdr.DateTime SHR 25) AND &H7F) + 1980
    PD.Month = (Hdr.DateTime SHR 21) AND &H0F
    PD.Day = (Hdr.DateTime SHR 16) AND &H1F
    PD.Hour = (Hdr.DateTime SHR 11) AND &H1F
    PD.Minute = (Hdr.DateTime SHR 5) AND &H3F
    PD.Secs = Hdr.DateTime AND &H1F
    ListView.AddItems FileName
    IF INSTR(UCASE$(FileName), ".ZIP") THEN
      ListView.Item(Index).ImageIndex = 1
    END IF
    ListView.AddSubItem Index, STR$(Hdr.USize)
    ListView.AddSubItem Index, CompType(Hdr.Compress)
    ListView.AddSubItem Index, STR$(Hdr.CSize)
    IF Hdr.USize = 0 THEN
      ListView.AddSubItem Index, "----"
    ELSE
      ListView.AddSubItem Index, STR$(INT((Hdr.USize - Hdr.CSize) / Hdr.USize * 100))+"%"
    END IF
    ListView.AddSubItem Index, STR$(PD.Month)+"-"+STR$(PD.Day)+"-"+STR$(PD.Year)
    ListView.AddSubItem Index, STR$(PD.Hour)+":"+STR$(PD.Minute)
    ListView.AddSubItem Index, LCASE$(HEX$(Hdr.CRC32))
    ZF.Seek(Hdr.CSize, soFromCurrent)
    Hdr.Signature = ZF.ReadNum(4)
    Index = Index + 1
  WEND

  IF Index = 0 THEN
     '-- Likely not a .ZIP file
     ShowMessage(ZIPFile+" is not a valid ZIP file!")
  END IF
END SUB

SUB OpenClick
  DIM OpenDialog AS QOpenDialog

  OpenDialog.InitialDir = CurDir$
  OpenDialog.Filter = "ZIP Files (*.zip)|*.zip|All Files (*.*)|*.*"

  IF OpenDialog.Execute THEN
    ZipView(OpenDialog.FileName)
  END IF
END SUB

SUB ExitClick
  Form.Close
END SUB

SUB FormResize
  ListView.Height = Form.ClientHeight
  ListView.Width = Form.ClientWidth
END SUB

SUB IconClick
  IconItem.Checked = True
  ListView.ViewStyle = vsIcon
END SUB

SUB SmallIconClick
  SmallIconItem.Checked = True
  ListView.ViewStyle = vsSmallIcon
END SUB

SUB ReportClick
  ReportItem.Checked = True
  ListView.ViewStyle = vsReport
END SUB

SUB ItemDblClick
  IF ListView.ItemIndex >= 0 THEN
    ShowMessage("Can't extract "+ListView.Item(ListView.ItemIndex).Caption);
  END IF
END SUB


Appendix A: QMAINMENU

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QMAINMENU

QMAINMENU Component

QMainmenu implements a container for your menu items. Use it to add a drop-down main menu to a form.

QMainMenu Properties
Field | Type | R/W | Default | Support
Parent | QFORM | W | WXG

QMainMenuCombobox Methods
Method | Type | Description | Params | Support
AddItems | SUBI | Add items to combobox | QMENUITEMs, Infinite | WXG
Insert | SUB (I%, Item AS QMENUITEM) | Insert an item | 2 | W

QMainMenu Examples
  DIM Form AS QForm
  DIM MainMenu AS QMainMenu
  DIM Item1 AS QMenuItem

  Item1.Caption = "&File"
  MainMenu.AddItems Item1
  MainMenu.Parent = Form

  Form.ShowModal


Appendix A: QMEMORYSTREAM

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QMEMORYSTREAM

QMEMORYSTREAM Component

QMemorystream is used to store temporary data to memory for manipulation.

QMemorystream Properties
Field | Type | R/W | Default | Support
LineCount | INTEGER | R | W
Pointer | INTEGER | R | WXG
Position | INTEGER | RW | WXG
SetSize | INTEGER | W | WXG
Size | INTEGER | RW | WXG

QMemorystream Methods
Method | Type | Description | Params | Support
Close | SUB | Close the stream | 0 | WXG
CopyFrom SUB (Stream, Bytes%) Copy from another stream
Either QFileStream or QMemoryStream
If Bytes%=0 then the whole stream is copied 		2 WXG
ReadLine | FUNCTION () AS STRING | Reads an entire line | 0 | W
ReadNum | FUNCTION (Size%) AS DOUBLE | Read Size% bytes, returns number | 1 | WXG
ReadStr | FUNCTION (Size%) AS STRING | Read Size% bytes, returns the string | 1 | WXG
ReadBinStr | FUNCTION (Size%) AS STRING | Read Size% bytes, returns the binary string | 1 | W
ReadUDT | SUB (MyType) | Read and store data in a MyType structure | 1 | WXG
Seek | SUB (Position%, From%) | Seek to Position%, From% see RAPIDQ.INC | 2 | WXG
WriteLine | SUB (S AS STRING) | Writes string with CR+LF | 1 | W
WriteNum | SUB (number, bytes%) | Writes a number to memory | 2 | WXG
WriteBinStr | SUB (string, bytes%) | Writes a binary string to file (slow) | 2 | W
WriteStr | SUB (string, bytes%) | Writes string to memory | 2 | WXG
WriteUDT | SUB (MyType) | Write data stored in a MyType structure | 1 | WXG

QMemoryStream Examples
  DIM Mem AS QMemoryStream

  S$ = "Hello world!"
  Mem.WriteStr(S$, LEN(S$))
  Mem.Position = 0
  S$ = Mem.ReadStr(LEN(S$))
  PRINT S$                            '' print it
  Mem.Close

'------------------------------------------------------

  TYPE MyType
      Name AS STRING*30
      Phone AS STRING*8
      Age AS INTEGER
  END TYPE

  DIM Person AS MyType
      Person.Name = "Joe"
      Person.Phone = "555-5555"

  DIM Mem AS QMemoryStream
      Mem.WriteUDT(Address)


Appendix A: QMENUITEM

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QMENUITEM

QMENUITEM Component

QMenuItem is used to describe the properties of an item in a menu. It is not meant to be a stand-alone component. You usually add a QMenuItem to a QMainMenu or QPopupMenu.

QMenuItem Properties
Field | Type | R/W | Default | Support
Caption | STRING | RW | WXG
Checked | INTEGER | RW | W
Enabled | INTEGER | RW | True | W
RadioItem | INTEGER | RW | False | W
ShortCut | STRING | RW | W
Visible | INTEGER | RW | True | W

QMenuItem Methods
Method | Type | Description | Params | Support
AddItems | SUBI | Add Subitems to MenuItem | QMENUITEMs, Infinite | WXG
Insert | SUB (I%, Item AS QMENUITEM) | Insert an item | 2 | W

QMenuItem Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User selects item | 0 | WXG

QMenuItem Examples
  DIM Form AS QForm
  DIM MainMenu AS QMainMenu
  DIM Item1 AS QMenuItem

  MainMenu.Parent = Form
  Item1.Caption = "&File"
  MainMenu.AddItems Item1

  Form.ShowModal


Appendix A: QMYSQL

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QMYSQL

QMYSQL Component

QMySQL is used to access your local or remote MySQL server. More information on MySQL can be obtained at http://www.mysql.com/

QMySQL Properties
Field | Type | R/W | Default | Support
Connected | INTEGER | R | WXG
DB | ARRAY of STRING | R | WXG
DBCount | INTEGER | R | WXG
FieldCount | INTEGER | R | WXG
Field.Decimals | INTEGER | R | WXG
Field.Flags | INTEGER | R | WXG
Field.Length | INTEGER | R | WXG
Field.MaxLength | INTEGER | R | WXG
Field.Name | STRING | R | WXG
Field.Table | STRING | R | WXG
Field.Type | INTEGER | R | WXG
Length | ARRAY of INTEGER | R | WXG
NumRows | INTEGER | R | WXG
Row | ARRAY of STRING | R | WXG
RowCount | INTEGER | R | WXG
Table | ARRAY of STRING | R | WXG
TableCount | INTEGER | R | WXG

QMySQL Methods
Method | Type | Description | Params | Support
Close | SUB | Disconnect from MySQL | 0 | WXG
Connect | FUNCTION (Host$, User$, Passwd$) AS INTEGER | Connect to MySQL | 3 | WXG
CreateDB | FUNCTION (DB$) AS INTEGER | Creates a new database | 1 | WXG
DropDB | FUNCTION (DB$) AS INTEGER | Drop database | 1 | WXG
EscapeString | FUNCTION (S$, Length%) AS STRING | Parses binary string S$ and returns a string that can be used in Blob fields | 2 | WXG
FetchField | FUNCTION AS INTEGER | Fetch next field | 0 | WXG
FetchLengths | FUNCTION AS INTEGER | Fetch lengths for current row | 0 | WXG
FetchRow | FUNCTION AS INTEGER | Fetch next row | 0 | WXG
FieldSeek | FUNCTION (Position%) | Jump to Field Position% | 1 | WXG
Query | FUNCTION (Query$) AS INTEGER | Query database | 1 | WXG
RealConnect | SUB (Host$, User$, Passwd$, DB$, Port%, UnixSock$, Flags%) | Connect to MySQL | 7 | WXG
Refresh | FUNCTION (RefreshFlags%) AS INTEGER | Refresh database | 1 | WXG
RowBlob | FUNCTION (Row%, Bytes&) AS STRING | Returns the binary blob as a string | 2 | WXG
RowSeek | FUNCTION (Row%) | Jump to a certain row | 1 | WXG
SelectDB | FUNCTION (DB$) AS INTEGER | Select database to use | 1 | WXG

QMySQL Events
Event Type Occurs when... Params

QMySQL Examples
' Sorry for lack of documentation, still a work in progress...
' This simply checks that you have a working MySQL server and lets you
' view some database fields.

$TYPECHECK ON
$INCLUDE "RAPIDQ.INC"

DECLARE SUB Button1Click (Sender AS QBUTTON)
DECLARE SUB DBListBoxClick (Sender AS QLISTBOX)
DECLARE SUB TableListBoxClick (Sender AS QLISTBOX)
DECLARE SUB SQLFormResize (Sender AS QFORM)

DIM Font AS QFONT
    Font.Name = "Courier"
DIM MySQL AS QMYSQL

    CREATE SQLForm AS QFORM
        Caption = "Connected"
        Width = 330
        Height = 300
        Center
        CREATE DBLabel AS QLABEL
            Caption = "Select a database:"
        END CREATE
        CREATE DBListBox AS QLISTBOX
            Top = 20
            Width = 150
            Height = 100
            OnClick = DBListBoxClick
        END CREATE
        CREATE TableListBox AS QLISTBOX
            Top = 20
            Left = 165
            Width = 150
            Height = 100
            OnClick = TableListBoxClick
        END CREATE
        CREATE FieldEdit AS QRICHEDIT
            Top = 130
            Width = SQLForm.ClientWidth
            Height = SQLForm.ClientHeight-130
            ReadOnly = TRUE
            WordWrap = FALSE
            PlainText = TRUE
            Font = Font
            ScrollBars = ssBoth
        END CREATE
        CREATE Grid AS QSTRINGGRID
            Top = 130
            Width = SQLForm.ClientWidth
            Height = SQLForm.ClientHeight-130
            AddOptions(goEditing)
        END CREATE
        OnResize = SQLFormResize
    END CREATE

CREATE Form AS QFORM
    Caption = "SQL Demo"
    Width = 230
    Height = 174
    Center
    CREATE Label1 AS QLABEL
        Caption = "Host:"
        Left = 44
        Top = 23
    END CREATE
    CREATE Label2 AS QLABEL
        Caption = "User name:"
        Left = 16
        Top = 50
        Width = 57
    END CREATE
    CREATE Label3 AS QLABEL
        Caption = "Password:"
        Left = 21
        Top = 79
        Width = 54
    END CREATE
    CREATE Edit1 AS QEDIT
        Text = ""
        Left = 83
        Top = 18
    END CREATE
    CREATE Edit2 AS QEDIT
        Text = ""
        Left = 83
        Top = 46
    END CREATE
    CREATE Edit3 AS QEDIT
        Text = ""
        Left = 83
        Top = 74
    END CREATE
    CREATE Button1 AS QBUTTON
        Caption = "&Ok"
        Left = 32
        Top = 112
        Kind = 1
        Default = 1
        NumBMPs = 2
        OnClick = Button1Click
    END CREATE
    CREATE Button2 AS QBUTTON
        Caption = "E&xit"
        Left = 118
        Top = 112
        Kind = 6
        NumBMPs = 2
    END CREATE
    ShowModal
END CREATE

SUB Button1Click
    DIM I AS INTEGER

    IF MySQL.Connect(Edit1.Text, Edit2.Text, Edit3.Text) = 0 THEN
       ShowMessage("Failed to connect to MySQL Server")
       EXIT SUB
    END IF

    FOR I = 0 TO MySQL.DBCount-1
        DBListBox.AddItems(MySQL.DB(I))
    NEXT

    SQLForm.ShowModal

    SUB DBListBoxClick (Sender AS QLISTBOX)

        IF Sender.ItemIndex < 0 THEN EXIT SUB
        IF MySQL.SelectDB(Sender.Item(Sender.ItemIndex)) = 0 THEN
            ShowMessage("Could not open "+Sender.Item(Sender.ItemIndex))
            EXIT SUB
        END IF

        TableListBox.Clear
        FOR I = 0 TO MySQL.TableCount-1
            TableListBox.AddItems(MySQL.Table(I))
        NEXT
    END SUB

    SUB TableListBoxClick (Sender AS QLISTBOX)
        DIM Str AS STRING, J AS INTEGER

        IF Sender.ItemIndex < 0 THEN EXIT SUB
        IF MySQL.Query("show columns from "+Sender.Item(Sender.ItemIndex)) = 0 THEN
            ShowMessage("Could not query "+Sender.Item(Sender.ItemIndex))
            EXIT SUB
        END IF

        FieldEdit.Clear
        Grid.ColCount = MySQL.FieldCount
        I = 0
        WHILE MySQL.FetchField
            Grid.Cell(I,0) = MySQL.Field.Name
            I++
        WEND

        Grid.RowCount = MySQL.RowCount+1
        IF MySQL.RowCount THEN
            J = 1
            WHILE MySQL.FetchRow
                MySQL.FieldSeek(0)
                FOR I=0 to MySQL.NumFields-1
                    Grid.Cell(I,J) = MySQL.Row(I)
                NEXT
                J++
            WEND
        END IF
    END SUB
END SUB

SUB SQLFormResize (Sender AS QFORM)
    Grid.Height = Sender.ClientHeight - Grid.Top
    Grid.Width = Sender.ClientWidth-1
    TableListBox.Width = Sender.ClientWidth-1 - TableListBox.Left
END SUB

IF MySQL.Connected THEN MySQL.Close
END


Appendix A: QNOTIFYICONDATA

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QNOTIFYICONDATA

QNOTIFYICONDATA Component

QNotifyIconData is not a visible component, it's a data type with the form
   TYPE QNotifyIconData
     cbSize AS INTEGER       ' Read only
     hWnd AS INTEGER
     uID AS INTEGER
     uFlags as INTEGER
     uCallBackMessage as INTEGER
     hIcon as INTEGER
     szTip as STRING
   END TYPE
Its use is primarily restricted to the Shell_NotifyIcon API call, but you may find other uses for it as well.


Appendix A: QOPENDIALOG

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QOPENDIALOG

QOPENDIALOG Component

QOpenDialog displays Window's file selection dialog

QOpenDialog Properties
Field | Type | R/W | Default | Support
Caption | STRING | RW | W
FileName | STRING | RW | WX
Filter | STRING | RW | W
FilterIndex | INTEGER | RW | 1 | W
InitialDir | STRING | RW | W

QOpenDialog Methods
Method | Type | Description | Params | Support
Execute | FUNCTION | Returns TRUE or FALSE | 0 | WX

QOpenDialog Examples
  '-- Simple demo
  DIM OpenDialog AS QOpenDialog

  IF OpenDialog.Execute THEN
    ShowMessage "You selected "+OpenDialog.FileName
  END IF

  '-- Using filters
  DIM OpenDialog AS QOpenDialog

  OpenDialog.Filter = "Picture files|*.BMP;*.ICO|All Files|*.*"
  OpenDialog.FilterIndex = 2    '' Use "All Files" as our default

  IF OpenDialog.Execute THEN
    ShowMessage "You selected "+OpenDialog.FileName
  END IF


Appendix A: QOUTLINE

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QOUTLINE

QOUTLINE Component

QOutLine implements the old style Win3.1 tree view.

QOutLine Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
BMPClosed | STRING | W
BMPLeaf | STRING | W
BMPMinus | STRING | W
BMPOpen | STRING | W
BMPPlus | STRING | W
BMPHandleClosed | RESOURCE | W
BMPHandleLeaf | RESOURCE | W
BMPHandleMinus | RESOURCE | W
BMPHandleOpen | RESOURCE | W
BMPHandlePlus | RESOURCE | W
BorderStyle | INTEGER | RW | bsSingle
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
Height | INTEGER | RW
Hint | STRING | RW
Item | ARRAY of STRING | RW
ItemHeight | INTEGER | RW | 13
ItemIndex | INTEGER | RW
ItemSeparator STRING RW \
Left | INTEGER | RW | 0
LineCount | INTEGER | RW
OutLineStyle | INTEGER | RW | osTreePictureText
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
Row | INTEGER | RW
ScrollBars | INTEGER | RW | ssBoth
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
Top | INTEGER | RW | 0
Visible | INTEGER | RW | True
Width | INTEGER | RW

QOutLine Methods
Method | Type | Description | Params
AddChild | SUB (Index%, String$) | Add child at Index% | 2
AddLines | SUBI | Add lines to Outline | STRING, Infinite
AddOptions | SUBI | Add Outline options | INTEGER, Infinite
Clear | SUB | Clear all items | 0
DelLines | SUBI | Delete lines from Outline | INTEGER, Infinite
DelOptions | SUBI | Delete Outline options | INTEGER, Infinite
Insert | SUB (Index%, String$) | Insert node at Index% | 2

QOutLine Events
Event | Type | Occurs when... | Params
OnClick | VOID | User clicked on item | 0
OnDblClick | VOID | User double clicked on item | 0

QOutLine Examples
CREATE Form AS QForm
  CREATE OutLine AS QOutLine
    AddLines "Parent 1", _
             " Child of Parent 1", _
             "  Child of Child of Parent 1", _
             "Parent 2", _
             "Parent 3", _
  END CREATE
  Center
  ShowModal
END CREATE


Appendix A: QOVALBTN

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QOVALBTN

QOVALBTN Component

QOvalbtn is similar to QCoolBtn, except the button looks round/oval.

QOvalbtn Properties >
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
BMP | STRING | W | W
BMPHandle | RESOURCE | W | W
Caption | STRING | RW | WX
Color | INTEGER | RW | WX
ColorHighLight | INTEGER | RW | W
ColorShadow | INTEGER | RW | W
Cursor | INTEGER | RW | crDefault | W
Down | INTEGER | RW | False | W
Enabled | INTEGER | RW | TrueWX
Flat | INTEGER | RW | False | WX
Font | QFONT | W | W
GroupIndex | INTEGER | RW | 0 | W
Height | INTEGER | RW | WX
Hint | STRING | RW | WX
Layout | INTEGER | RW | blBMPLeft | W
Left | INTEGER | RW | 0 | WX
NumBMPs | INTEGER | RW | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WX
ShowHint | INTEGER | RW | False | WX
Spacing | INTEGER | RW | W
TabOrder | INTEGER | RW | W
Top | INTEGER | RW | 0 | WX
Transparent | INTEGER | RW | False | W
TransParentColor | INTEGER | RW | W
Width | INTEGER | RW | WX
Visible | INTEGER | RW | True | WX

QOvalbtn Methods
Method | Type | Description | Params | Support
StartDrag | SUB | Allows Button to be dragged | 0 | W

QOvalbtn Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicked on the button | 0 | WX
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4 | WX
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3 | WX
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4 | WX

QOvalbtn Examples
CREATE Form AS QForm
  CREATE OvalBtn AS QOvalBtn
    Caption = "Oval Button"
    Color = &H00FF00
  END CREATE
  ShowModal
END CREATE


Appendix A: QPANEL

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QPANEL

QPANEL Component

QPanel implements a generic container for your components.

QButton Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Alignment | INTEGER | RW | taCenter | W
BevelInner | INTEGER | RW | bvNone | W
BevelOuter | INTEGER | RW | bvRaised | W
BevelWidth | INTEGER | RW | 1 | W
BorderStyle | INTEGER | RW | bsNone | W
Caption | STRING | RW | W
ClientHeight | INTEGER | RW | WX
ClientWidth | INTEGER | RW | WX
Color | INTEGER | RW | W
Cursor | INTEGER | RW | crDefault | W
Enabled | INTEGER | RW | True | WX
Font | QFONT | W | W
Height | INTEGER | RW | WX
Hint | STRING | RW | W
Left | INTEGER | RW | 0 | WX
Parent | QFORM/QPANEL/QTABCONTROL | W | WX
ShowHint | INTEGER | RW | False | W
TabOrder | INTEGER | RW | W
Top | INTEGER | RW | 0 | WX
Width | INTEGER | RW | WX
Visible | INTEGER | RW | True | WX

QPanel Methods
Method | Type | Description | Params | Support
Repaint | SUB | Refreshes panel and all contents | 0 | W

QPanel Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicked on open area of panel | 0 | WX
OnDblClick | VOID | User double clicked panel | 0 | W
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4 | W
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves over panel | 3 | W
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4 | W

QPanel Examples
  DIM Form AS QForm
  DIM Button AS QButton
  DIM Panel AS QPanel

  Panel.Parent = Form
  Panel.Width = 100
  Button.Parent = Panel

  Form.ShowModal


Appendix A: QPOPUPMENU

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QPOPUPMENU

QPOPUPMENU Component

QPopupMenu provides a popup menu selection control

QPopupMenu Properties
Field | Type | R/W | Default
Alignment | INTEGER | RW

QPopupMenu Methods
Method | Type | Description | Params
AddItems | SUBI | Add Item to Menu | QMENUITEMs, Infinite
Insert | SUB (I%, Item AS QMENUITEM) | Insert an item | 2
Popup | SUB (X%, Y%) | Popup menu at (X,Y) | 2

QPopupMenu Events
Event Type Occurs when... Params

QPopupMenu Examples
  DIM PopupMenu AS QPopupMenu
  DIM Item1 AS QMenuItem

  Item1.Caption = "Item 1"
  PopupMenu.AddItems Item1

  PopupMenu.Popup(100,100)


Appendix A: QRADIOBUTTON

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QRADIOBUTTON

QRADIOBUTTON Component

QRadioButton is a simple radio item. If you want to group radiobuttons, use a container like QPanel.

QRadioButton Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Caption | STRING | RW | WXG
Checked | INTEGER | RW | False | WXG
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Left | INTEGER | RW | 0 | WXG
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | WXG
TabOrder | INTEGER | RW | W
Top | INTEGER | RW | 0 | WXG
Visible | INTEGER | RW | True | WXG
Width | INTEGER | RW | WXG

QRadioButton Methods
Method Type Description Params

QRadioButton Events
Event | Type | Occurs when... | Params | Support
OnClick | VOID | User clicked on radio button | 0 | WXG

QRadioButton Examples
  DIM Form AS QForm
  DIM Radio1 as QRadioButton
  DIM Radio2 as QRadioButton
  DIM Radio3 as QRadioButton

  Radio1.Parent = Form
  Radio1.Top = 10
  Radio1.Caption = "Item 1"
  Radio2.Parent = Form
  Radio2.Top = 35
  Radio2.Caption = "Item 2"
  Radio3.Parent = Form
  Radio3.Top = 60
  Radio3.Caption = "Item 3"

  Form.ShowModal


Appendix A: QRECT

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QRECT

QRECT Component

QRect is not a visible component, it's a data type with the form
   TYPE QRect
     Top AS INTEGER
     Left AS STRING
     Right AS INTEGER
     Bottom as INTEGER
   END TYPE


Appendix A: QREGISTRY

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QREGISTRY

QREGISTRY Component

QRegistry encapsulates functions that operate on the Window's system registry.

QRegistry Properties
Field | Type | R/W | Default
CurrentKey | INTEGER | R
CurrentPath | STRING | R
GetDataSize | INTEGER | R
GetDataType | INTEGER | R
HasSubKeys | INTEGER | R
KeyItemCount | INTEGER | R
ValueItemCount | INTEGER | R
RootKey | INTEGER | RW | HKEY_CURRENT_USER

QRegistry Methods
Method | Type | Description | Params
CloseKey | SUB | Closes opened key | 0
CreateKey | FUNCTION (Key$) AS INTEGER | Creates a new key in CurrentPath. | 1
DeleteKey | FUNCTION (Key$) AS INTEGER | Deletes key. | 1
DeleteValue | FUNCTION (ValName$) AS INTEGER | Deletes a value data. | 1
KeyExists | FUNCTION (Key$) AS INTEGER | Returns 0 or 1 if key exists. | 1
KeyItem | FUNCTION (Index%) AS STRING | Retrieve the names of the subkeys | 1
MoveKey | FUNCTION (Old$, New$, Delete%) | Moves existing key, subkeys, and data values. | 3
OpenKey | FUNCTION (Key$, CanCreate%) | CanCreate specifies whether to create the specified key if it does not exist. | 2
ReadBinary | FUNCTION (Key$, Index%) AS BYTE | Return binary value of specified key | 2
ReadFloat | FUNCTION (Key$) AS DOUBLE | Return double value of specified key | 1
ReadInteger | FUNCTION (Key$) AS INTEGER | Return integer value of specified key | 1
ReadString | FUNCTION (Key$) AS STRING | Return string value of specified key | 1
RegistryConnect | FUNCTION (CompName$) AS INTEGER | Establishes connection to another computer's registry. | 1
RenameValue | FUNCTION (Old$, New$) AS INTEGER | Renames existing data value. | 2
ValueExists | FUNCTION (Value$) AS INTEGER | Returns 0 or 1 if data value Value$ exists. | 1
ValueItem | FUNCTION (Index%) AS STRING | Retrieve the names of the data values | 1
WriteBinary | SUB (Key$, BYTE(), Size%) | Write Array of BYTEs in the specified key | 3
WriteFloat | SUB (Key$, Value#) | Write double value in the specified key | 2
WriteInteger | SUB (Key$, Value&) | Write integer value in the specified key | 2
WriteString | SUB (Key$, Value$) | Write string in the specified key | 2

QRegistry Events
Event Type Occurs when... Params

QRegistry Examples
'  Detect if your computer is connected to the internet

Const HKEY_LOCAL_MACHINE = &H80000002

DIM Registry AS QRegistry

Registry.RootKey = HKEY_LOCAL_MACHINE
Registry.OpenKey("System\CurrentControlSet\Services\RemoteAccess", 0)

IF Registry.ReadBinary("Remote Connection", 0) = 1 THEN
  ShowMessage("You're connected!")
ELSE
  ShowMessage("You're not connected!")
END IF


Appendix A: QRICHEDIT

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QRICHEDIT

QRICHEDIT Component

QRichedit implements a fully featured multi-line text edit control.

QRichedit Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Alignment | INTEGER | RW | taLeftJustify | W
BorderStyle | INTEGER | RW | bsSingle | W
Color | INTEGER | RW | W
Enabled | INTEGER | RW | True | WX
Font | QFONT | W | WX
Height | INTEGER | RW | WX
HideScrollBars | INTEGER | RW | True | W
HideSelection | INTEGER | RW | True | W
Hint | STRING | RW | W
Left | INTEGER | RW | 0 | WX
Line | ARR_STRING | RW | WX
LineCount | INTEGER | RW | WX
Modified | INTEGER | R | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WX
PopupMenu | QPOPUPMENU | W | W
Plaintext | INTEGER | RW | False | W
Readonly | INTEGER | RW | False | WX
ScrollBars | INTEGER | RW | ssNone | WX
SelAttributes | QFONT | W | W
SelLength | INTEGER | RW | WX
SelStart | INTEGER | RW | WX
SelText | STRING | RW | WX
ShowHint | INTEGER | RW | False | W
TabOrder | INTEGER | RW | W
Text | STRING | RW | WX
Top | INTEGER | RW | 0 | WX
WantTabs | INTEGER | RW | False | W
Width | INTEGER | RW | WX
WhereX | INTEGER | R | WX
WhereY | INTEGER | R | WX
Wordwrap | INTEGER | RW | True | W
Visible | INTEGER | RW | True | WX

QRichedit Methods
Method | Type | Description | Params | Support
AddString | SUB (S$) | Add a string | 1 | WX
AddStrings | SUBI | Add strings (up to 255) | STRING | WX
Clear | SUB | Clear entire text | 0 | WX
CopyToClipboard | SUB | Copy selected text to clipboard | 0 | W
CutToClipboard | SUB | Cut selected text to clipboard | 0 | W
LoadFromFile | SUB (FileName$) | Load text from a file | 1 | WX
LoadFromStream | SUB (Stream) | Load text from a stream | 1 | WX
PasteFromClipboard | SUB | Paste text from clipboard | 0 | W
SaveToFile | SUB (FileName$) | Save text to a file | 1 | WX
SaveToStream | SUB (Stream) | Save text to a stream | 1 | W
SelectAll | SUB | Selects all text from Richedit | 0 | WX

QRichedit Events
Event | Type | Occurs when... | Params | Support
OnChange | VOID | Text changes | 0 | W
OnKeyDown | SUB (Key AS WORD, Shift AS INTEGER) | Key held down | 2 | W
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1 | W
OnKeyUp | SUB (Key AS WORD, Shift AS INTEGER) | Key released | 2 | W
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4 | WX
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 2 | WX
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4 | WX

QRichedit Examples
  $INCLUDE "RAPIDQ.INC"

  DIM Form AS QForm
  DIM RichEdit AS QRichEdit

  RichEdit.Parent = Form
  RichEdit.Scrollbars = ssBoth
  RichEdit.AddString "Hello world!"

  Form.ShowModal


Appendix A: QSAVEDIALOG

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSAVEDIALOG

QSAVEDIALOG Component

QSaveDialog displays a Save As dialog box for saving files.

QSaveDialog Properties
Field | Type | R/W | Default
Caption | STRING | RW
FileName | STRING | RW
Filter | STRING | RW
FilterIndex | INTEGER | RW | 1
InitialDir | STRING | RW

QSaveDialog Methods
Method | Type | Description | Params
Execute | FUNCTION | Returns TRUE or FALSE | 0

QSaveDialog Examples
  '-- Simple demo
  DIM SaveDialog AS QOpenDialog

  IF SaveDialog.Execute THEN
    ShowMessage "You want to save as "+SaveDialog.FileName
  END IF


Appendix A: QSCROLLBAR

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSCROLLBAR

QSCROLLBAR Component

QScrollBar is a Windows scroll bar, used to scroll contents of a window, form, or control. It can also act as a simple trackbar.

QScrollBar Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Cursor | INTEGER | RW | crDefault | W
Enabled | INTEGER | RW | True | WX
Height | INTEGER | RW | WX
Hint | STRING | RW | WX
Kind | INTEGER | RW | sbHorizontal | WX
LargeChange | INTEGER | RW | 1 | WX
Left | INTEGER | RW | 0 | WX
Max | INTEGER | RW | 100 | WX
Min | INTEGER | RW | 0 | WX
Parent | QFORM/QPANEL/QTABCONTROL | W | WX
PopupMenu | QPOPUPMENU | W | W
Position | INTEGER | RW | 0 | WX
ShowHint | INTEGER | RW | False | WX
SmallChange | INTEGER | RW | 1 | WX
TabOrder | INTEGER | RW | W
Top | INTEGER | RW | 0 | WX
Width | INTEGER | RW | WX
Visible | INTEGER | RW | True | WX

QScrollBar Events
Event | Type | Occurs when... | Params | Support
OnChange | VOID | Scroll position changes | 0 | WX
OnKeyDown | SUB (Key AS Word, Shift AS INTEGER) | Key held down | 2 | W
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1 | W
OnKeyUp | SUB (Key AS Word, Shift AS INTEGER) | User releases a key | 2 | W
OnScroll | SUB (ScrollCode AS BYTE, ScrollPos AS LONG) | Scrolling | 2 | W

QScrollBar Examples
' Color Palette for Rapid-Q by William Yu

DECLARE SUB ColorChange
DECLARE SUB Paint

CONST False = 0
CONST True = NOT False

'' Here's something that will convert your standard RGB to Rapid-Q's BGR.
FUNCTION ConvertRGB(R AS INTEGER, G AS INTEGER, B AS INTEGER) AS INTEGER
  ConvertRGB = (B SHL 16) OR (G SHL 8) OR R
END FUNCTION

CREATE Form AS QForm
  CREATE LabelRed AS QLabel
    Left = 10
    Top = 22
    Caption = "Red:"
  END CREATE
  CREATE LabelGreen AS QLabel
    Left = 5
    Top = 52
    Caption = "Green:"
  END CREATE
  CREATE LabelBlue AS QLabel
    Left = 10
    Top = 82
    Caption = "Blue:"
  END CREATE
  CREATE LabelNum1 AS QLabel
    Left = 270
    Top = 22
    Caption = "0"
  END CREATE
  CREATE LabelNum2 AS QLabel
    Left = 270
    Top = 52
    Caption = "0"
  END CREATE
  CREATE LabelNum3 AS QLabel
    Left = 270
    Top = 82
    Caption = "0"
  END CREATE
  CREATE ScrollRed AS QScrollBar
    Left = 50
    Top = 20
    Width = 200
    Height = 20
    Min = 0: Max = 255
    ShowHint =  True
    Hint = "Red Attribute"
    OnChange = ColorChange
  END CREATE
  CREATE ScrollGreen AS QScrollBar
    Left = 50
    Top = 50
    Width = 200
    Height = 20
    Min = 0: Max = 255
    ShowHint =  True
    Hint = "Green Attribute"
    OnChange = ColorChange
  END CREATE
  CREATE ScrollBlue AS QScrollBar
    Left = 50
    Top = 80
    Width = 200
    Height = 20
    Min = 0: Max = 255
    ShowHint =  True
    Hint = "Blue Attribute"
    OnChange = ColorChange
  END CREATE
  CREATE PaintBox AS QCanvas
    Left = 50
    Top = 110
    Height = 90
    Width = 200
    OnPaint = Paint
  END CREATE
  Caption = "Color Palette"
  Center
  ShowModal
END CREATE

SUB ColorChange
  LabelNum1.Caption = STR$(ScrollRed.Position)
  LabelNum2.Caption = STR$(ScrollGreen.Position)
  LabelNum3.Caption = STR$(ScrollBlue.Position)
  Paint
END SUB

SUB Paint
  PaintBox.Paint(0,0,ConvertRGB(ScrollRed.Position, ScrollGreen.Position, ScrollBlue.Position),&HFFFFFF)
END SUB


Appendix A: QSCROLLBOX

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSCROLLBOX

QSCROLLBOX Component

QScrollBox is a scrolling window control.

QScrollBox Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
AutoScroll | INTEGER | RW | True
BorderStyle | INTEGER | RW | bsSingle
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
Handle | INTEGER | R
Height | INTEGER | RW
Hint | STRING | RW
HorzIncrement | INTEGER | RW | 8
HorzMargin | INTEGER | RW | 0
HorzPosition | INTEGER | RW | 0
HorzRange | INTEGER | RW | 0
HorzTracking | INTEGER | RW | False
HorzVisible | INTEGER | RW | True
Left | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
Top | INTEGER | RW | 0
Width | INTEGER | RW
VertIncrement | INTEGER | RW | 8
VertMargin | INTEGER | RW | 0
VertPosition | INTEGER | RW | 0
VertRange | INTEGER | RW | 0
VertTracking | INTEGER | RW | False
VertVisible | INTEGER | RW | True
Visible | INTEGER | RW | True

QTrackBar Methods
Method | Type | Description | Params
Repaint | SUB | Repaint control | 0

QTrackBar Events
Event | Type | Occurs when... | Params
OnClick | VOID | User clicked on scrollbox | 0
OnDblClick | VOID | User double clicked on scrollbox | 0
OnMouseDown | SUB (Button%, X%, Y%, Shift%) | Mouse button held down | 4
OnMouseMove | SUB (X%, Y%, Shift%) | Mouse moves | 3
OnMouseUp | SUB (Button%, X%, Y%, Shift%) | Mouse button is released | 4
OnResize | VOID | Scrollbox is resized | 0

QScrollBox Examples
CREATE Form AS QForm
  Center
  CREATE ScrollBox AS QScrollBox
    Left = 50
    CREATE Button AS QButton   '-- Create button inside scrollbox
    END CREATE
  END CREATE
  ShowModal
END CREATE


Appendix A: QSOCKET

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSOCKET

QSOCKET Component

QSocket provides an easy to use interface to communicate between server/client with sockets.

QSocket Properties
Field | Type | R/W | Default | Support
Family | INTEGER | RW | AF_INET | W
Protocol | INTEGER | RW | IPPROTO_IP | W
Transferred | INTEGER | R | WXG
Type | INTEGER | RW | SOCK_STREAM | W

QSocket Methods
Method | Type | Description | Params | Support
Accept | FUNCTION ClientSock%(Socket%) | Accepts Client Connection | 1 | WXG
Close | SUB (Socket%) | Closes Socket% file descriptor | 1 | WXG
Connect | FUNCTION Sock%(ServerName$, PortNum%) | Connect to server on PortNum% | 2 | WXG
ConnectionReady | FUNCTION Bool%(Sock%) | True/False if connection pending | 1 | WXG
GetHostIP | FUNCTION AS STRING | Returns host IP Address | 0 | WXG
GetHostName | FUNCTION AS STRING | Returns host name | 0 | WXG
GetPeerName | FUNCTION GetPeerName$(Socket%) | Returns peer name | 1 | WXG
IsClientReady | FUNCTION Bool%(Sock%, ClientSock%) | True/False if client is sending data | 2 | WXG
IsServerReady | FUNCTION Bool%(Sock%) | True/False if server is sending data | 1 | WXG
Open | FUNCTION Sock%(PortNum%) | Open TCP server on PortNum% | 1 | WXG
Peek | FUNCTION Peek$(Socket%, NumBytes%) | Peek information coming from socket, but do not clear. Win32 | 2 | W
Read | FUNCTION Message$(Socket%, NumBytes%) | Read NumBytes% | 2 | WXG
ReadLine | FUNCTION Message$(Socket%) | Read complete line | 1 | WXG
Write | SUB (Socket%, Message$, NumBytes%) | Sends NumBytes% from Message$ | 3 | WXG
WriteLine | FUNCTION Bytes%(Socket%, Message$) | Send Message$ | 2 | WXG

QSocket Examples
See the chatserver.bas and chatclient.bas (or chatserv.bas and chatcli.bas for Windows)
included in the Rapid-Q distribution.
Also take a look at http.bas included in the Rapid-Q for Windows distribution.


Appendix A: QSPLITTER

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSPLITTER

QSPLITTER Component

QSplitter sits between a control aligned to one of the edges of the form and the controls that fill up the rest of the client area. It is used to resize the controls at runtime.

QSplitter Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alLeft
Beveled | INTEGER | RW | True
ClientHeight | INTEGER | RW
ClientWidth | INTEGER | RW
Color | INTEGER | RW
Cursor | INTEGER | RW | crHSplit
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW
MinSize | INTEGER | RW | 30
Parent | QFORM/QPANEL/QTABCONTROL | W
ShowHint | INTEGER | RW | False
Top | INTEGER | RW
Width | INTEGER | RW

QSplitter Methods
Method Type Description Params

QSplitter Events
Event | Type | Occurs when... | Params
OnMoved | VOID | Splitter Moved | 0

QSplitter Examples
$INCLUDE "RAPIDQ.INC"

CREATE Form AS QFORM
    Height = 400
    Caption = "QSplitter example"
    Center
    Visible = 1                  '-- Required
    Visible = 0                  '-- trick
    CREATE Panel AS QPANEL
        Align = alTop            '-- Fill top portion of form
        Height = 100
        Caption = "PANEL"
    END CREATE
    CREATE Splitter AS QSPLITTER '-- Note position
        Align = alTop            '-- Fill middle
        Cursor = crVSplit
        Height = 10
    END CREATE
    CREATE RichEdit AS QRICHEDIT
        Align = alClient         '-- Fill rest of form
        AddStrings "RICHEDIT"
    END CREATE
    ShowModal
END CREATE


Appendix A: QSTATUSBAR

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSTATUSBAR

QSTATUSBAR Component

QStatusBar implements a Windows status bar.

QStatusBar Internal Types
   TYPE PanelType           '' ie. StatusBar.Panel(0).Caption
     Alignment AS INTEGER
     Caption AS STRING
     Width AS INTEGER
   END TYPE
QStatusBar Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alBottom
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW | 0
Panel | ARRAY of PanelType | RW
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ShowHint | INTEGER | RW | False
SimplePanel | INTEGER | RW | False
SimpleText | STRING | RW
SizeGrip | INTEGER | RW | True
TabOrder | INTEGER | RW
Top | INTEGER | RW | 0
Width | INTEGER | RW
Visible | INTEGER | RW | True

QStatusBar Methods
Method | Type | Description | Params
AddPanels | SUBI | Add panels to status bar | STRING, Infinite
Clear | SUB | Clear panels | 0

QStatusBar Events
Event | Type | Occurs when... | Params
OnResize | VOID | Status bar is being resized | 0

QStatusBar Examples
CREATE Form AS QForm
  Center
  CREATE StatusBar AS QStatusBar
    AddPanels "Panel 1", "Panel 2", "Panel 3"
    Panel(1).Width = 100  ' change width of Panel 2
  END CREATE
  ShowModal
END CREATE


Appendix A: QSTRINGGRID

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSTRINGGRID

QSTRINGGRID Component

QStringGrid allows you to present textual data in a tabular format.

QStringGrid Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
BorderStyle | INTEGER | RW | bsSingle
Cell | 2D ARRAY of STRING | RW
Col | INTEGER | RW
ColCount | INTEGER | RW | 5
Color | INTEGER | RW
ColWidths | ARRAY of INTEGER | RW
Cursor | INTEGER | RW | crDefault
DefaultColWidth | INTEGER | RW | 64
DefaultRowHeight | INTEGER | RW | 24
EditorMode | INTEGER | RW
Enabled | INTEGER | RW | True
FixedColor | INTEGER | RW
FixedCols | INTEGER | RW | 1
FixedRows | INTEGER | RW | 1
Font | QFONT | W
GridHeight | INTEGER | RW
GridLineWidth | INTEGER | RW | 1
GridWidth | INTEGER | RW
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW | 0
LeftCol | INTEGER | RW
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
Row | INTEGER | RW
RowCount | INTEGER | RW | 5
RowHeights | ARRAY of INTEGER | RW
ScrollBars | INTEGER | RW | ssBoth
Separator | STRING | RW
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
TabStops | ARRAY of INTEGER | RW
Top | INTEGER | RW | 0
TopRow | INTEGER | RW
Visible | INTEGER | RW | True
VisibleColCount | INTEGER | R
VisibleRowCount | INTEGER | R
Width | INTEGER | RW

QStringGrid Methods
Method | Type | Description | Params
AddOptions | SUBI | Add options to string grid | INTEGER, Infinite
DeleteCol | SUB (Column%) | Deletes/Remove a column | 1
DeleteRow | SUB (Row%) | Deletes/Remove a row | 1
DelOptions | SUBI | Delete options from string grid | INTEGER, Infinite
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3
Draw | SUB (x%, y%, BMP) | Draw Bitmap at (X,Y) | 3
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draws & Fills a rectangle | 5
InsertCol | SUB (Column%) | Inserts a blank column | 1
InsertRow | SUB (Row%) | Inserts a blank row | 1
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5
LoadFromFile | SUB (File$, RowOffset%, ColOffset%, MaxRows%) | Loads table from file w/Separator | 4
LoadFromStream | SUB (S AS QFileStream/QMemoryStream, RowOffset%, ColOffset%, MaxRows%) | Loads table from stream w/Separator | 4
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4
Pset | SUB (x%, y%, c%) | Pixel plot | 3
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5
Repaint | SUB | Force repainting of stringgrid | 0
SaveToFile | SUB (File$, RowOffset%, ColOffset%, MaxRows%) | Saves table to file w/Separator | 4
SaveToStream | SUB (S AS QFileStream/QMemoryStream, RowOffset%, ColOffset%, MaxRows%) | Saves table to stream w/Separator | 4
SwapCols | SUB (Col1%, Col2%) | Swap two columns | 2
SwapRows | SUB (Row1%, Row2%) | Swap two rows | 2
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text to cell | 5

QStringGrid Events
Event | Type | Occurs when... | Params
OnDrawCell | SUB (Col%, Row%, State%, R AS QRect) | Cells need to be redrawn | 4
OnSelectCell | SUB (Col%, Row%, CanSelect%) | User has selected a cell | 3
OnSetEditText | SUB (Col%, Row%, Value$) | User has changed contents of cell | 3

QStringGrid Examples
CREATE Form AS QForm
  CREATE Grid AS QStringGrid
    Cell(1,1) = "hello"
  END CREATE
  Center
  ShowModal
END CREATE


Appendix A: QSTRINGLIST

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QSTRINGLIST

QSTRINGLIST Component

QStringList is a component to store and manipulate a list of strings.

QStringList Properties
Field | Type | R/W | Default
Duplicates | INTEGER | RW | dupIgnore
Item | ARRAY of STRING | RW
ItemCount | INTEGER | R
Sorted | INTEGER | RW | False
Text | STRING | RW

QStringList Methods
Method | Type | Description | Params
AddItems | SUBI | Add strings to stringlist | STRINGs, Infinite
AddList | SUB (List AS QStringList) | Append another stringlist | 1
Build | FUNCTION Build(Start%, End%, Delim$) AS STRING | Returns a deliminated string | 3
Clear | SUB | Clears entire stringlist | 0
DelItems | SUBI | Delete strings by their index | Index #s, Infinite
Exchange | SUB (Index1%, Index2%) | Swap strings at Index1% with Index2% | 2
IndexOf | FUNCTION IndexOf%(String$) | Return Index number of string | 1
InsertItem | SUB (Index%, String$) | Insert string at Index% | 2
LoadFromFile | SUB (File$) | Load text file in stringlist | 1
LoadFromStream | SUB (File AS QStream) | Load file/memorystream in stringlist | 1
Parse | FUNCTION Parse(Source$, Delim$) AS LONG | Separates strings by the Delim$ and stores each item in the list | 2
SaveToFile | SUB (File$) | Saves stringlist to file | 1
SaveToStream | SUB (File AS QStream) | Load file/memorystream in stringlist | 1
Sort | SUB | Sort the stringlist | 0

QStringList Events
Event Type Occurs when... Params

QStringList Examples
  DIM StringList1 AS QStringList
  DIM StringList2 AS QStringList

  StringList1.AddItems "Oranges","Apples"
  StringList2.AddItems "Byte","Word","Integer"
  StringList1.AddList(StringList2)
  StringList1.Sort

  ?StringList1.Text
  ?StringList1.Item(3)
  ?StringList1.IndexOf("Word")
  ?StringList1.IndexOf("hi")

  '-------------------------------------------------------

  DIM StringList AS QSTRINGLIST

  StringList.Parse("James:Brown:555-3454:House",":")

  PRINT StringList.Build(0,StringList.Count-1,",")


Appendix A: QTABCONTROL

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QTABCONTROL

QTABCONTROL Component

QTabControl is a tab set that has the appearance of notebook dividers, except it is not made up of several pages.

QTabControl Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
ButtonStyle | INTEGER | RW | False
ClientHeight | INTEGER | RW
ClientWidth | INTEGER | RW
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
FlatButtons | INTEGER | RW | False
FlatSeperators | INTEGER | RW | False
FocusButtons | INTEGER | RW | False
Font | QFONT | W
Height | INTEGER | RW
Hint | STRING | RW
HotTrack | INTEGER | RW | False
Left | INTEGER | RW | 0
MultiLine | INTEGER | RW | False
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ScrollOpposite | INTEGER | RW | False
ShowHint | INTEGER | RW | False
Tab | ARRAY of STRING | RW
TabHeight | INTEGER | RW
TabInactiveColor | INTEGER | RW
TabInactiveFont | QFONT | W
TabIndex | INTEGER | RW
TabOrder | INTEGER | RW
TabPosition | INTEGER | RW
TabWidth | INTEGER | RW
Top | INTEGER | RW | 0
Width | INTEGER | RW
VerticalTabs | INTEGER | RW | False
Visible | INTEGER | RW | True

QTabControl Methods
Method | Type | Description | Params
AddTabs | SUBI | Add tabs to control | STRING, Infinite
DelTabs | SUBI | Delete tabs from control | INTEGER, Infinite
InsertTab | SUB (Index%, String$) | Inserts Tab at Index% | 2

QTabControl Events
Event | Type | Occurs when... | Params
OnChange | VOID | Tabs change | 0

QTabControl Examples
'' Tab Control Example for Rapid-Q by William Yu
'' When you hide a container (like QFORM, QTABCONTROL, and QPANEL), all the
'' components within it are also hidden.

$INCLUDE "RAPIDQ.INC"

DECLARE SUB TabChange

CREATE MainForm AS QForm
  Center
  Height = 300
  Width = 350
  Caption = "Tab Control demo"
  CREATE Tab AS QTabControl
    AddTabs "Tab 1","Tab 2","Tab 3","Tab 4"
    Width = MainForm.ClientWidth
    Height = MainForm.ClientHeight
    OnChange = TabChange
    HotTrack = True
    CREATE Panel0 AS QPanel
      Top = 40
      Left = 5
      Width = Tab.ClientWidth - 10
      Height = Tab.ClientHeight - 50
      Caption = "Panel 1"
      BevelInner = bvLowered
      CREATE Button1 AS QButton
        Caption = "Hello world!"
      END CREATE
    END CREATE
    CREATE Panel1 AS QPanel
      Top = 40
      Left = 5
      Width = Tab.ClientWidth - 10
      Height = Tab.ClientHeight - 50
      Caption = "Panel 2"
      BevelInner = bvLowered
      Visible = False
    END CREATE
    CREATE Panel2 AS QPanel
      Top = 40
      Left = 5
      Width = Tab.ClientWidth - 10
      Height = Tab.ClientHeight - 50
      Caption = "Panel 3"
      BevelInner = bvLowered
      Visible = False
    END CREATE
    CREATE Panel3 AS QPanel
      Top = 40
      Left = 5
      Width = Tab.ClientWidth - 10
      Height = Tab.ClientHeight - 50
      Caption = "Panel 4"
      BevelInner = bvLowered
      Visible = False
    END CREATE
  END CREATE
END CREATE

SUB TabChange
  SELECT CASE Tab.TabIndex
    CASE 0
      Panel0.Visible = True
      Panel1.Visible = False
      Panel2.Visible = False
      Panel3.Visible = False
    CASE 1
      Panel1.Visible = True
      Panel0.Visible = False
      Panel2.Visible = False
      Panel3.Visible = False
    CASE 2
      Panel2.Visible = True
      Panel1.Visible = False
      Panel0.Visible = False
      Panel3.Visible = False
    CASE 3
      Panel3.Visible = True
      Panel1.Visible = False
      Panel2.Visible = False
      Panel0.Visible = False
  END SELECT
END SUB

MainForm.ShowModal


Appendix A: QTIMER

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QTIMER

QTIMER Component

QTimer implements the Windows API timer functions.

QTimer Properties
Field | Type | R/W | Default | Support
Enabled | INTEGER | RW | True | WXG
Interval | INTEGER | RW | WXG

QTimer Events
Event | Type | Occurs when... | Params | Support
OnTimer | VOID | Timer interval elaspes | 0 | WXG

QTimer Examples
' Timer & OnKeyPress example for Rapid-Q by William Yu
'       If no form is visible, Timer will not function.
'       Not for PURE CONSOLE apps, but you're allowed to MIX.

DIM Timer AS QTimer, Timer2 AS QTimer
DIM Form AS QFORM
DIM Label1 AS QLABEL, Label2 AS QLABEL
DIM Label3 AS QLABEL

SUB TimerOver
  Timer.Interval = 100
  I = I + 1
  Label1.Caption = STR$(I)
END SUB

SUB Timer2Over
  Timer2.Interval = 1000
  J = J + 1
  Label2.Caption = STR$(J)
END SUB

SUB KeyPressed (Key AS BYTE)      '' Event returns one parameter
  IF UCASE$(CHR$(Key)) = "Q" THEN
    FORM.CLOSE
  END IF
END SUB

I = 0        ' Undeclared variables are automatically global!
J = 0

FORM.CAPTION = "Timer Example"
FORM.WIDTH = 150
FORM.HEIGHT = 120
FORM.CENTER

Label1.Parent = Form
Label1.Caption = STR$(I)
Label1.Left = FORM.WIDTH/2

Label2.Parent = Form
Label2.Caption = STR$(J)
Label2.Left = FORM.WIDTH/2
Label2.Top = 40

Label3.Parent = Form
Label3.Caption = "Press 'Q' to quit'
Label3.Top = 75

Timer.Interval = 100
Timer.Enabled = 1          ' True
Timer.OnTimer = TimerOver

Timer2.Interval = 1000
Timer2.Enabled = 1          ' True
Timer2.OnTimer = Timer2Over

FORM.OnKeyPress = KeyPressed
FORM.SHOWMODAL


Appendix A: QTRACKBAR

Rapid-Q Documentation by William Yu (c)1999 Appendix A: QTRACKBAR

QTRACKBAR Component

QTrackBar is a track bar control used to represent a position along a continuum using a slider and, optionally, tick marks.

QTrackBar Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Frequency | INTEGER | RW
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW | 0
LineSize | INTEGER | RW | 1
Max | INTEGER | RW | 10
Min | INTEGER | RW | 0
Orientation | INTEGER | RW | tbHorizontal
PageSize | INTEGER | RW | 2
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
Position | INTEGER | RW
SelEnd | INTEGER | RW
SelStart | INTEGER | RW
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
TickMarks | INTEGER | RW | tmBottomRight
TickStyle | INTEGER | RW | tsAuto
Top | INTEGER | RW | 0
Width | INTEGER | RW
Visible | INTEGER | RW | True

QTrackBar Methods
Method | Type | Description | Params
SetTick | SUB (Pos%) | Set a tick mark at Pos% | 1

QTrackBar Events
Event | Type | Occurs when... | Params
OnChange | VOID | Track bar changes | 0

QTrackBar Examples
CREATE Form AS QForm
  Center
  CREATE TrackBar AS QTrackBar
    ' Initialize track bar
  END CREATE
  ShowModal
END CREATE


Appendix B: QDXIMAGELIST

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QDXIMAGELIST

QDXIMAGELIST Component

QDXImageList maintains a list of images for use in your programs. Unlike QImageList, you must create the imagelist using an Image Library.

QDXImageList Properties
Field | Type | R/W | Default
Parent | QDXSCREEN | W

QDXImageList Methods
Method | Type | Description | Params
Draw | SUB (Item%, X%, Y%, Mask%) | Draw image on Screen | 4
LoadFromFile | SUB (FileName$) | Load image list | 1

QDXImageList Events
Event Type Occurs when... Params

QDXImageList Examples
See DIRECTX.BAS example


Appendix B: QDXSCREEN

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QDXSCREEN

QDXSCREEN Component

QDXScreen allows you to create a DirectX screen for all your DXComponents. All operations are done on the off-screen buffer, so nothing is displayed until you flip to it. To use full screen mode, set FullScreen to true, and make sure your form border style is bsNone.

QDXScreen Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
AllowStretch | INTEGER | RW | True
AutoSize | INTEGER | RW | True
BitCount | INTEGER | RW | 8
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
FullScreen | INTEGER | RW | False
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW
Parent | QFORM/QPANEL/QTABCONTROL | W
Pixel | 2D ARRAY of INTEGER | RW
ShowHint | INTEGER | RW | False
Top | INTEGER | RW
Use3D | INTEGER | RW | False
UseHardware | INTEGER | RW | True
Visible | INTEGER | RW | True
Width | INTEGER | RW

QDXScreen Methods
Method | Type | Description | Params
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle | 6
CopyRect | SUB (D, Image, S) | D and S are QRECTs, Image can be a QImage, QCanvas, or QBitmap | 3
Draw | SUB (x%, y%, BMP) | Draw Bitmap at (X,Y) | 3
Fill | SUB (DevCol%) | Fill screen (not traditional colors) | 1
FillRect | SUB (x1%, y1%, x2%, y2%, c%) | Draw & Fill a rectangle | 5
Flip | SUB | Copies off-screen buffer to visible page | 0
Init | SUB (Width%, Height%) | Create Screen | 2
Line | SUB (x1%, y1%, x2%, y2%, c%) | Draws a line | 5
Paint | SUB (x%, y%, c%, borderc%) | Fill Region | 4
Pset | SUB (x%, y%, c%) | Pixel Plot | 3
Rectangle | SUB (x1%, y1%, x2%, y2%, c%) | Draws a rectangle | 5
Release | SUB | Force update | 0
Rotate | SUB (xOrigin%, yOrigin%, Angle%) | Rotates entire screen at specified origin | 3 | W
StretchDraw | SUB (Rect AS QRECT, BMP) | Draw BMP and stretch to fit inside Rect | 2
TextHeight | FUNCTION (Text$) AS WORD | Returns the height, in pixels, of Text$ string | 1
TextWidth | FUNCTION (Text$) AS WORD | Returns the width, in pixels, of Text$ string | 1
TextRect | SUB (Rect AS QRECT, x%, y%, S$, fc%, bc%) | Write text, and clip within region Rect | 6
TextOut | SUB (x%, y%, S$, fc%, bc%) | Writes text | 5
QDXScreen 3D Methods
Method | Type | Description | Params
AddLight | SUB (Light AS QD3DLight) | Add light to scene | 1
CameraLookAt | SUB (F AS QD3DFrame, Constraint AS INTEGER) | Fix frame and constrain rotation | 2
CreateFace | SUB (Face AS QD3DFace) | Creates a face | 1
CreateFrame | SUB (Frame AS QD3DFrame) | Creates frame | 1
CreateLightRGB | SUB (LightType%, R#, G#, B#, Light AS QD3DLight) | Create light object | 5
CreateMeshBuilder | SUB (MB AS QD3DMeshBuilder) | Creates meshbuilder | 1
CreateShadow | SUB (MB AS QD3DMeshBuilder, Light AS QD3DLight, px#, py#, pz#, nx#, ny#, nz#, V AS QD3DVisual) | Creates a visual shadow object | 9
CreateWrap | SUB (WrapType%, A#, B#, C#, D#, E#, F#, G#, H#, I#, J#, K#, L#, M#, W AS QD3DWrap) | Creates a wrap object | 15
ForceUpdate | SUB (X1%, Y1%, X2%, Y2%) | Force update on specific region | 4
LoadTexture | SUB (File AS STRING, Tex AS QD3DTexture) | Create a texture object | 2
Move | SUB (D AS DOUBLE) | Moves/animates scene | 1
SetBackgroundImage | SUB (Tex AS QD3DTexture) | Set background image for scene | 1
SetCameraPosition | SUB (X#, Y#, Z#) | Set camera position for entire scene | 3
SetCameraOrientation | SUB (DX#, DY#, DZ#, UX#, UY#, UZ#) | Set camera orientation for scene | 6
SetRenderMode | SUB (M AS INTEGER) | Set render mode for scene | 1
SetTextureQuality | SUB (Quality AS INTEGER) | Set texture quality for scene | 1

QDXScreen Events
Event | Type | Occurs when... | Params
OnClick | VOID | Mouse button clicked | 0
OnDblClick | VOID | Mouse button double clicked | 0
OnInitialize | VOID | DirectX succeeds in initializing | 0
OnInitializeSurface | VOID | Another event for you to do initializing | 0
OnKeyDown | SUB (Key AS Word, Shift AS INTEGER) | Key held down | 2
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1
OnMouseDown | SUB (Button%, X%, Y%) | Mouse button held down | 3
OnMouseMove | SUB (X%, Y%) | Mouse moves | 2
OnMouseUp | SUB (Button%, X%, Y%) | Mouse button is released | 3

QDXScreen Examples
$APPTYPE GUI
$TYPECHECK ON
$INCLUDE "RAPIDQ.INC"

DIM Form AS QForm
    Form.ClientHeight = 480
    Form.ClientWidth = 640
DIM Screen AS QDXScreen

Screen.Parent = Form
Screen.Init(640, 480)
Screen.Align = alClient

Form.ShowModal


Appendix B: QDXTIMER

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QDXTIMER

QDXTIMER Component

QDXTimer is a high precision timer for DirectX. It has automatic frame adjustments.

QDXTimer Properties
Field | Type | R/W | Default
ActiveOnly | INTEGER | RW | True
Enabled | INTEGER | RW | False
FrameRate | INTEGER | R
Interval | INTEGER | RW

QDXTimer Methods
Method Type Description Params

QDXTimer Events
Event | Type | Occurs when... | Params
OnTimer | VOID | Timer expired | 0

QDXTimer Examples
See DIRECTX.BAS example


Appendix B: QD3DFACE

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DFACE

QD3DFACE Component

QD3DFace implements IDirect3DRMFace.

QD3DFace Properties
Field | Type | R/W | Default
VertexCount | INTEGER | R

QD3DFace Methods
Method | Type | Description | Params
AddVertex | SUB (X#, Y#, Z#) | Add a vertex | 3
GetVertex | SUB (Index AS LONG, Position AS QD3DVector, Normal AS QD3DVector) | Retrieve the position and normal of a vertex | 3
SetColorRGB | SUB (R#, G#, B#) | Set face color | 3

QD3DFace Events
Event Type Occurs when... Params

QD3DFace Examples
' Direct 3D construction using Faces

$TYPECHECK ON

CONST alClient = 5

'-- Light Types
CONST D3DRMLIGHT_AMBIENT = 0
CONST D3DRMLIGHT_POINT = 1
CONST D3DRMLIGHT_SPOT = 2
CONST D3DRMLIGHT_DIRECTIONAL = 3
CONST D3DRMLIGHT_PARALLELPOINT = 4

'-- Renderer modes
CONST D3DRMRENDERMODE_BLENDEDTRANSPARENCY = 1
CONST D3DRMRENDERMODE_SORTEDTRANSPARENCY = 2
CONST D3DRMRENDERMODE_LIGHTINMODELSPACE = 8
CONST D3DRMRENDERMODE_VIEWDEPENDENTSPECULAR = 16
CONST D3DRMRENDERMODE_DISABLESORTEDALPHAZWRITE = 32

DECLARE SUB DXInitialize(Sender AS QDXScreen)
DECLARE SUB DXInitializeSurface(Sender AS QDXScreen)
DECLARE SUB DXTimerExpired

DIM DXTimer AS QDXTimer
    DXTimer.Enabled = 1
    DXTimer.Interval = 0
    DXTimer.Activeonly = 0
    DXTimer.OnTimer = DXTimerExpired
DIM MeshBuilder AS QD3DMeshBuilder
DIM MeshFrame AS QD3DFrame

CREATE Form AS QForm
    Caption = "Direct 3D Example"
    Width = 640
    Height = 480
    Center
    CREATE DXScreen AS QDXScreen
        Init(640,480)
        Align = alClient
        BitCount = 16
        Use3D = 1
        UseHardware = 0        '' This is for non-3D accelerated video cards.
                               '' 3D will be emulated using software, which
                               '' is much slower.
        OnInitialize = DXInitialize
        OnInitializeSurface = DXInitializeSurface
    END CREATE
    ShowModal
END CREATE

SUB DXInitialize(Sender AS QDXScreen)
   DIM Light AS QD3DLight, Ambient AS QD3DLight
   DIM LightFrame AS QD3DFrame
   DIM Face AS QD3DFace

   DXScreen.CreateFrame(LightFrame)
   DXScreen.CreateFrame(MeshFrame)

   DXScreen.CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, 0.9, 0.9, 0.9, Light)
   LightFrame.AddLight(Light)

   DXScreen.CreateLightRGB(D3DRMLIGHT_AMBIENT, 0.6, 0.6, 0.6, Ambient)
   DXScreen.AddLight(Ambient)

   LightFrame.SetPosition(2, 0, 22)
   DXScreen.SetCameraPosition(-5, 10, 0)

   MeshFrame.AddLight(Ambient)
   MeshFrame.SetPosition(0, 0, 0)
   MeshFrame.SetRotation(0, 0, 0, 0.05)       ' Angle of rotation = 0.05

   DXScreen.CreateMeshBuilder(MeshBuilder)
   DXScreen.CreateFace(Face)

   Face.AddVertex(0.996094,1.000000,-0.995850)
   Face.AddVertex(-0.995850,1.000000,-0.995850)
   Face.AddVertex(-0.995850,1.000000,0.996094)
   Face.AddVertex(0.996094,1.000000,0.996094)
   Face.AddVertex(0.996094,-0.999756,-0.995850)
   Face.AddVertex(-0.995850,-0.999756,-0.995850)
   Face.AddVertex(-0.995850,-0.999756,0.996094)
   Face.AddVertex(0.996094,-0.999756,0.996094)

   MeshBuilder.AddFace(Face)

   MeshBuilder.Scale(2,2,2)
   MeshBuilder.SetRGB(1, 1, .7)
   MeshFrame.AddVisual(MeshBuilder)
   DXScreen.CameraLookAt(MeshFrame, 1)
END SUB

SUB DXInitializeSurface(Sender AS QDXScreen)
   DXScreen.SetRenderMode(D3DRMRENDERMODE_BLENDEDTRANSPARENCY OR D3DRMRENDERMODE_SORTEDTRANSPARENCY)
END SUB

SUB DXTimerExpired
   DXScreen.ForceUpdate(0,0,50,40)     ' Update FPS text only
   DXScreen.Move(1)                    ' This does the rotation by 2 times
   DXScreen.Render
   DXScreen.TextOut(10,10,"FPS: "+STR$(DXTimer.FrameRate), &HFFFFFF, -1)
   DXScreen.Flip
END SUB


Appendix B: QD3DFRAME

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DFRAME

QD3DFRAME Component

QD3DFrame implements IDirect3DRMFrame.

QD3DFrame Properties
Field | Type | R/W | Default
FogColor | INTEGER | RW
FogEnabled | INTEGER | RW
FogMode | INTEGER | RW

QD3DFrame Methods
Method | Type | Description | Params
AddLight | SUB (Light AS QD3DLight) | Add light object to frame | 1
AddScale | SUB (CombineType%, X#, Y#, Z#) | Add scale | 4
AddVisual | SUB (Visual AS QD3DMeshBuilder/QD3DMesh/QD3DVisual) | Add visual object to frame | 1
CreateFrame | SUB (Frame AS QD3DFrame) | Create frame relative to this | 1
DeleteFrame | SUB (Frame AS QD3DFrame) | Removes a frame from hierarchy | 1
DeleteVisual | SUB (Visual AS QD3DMeshBuilder/QD3DMesh/QD3DVisual) | Removes visual object from frame | 1
Load | SUB (FileName AS STRING) | Load a frame from .X file | 1
LookAt | SUB (F AS QD3DFrame, Constraint AS INTEGER) | Fix frame and constrain rotation | 2
Move | SUB (D AS DOUBLE) | Moves frame (rotate) | 1
SetBackgroundImage | SUB (Texture AS QD3DTexture) | Add texture to frame | 1
SetBackgroundRGB | SUB (R#, G#, B#) | Set background color | 3
SetFogParams | SUB (Start#, End#, Density#) | Set fog parameters | 3
SetOrientation | SUB (DX#, DY#, DZ#, UX#, UY#, UZ#) | Set orientation of frame | 6
SetPosition | SUB (X#, Y#, Z#) | Set viewing position of frame | 3
SetRotation | SUB (X#, Y#, Z#, Theta#) | Set rotation relative to X,Y,Z | 4
SetTexture | SUB (Tex AS QD3DTexture) | Add texture backdrop to frame | 1

QD3DFrame Events
Event Type Occurs when... Params

QD3DFrame Examples


Appendix B: QD3DLIGHT

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DLIGHT

QD3DLIGHT Component

QD3DLight implements IDirect3DRMLight.

QD3DLight Properties
Field Type R/W Default

QD3DLight Methods
Method | Type | Description | Params
SetLightRGB | SUB (LightType%, R#, G#, B#) | Set lighting type and color | 4
SetPenUmbra | SUB (Angle#) | Set light of outer cone | 1
SetRange | SUB (Range#) | Set range of light | 1
SetUmbra | SUB (Angle#) | Set light of inner cone | 1

QD3DLight Events
Event Type Occurs when... Params

QD3DLight Examples


Appendix B: QD3DMESH

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DMESH

QD3DMESH Component

QD3DMesh implements IDirect3DRMMesh.

QD3DMesh Properties
Field | Type | R/W | Default
MaxY | SINGLE | R
MinY | SINGLE | R

QD3DMesh Methods
Method Type Description Params

QD3DMesh Events
Event Type Occurs when... Params

QD3DMesh Examples


Appendix B: QD3DMESHBUILDER

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DMESHBUILDER

QD3DMESHBUILDER Component

QD3DMeshBuilder implements IDirect3DRMMeshBuilder.

QD3DMeshBuilder Properties
Field | Type | R/W | Default
FaceCount | INTEGER | R

QD3DMeshBuilder Methods
Method | Type | Description | Params
AddFace | SUB (Face AS QD3DFace) | Add a face to mesh object | 1
AddVertex | SUB (X#, Y#, Z#) | Add a vertex | 3
CreateFace | SUB (Face AS QD3DFace) | Creates a new face with no vertices | 1
CreateMesh | SUB (Mesh AS QD3DMesh) | Create mesh from meshbuilder | 1
DeleteFace | SUB (Face AS QD3DFace) | Delete face from meshbuilder | 1
GetFace | SUB (Index AS LONG, Face AS QD3DFace) | Get a single mesh face | 2
Load | SUB (S AS STRING) | Load an object file (.x file) | 1
Move | SUB (D AS DOUBLE) | Moves frame (rotate) | 1
Scale | SUB (X#,Y#,Z#) | Scale object | 3
SetQuality | SUB (Quality AS INTEGER) | Set rendering quality | 1
SetRGB | SUB (R#, G#, B#) | Set object's color | 3
SetRGBA | SUB (R#, G#, B#, A#) | Add color w/alphablending | 4
SetTexture | SUB (Tex AS QD3DTexture) | Add texture backdrop to object | 1
Translate | SUB (TX#, TY#, TZ#) | Translate is a move operation but in 3D | 3

QD3DMeshBuilder Events
Event Type Occurs when... Params

QD3DMeshBuilder Examples


Appendix B: QD3DTEXTURE

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DTEXTURE

QD3DTEXTURE Component

QD3DTexture implements IDirect3DRMTexture.

QD3DTexture Properties
Field Type R/W Default

QD3DTexture Methods
Method Type Description Params

QD3DTexture Events
Event Type Occurs when... Params

QD3DTexture Examples


Appendix B: QD3DVECTOR

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DVECTOR

QD3DVECTOR Component

QD3DVector implements D3DVector.

QD3DVector Properties
Field | Type | R/W | Default
DVX | SINGLE | RW
DVY | SINGLE | RW
DVZ | SINGLE | RW
X | SINGLE | RW
Y | SINGLE | RW
Z | SINGLE | RW

QD3DVector Methods
Method Type Description Params

QD3DVector Events
Event Type Occurs when... Params

QD3DVector Examples


Appendix B: QD3DVISUAL

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DVISUAL

QD3DVISUAL Component

QD3DVisual implements IDirect3DRMVisual.

QD3DVisual Properties
Field Type R/W Default

QD3DVisual Methods
Method Type Description Params

QD3DVisual Events
Event Type Occurs when... Params

QD3DVisual Examples


Appendix B: QD3DWRAP

Rapid-Q Documentation by William Yu (c)1999 Appendix B: QD3DWRAP

QD3DWRAP Component

QD3DWrap implements IDirect3DRMWrap.

QD3DWrap Properties
Field Type R/W Default

QD3DWrap Methods
Method | Type | Description | Params
Apply | SUB (M AS QD3DMesh) | Apply wrap to mesh | 1
ApplyRelative | SUB (F AS QD3DFrame, M AS QD3DMesh) | Apply wrap relative to frame | 2

QD3DWrap Events
Event Type Occurs when... Params

QD3DWrap Examples


Appendix C: Operators

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Operators

Introduction to Operators

Operators perform mathematical or logical operations on values. They are usually encompassed by an expression. For example, 2 * 8 is a valid expression, and * is an operator operating on values 2 and 8. Rapid-Q can evaluate both INFIX and POSTFIX (RPN) expressions, but if you want to evaluate POSTFIX expressions, you'll need to note the special cases.

Arithmetic operators
Rapid-Q maintains a table of precedence for each operator. The highest precedence operator will always execute before any lower precedence operator. For operators that share the same precedence, the left to right associativity law holds. Expressions enclosed in braces (...) automatically have higher precedence than expressions outside the braces.
Operation Operator Precedence Description
Exponentiation ^ 1 Calculates power of a number
ie. 2^6
is 2 to the power of 6
Negation - 1 Negates a number
ie. -99
is negative 99
Multiplication * 2 Multiplies 2 numbers
ie. 2*6
is 2 multiplied by 6
Floating-point Division / 2 Divides 2 floating point numbers
ie. 6.5/2.6
is 6.5 divided by 2.6
Integer Division \ 2 Divides 2 integer numbers
Before integer division is performed, operands are rounded to integers. The result is truncated to an integer value.ie. 6\2
is 6 divided by 2
Left Bit Shift SHL 2 Shifts bits left by amount specified
ie. 10 SHL 2
is number 10 whose bits are shifted 2 bits to the left
Right Bit Shift SHR 2 Shifts bits right by amount specified
ie. 10 SHR 2
is number 10 whose bits are shifted 2 bits to the right
Modulus/Remainder MOD 3 Returns the remainder of the division
ie. 15 MOD 10
is 15/10 whose remainder is 5
Inverse Modulus INV 3 Returns the inverse of a number in modulus
ie. 3 INV 26
The inverse of 3 is 9 in 1 (MOD 26)
Addition + 4 Add 2 operands (strings included)
ie. 3+6
is 3 plus 6 = 9
ie. "hi"+"world"
is "world" appended to "hi" = "hiworld"
Subtraction - 4 Subtracts 2 operands (strings included)
ie. 6-3
is 6 minus 3 = 3
ie. "jello"-"l"
is "jello" minus all occurrences of "l" = "jeo"

Relational operators
Relational operators are used to compare 2 values. The result of this comparison is either "true" (nonzero) or "false" (zero). You may assume that "true" equals -1.
Relation Operator Precedence Description
Equality = 5 Tests for equality between 2 operands (strings included)
ie. 2=2
if 2 equals 2 then "true" else "false"
Inequality <> 5 Tests for inequality between 2 operands (strings included)
ie. "hello"<>"world"
if "hello" is not equal to "world" then "true" else "false"
Less than < 5 Tests if operand is less than another (strings included)
ie. 2<10
if 2 is less than 10 then "true" else "false"
Greater than > 5 Tests if operand is greater than another (strings included)
ie. "z">"a"
if "z" is greater than "a" then "true" else "false"
Less than or equal <= 5 Tests if operand is less than or equal to another (strings included)
ie. 2<=10
if 2 is less than or equal to 10 then "true" else "false"
Greater than or equal >= 5 Tests if operand is greater than or equal to another (strings included)
ie. 20>=10
if 20 is greater than or equal to 10 then "true" else "false"

Logical operators
Logical operators perform tests on multiple relations, bit manipulation, or Boolean operations and return a true (nonzero) or false (zero) value to be used in making a decision.
Operation Operator Precedence Description
Logical complement NOT 6 Returns the complement (inverted bits)
ie. NOT -1
-1 has all bits set, NOT -1 inverts all bits
Conjunction AND 7 Compare corresponding bits in 2 operands and sets the corresponding bit in the result to 1 if both bits are 1.
ie. 5 AND 3
5 AND 3 = 1 since they share one bit in common
Disjunction (inclusive "or") OR 8 Compares corresponding bits in 2 operands and sets bit to 1 if either one has a corresponding bit set.
ie. 5 OR 3
5 OR 3 = 7 since bits overlap
Exclusive "or" XOR 9 Compares corresponding bits in 2 operands and sets bit to 1 if only one of the operands has a corresponding bit set.
ie. 5 XOR 3
5 XOR 3 = 6 since one bit overlaps

INFIX/POSTFIX notation
Expressions, in most languages, are expressed in INFIX notation. Rapid-Q prefers INFIX notation, but can also handle POSTFIX notation with a few special cases.
      Example INFIX expression:
          A = 4 * 7 + (4 - 1)^6
INFIX notation is easier to use and understand than POSTFIX notation. In fact, Rapid-Q's POSTFIX notation is a simple side effect, and was not intentional. Please avoid using POSTFIX if possible.
      Example POSTFIX expression:
          A = (4) (7) (*) (4) (1) (-) (6) (^) (+)
The 2 expressions should evaluate to 757. As you'll note, when dealing with POSTFIX notation, make sure all operands and operators are enclosed in braces. When dealing with negation, you'll have to do this instead:
      Example POSTFIX expression w/negation:
          A = (5) (0-5) (-)
Notice that (0-5) and (-5) return different results.


Appendix C: Rapid-Q definitions

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Rapid-Q definitions

Internal Definitions

Rapid-Q has these variables already defined:
    $DEFINE WIN32 WIN32
    $DEFINE UNIX  UNIX
    $DEFINE TYPE  STRUCT
WIN32 is defined if you're using the Windows version of Rapid-Q
UNIX is defined if you're using the Linux/Unix version of Rapid-Q
TYPE is defined to replace the old style TYPE

Unhooking definitions
The term "unhooking" just means undefining a definition, ie:
    $UNDEF TYPE
This is the only definition (at this time) that can affect your program when unhooked. See the section on "User Defined Types" for more information.

Using definitions
Chapter 3 lists some examples on using $IFDEF and $IFNDEF:
    $IFDEF WIN32
         PRINT "I'm using the Windows version!"
    $ELSE
         PRINT "I'm using the Linux/Unix version!"
    $ENDIF


Appendix C: Branching with GOTO and GOSUB

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Branching

Introduction to Branching

Branching seems to be very popular in BASIC, mainly because in the old days, BASIC was very unstructured and didn't carry with it the concepts we now see today. Sure, some say it's still unstructured, but so is a lot of other languages depending on your coding style. Branching is just the mechanism of skipping (or jumping) instructions, either forward or backward. It's much like writing SUBs and FUNCTIONs, just a bit more unstructured as you'll see.

What are labels?
Before talking about GOTOs and GOSUBs, you'll need to understand what labels are. You can think of them as bookmarks, they don't actually do anything, but you can use labels as a guide. The following are valid labels:
    Label1:
    100
    10.5
A label always appears as the first statement and can be any number or a named label. A named label must end with a colon : symbol. After any label, you can write your code as before.
    Label1:
       PRINT "some code..."
    100 PRINT "more code"
    10.5
       PRINT "yet more code"
The formatting above is just an example, it doesn't mean that a named label can't have code on the same line.

Branching with GOTO
Perhaps the most shunned upon keyword in BASIC is the GOTO statement. Obviously if you programmed in BASIC before, GOTO was used almost everywhere. This is because GOTO was so easy to understand, and when we first jump into programming, we don't usually pick up what subroutines and functions are. Rapid-Q still supports GOTO, but we definitely don't encourage its use, at all. In fact, if you find yourself using it now, you'll probably wonder why in a few years/months as you become more experienced. Here's an example of using GOTO:
    IF I = 100 THEN GOTO 10 ELSE GOTO 20

    10 PRINT "I = 100"
       END

    20 PRINT "I is not 100"
       END
If it's so terrible, are there any penalties in its use? No. In fact, it's probably the purest command you'll find. All it does is skip instructions, so in the above example, if I = 200, then the lines
    10 PRINT "I = 100"
       END
are skipped. GOTO requires no stack or memory consumption, unlike GOSUB and SUBs or FUNCTIONs. If you want to think about assembly, that's basically all you do, branch here and there, but since BASIC is a high level language, we usually don't like to think that way, so we avoid using GOTO if possible.

Branching with GOSUB .. RETURN
Using GOSUB is actually more useful than using GOTO, but still not recommended. It is in essence, calling a SUB without parameters. What it provides is a quick "hack" without creating SUBs. It is often used in loops, as you may see here:
    DO
      DO
        A$ = INKEY$
      LOOP UNTIL LEN(A$)

      IF A$ = "A" THEN
          GOSUB 100
      ELSEIF A$ = "B" THEN
          GOSUB 110
      ELSEIF A$ = "C" THEN
          GOSUB 110
      END IF
    LOOP

    END

    100 PRINT "A pressed"
        RETURN
    110 PRINT "B pressed"
        RETURN
    120 PRINT "C pressed"
        RETURN
The RETURN statement is used to jump back to the previous call of GOSUB. You can think of GOSUB as a GOTO statement with a marker, and the RETURN statement as another GOTO statement that returns to that marker.


Appendix C: User Defined Types

Rapid-Q Documentation by William Yu (c)1999 Appendix C: User Defined Types

Introduction to UDTs

User defined types (or UDTs) are structures that you can use in most BASIC languages, Rapid-Q is no exception.

Using TYPE
Here's an example of a user defined type:
    TYPE TWorld
        CityName(100) AS STRING
        Population(100) AS LONG
    END TYPE

    DIM World AS TWorld
As you can see, you can have arrays within UDTs. You can also create arrays of UDTs:
    TYPE TWorld
        CityName(100) AS STRING
        Population(100) AS LONG
    END TYPE

    DIM Country(100) AS TWorld
There is currently an issue with the memory address of your array (within UDT). Please note that this is hardly ever noticed unless you're going to pass one of these structures to a DLL that require arrays within UDTs. This address problem won't affect your program, but it's hard to explain (without getting too deep). NOTE: it only occurs when you create arrays of UDTs that have arrays within UDTs. In the first example (higher up), there is no address problem since you're not creating an array of UDTs. You can safely pass that to a DLL.

Copying UDTs
To copy 2 UDTs, just assign the two:
    TYPE TStuff
        A AS LONG
        B AS INTEGER
    END TYPE

    DIM S1 AS TStuff
    DIM S2 AS TStuff

    S1 = S2
Contents in S2 are copied to S1. When dealing with arrays within UDTs, the arrays are not copied, only referenced. To copy arrays of UDTs, you'll have to manually copy each one:
    DIM S1(100) AS TStuff
    DIM S2(100) AS TStuff

    FOR I = 1 TO 100
        S1(I) = S2(I)
    NEXT

Unhooking TYPE
There are actually 2 ways to create your types, with TYPE and STRUCT. STRUCT is actually mirrored in TYPE, to unhook the two, you have to undefine TYPE.
    $UNDEF TYPE

    STRUCT TWorld
        CityName(100) AS STRING
        Population(100) AS LONG
    END STRUCT

    DIM World AS TWorld
Using TYPE and STRUCT are not the same. If you unhook the two, TYPE now reverts back to the old style (pre-May 17 version), where arrays of UDTs is not allowed. Why the heck would I want a stripped down version? Well, perhaps performance. The old style TYPE lacks in many things, but makes up in performance, if that's really necessary.


Appendix C: Conditions

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Conditions

Introduction to Condition Statements

Conditional statements offer the ability to execute code for which the condition is satisfied. This is probably one of the first things you learn in programming, besides the usual.

IF .. THEN .. ELSE
There are 2 ways to use IF .. THEN .. ELSE. You can place your statement on one single line like so:
    IF I > 100 THEN PRINT "I is greater than 100"
Or split it up like so:
    IF I > 100 THEN
      PRINT "I is greater than 100"
    END IF
As you can see, I > 100 is a condition, as long as this is satisfied, the code gets executed, if not then that piece of code is skipped. A condition is satisfied whenever the expression evaluates to any non-zero number. Which also means that this is valid:
   I = 100
   IF I THEN
     PRINT "Condition satisfied"
   ELSE
     PRINT "Condition is not satisfied"
   END IF
Use ELSEIF whenever you have multiple conditions that you want satisfied:
   IF I > 10 AND I < 20 THEN
      '' do stuff
   ELSEIF I > 55 THEN
      '' do stuff
   ELSE
      '' do stuff
   END IF
Sometimes it helps to use SELECT CASE instead of all these ELSEIFs, which we'll cover next.

SELECT CASE .. END SELECT
Select cases are usually implemented when you have a lot of conditions that you want to test for. It's really not useful if you only have 2 or 3 conditions, but no one's stopping you from using it. There are no special cases in using SELECT CASEs in Rapid-Q, so everything you learned in QBasic, can be implemented here as well.
    SELECT CASE Expression
      CASE 1
        '' Do stuff
      CASE 5
        '' Do stuff
      CASE ELSE
        '' No conditions satisfied, do stuff
    END SELECT
It probably involves less typing, but there are many other useful purposes, for example, range testing becomes so much easier:
    SELECT CASE Expression
      CASE 1 TO 4, 10 TO 20
        '' Do stuff
      CASE 100 TO 150
        '' Do stuff
      CASE IS > 200
        '' Do stuff
    END SELECT
As you can see, you can have multiple test conditions by separating each with a comma. I think you can figure out how the IS keyword is used.


Appendix C: Loops

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Loops

Introduction to Looping

Loops provide a mechanism for executing a series of instructions a certain number of times. Many of your programs will involve looping. Compilers convert loops to GOTO statements, so you could implement your own LOOP using GOTOs without any consequences. However, for optimization purposes, the FOR loop in Rapid-Q doesn't use this mechanism to save on unnecessary instructions. You may notice that your FOR loop is slightly faster than your WHILE or DO loop in Rapid-Q.

FOR .. NEXT Loop
As previously stated, in Rapid-Q this looping structure is optimized, but you may only notice a slight difference. There are some special cases when using a FOR loop in Rapid-Q.
    FOR I(1) = 1 to 100
    NEXT
This is not valid in Rapid-Q. Why not? Because I(1) is an array, you'll get a compiler error. Only simple types are supported, which means anything BUT arrays. The default increment value is 1, if you want a different increment value, please use STEP:
    FOR I = 1 TO 100 STEP 2
      PRINT I
    NEXT
This will skip all the even numbers, so the output will be: 1 3 5 7 9 ...etc. If for whatever reason you wanted to exit the loop, you can use EXIT FOR.

WHILE .. WEND
If you want to test a condition before entering the loop, you could use a WHILE .. WEND loop. There are no special cases when using this loop, it's exactly like QBasic:
    WHILE I < 100
      I++          '-- Increment I
    WEND
It's much like a DO .. LOOP, except the expression is tested before entering the loop. To exit the WHILE .. WEND loop for whatever reason, you use EXIT WHILE.

DO .. LOOP
A simple DO .. LOOP without any test expression will loop infinitely:
    DO
      PRINT " Hello World! "
    LOOP
To exit the DO .. LOOP, you use EXIT DO. Infinite loops aren't used much in Windows programming (event based anyway). You'll usually want a test expression as in our WHILE .. WEND loop, except we place it differently:
    DO
      I++
    LOOP UNTIL I >= 100
Unlike QBasic or other implementations of BASIC, Rapid-Q does not offer DO WHILE or LOOP WHILE. They're basically useless (ie. they can be implemented in another way), except to provide users with more options. For example, this is valid in QBasic:
   DO
   LOOP WHILE I < 100
Which is equivalent to:
   DO
   LOOP UNTIL I >= 100


Appendix C: Methods

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Methods

Introduction to Methods

There's many definitions of a "method," for lack of a better word, that's what I'm using to describe the methods CONSTRUCTOR, CREATE and WITH. Alone they serve no purpose, but you'll learn what each does, and how to use them here.

CREATE .. END CREATE
Using CREATE is exactly like using DIM
    CREATE Form AS QForm
    END CREATE

    '' or

    DIM Form AS QForm
However, the CREATE method offers more. It can save you typing, and also make your code look cleaner by embedding CREATEs (refer to Chapter 5). Any code you type inbetween the CREATE .. END CREATE method is automatically bound to that object. Since there's no point in regurgitating what was already mentioned, please refer to Chapter 5 for some examples.

WITH .. END WITH
The WITH construct is to provide the developer an easier way to reference properties, methods, and events of certain objects. Basically what it does is save you a lot of typing:
    Form.Caption = "Hello"
    Form.ShowModal

    '' Using WITH

    WITH Form
       .Caption = "Hello"
       .ShowModal
    END WITH
You can also embed WITH .. END WITH statements:
    Something.Another.Caption = "Hello"

    '' Using WITH

    WITH Something
       WITH Another
         .Caption = "Hello"
       END WITH
    END WITH
As you can see, the embedded WITH statement inherits the previous declaration. The period at the front tells the compiler to bind that variable to the WITH declaration. Anything which doesn't start with a period won't be bound, don't worry, decimal numbers won't be bound.

CONSTRUCTOR .. END CONSTRUCTOR
This method is only used inside a TYPE declaration when you're defining your own objects. It will give default values to your properties whenever your component is created (DIMmed).
    TYPE NewObject EXTENDS QObject
      Left AS INTEGER

      CONSTRUCTOR
        Left = 50
      END CONSTRUCTOR
    END TYPE
There's nothing to it, it's much like the CREATE method, except our object in this case is NewObject.


Appendix C: Procedures

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Procedures

Introduction to Procedures

A procedure in BASIC is either a SUB or FUNCTION (or SUBI and FUNCTIONI). It's functionally the same as GOSUB and RETURN but introduces the concept of parameters and return values. Unlike QBasic, a FUNCTION can also be called as a SUB. Meaning you can ignore its return value.

DECLARE SUB
Use DECLARE SUB whenever you want to provide a "forward" declaration without actually writing the SUB yet.
    DECLARE SUB Test

    CALL Test

    SUB Test
      '' Do Stuff
    END SUB
Using CALL to call your subroutine is strictly optional. As you can see, we're providing a forward declaration of the SUB Test. To avoid using DECLARE SUB, you could have written the SUB Test before CALLing it.
    SUB Test
    END SUB

    Test
This way you don't need to use DECLARE SUB. Please note that your parameter names in the DECLARE SUB and your actual SUB declaration MUST MATCH exactly! If you're not sure what I mean, take this for example:
    DECLARE SUB Test (A AS INTEGER, B AS INTEGER)

    SUB Test (X AS INTEGER, Y AS INTEGER)
       PRINT X;" ";Y
    END SUB
Don't change the variable names! This is because when you defined your DECLARE SUB, the parameter names have been fixed as A and B, which also means you can comfortably do this:
    DECLARE SUB Test (A AS INTEGER, B AS INTEGER)

    SUB Test
       PRINT A;" ";B
    END SUB
This is perfectly valid, since you've already declared your subroutine to have an A and B parameter. You don't actually need to define parameters if you already have a forward declaration in place. Obviously this can become confusing so it's not recommended.

Passing variables by reference
There are 2 ways to pass variables by reference. Unlike other BASIC languages, Rapid-Q assumes that all parameters are passed by value unless explicitly specified. To do this explicitly, you can attach a BYREF keyword in front of your parameter list. Here's an example
    SUB StrCat (BYREF Source AS STRING, Text AS STRING)
        Source = Source + Text
    END SUB

    A$ = "Hello"
    StrCat A$, " world!"
    PRINT A$              '-- returns "Hello world!"
Another way is to prepend an '@' symbol in front of the variable:
    SUB StrCat (Source AS STRING, Text AS STRING)
        Source = Source + Text
    END SUB

    A$ = "Hello"
    StrCat @A$, " world!"
    PRINT A$              '-- returns "Hello world!"

FUNCTIONs versus SUBs
The only difference between a FUNCTION and a SUB is that a FUNCTION returns a value.
   FUNCTION Test AS INTEGER
     Test = 123
     Result = 123
   END FUNCTION

   Rval% = Test
Our FUNCTION Test returns an INTEGER, which we can clearly see returns 123. To return a value, you can use the FUNCTION's name or use the keyword Result. Just because you've attached a return value to the FUNCTION, it does not automatically terminate until it reaches your END FUNCTION. So you can really assign as many return values as you like without consequences. The last return value assigned will ultimately be the one bound to your FUNCTION. To exit a FUNCTION or SUB, just use EXIT FUNCTION, or EXIT SUB respectively. One special case in using SUBs or FUNCTIONs in Rapid-Q is that you can only pass at most 10 parameters. Only simple types, QObjects and Arrays can be passed. No UDTs (user defined TYPEs). QObjects and Arrays are passed by reference, everything else is passed by value. In order for Rapid-Q to recognize that you want to pass a variable by reference, you must attach an @ symbol in front of the variable, or use BYREF in your parameter list. See Chapter 3 section 5 for more information.

SUBI and FUNCTIONI
There's a whole chapter reserved for these two procedure methods. It's not really that complicated, but is very handy to use. They provide the programmer with infinite parameters without type checking. Only simple types like numbers and strings can be passed, no Arrays, UDTs or QObjects. See Chapter 9 for all the details.


Appendix C: Internal Variables

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Internal Variables

Internal Variables

Internal Variables are Read-Only (except SCREEN.CURSOR). When I refer to Unix, I mean Linux & Unix.

Variable | Support | Type | Description
Application.Handle | Windows | INTEGER | Returns handle of your application, useful for API calls that require it.
Application.hInstance | Windows | INTEGER | Same as Application.Handle, but you may want to use this instead.
CommandCount | Windows Unix | INTEGER | Number of command line parameters received.
Command$() | Windows Unix | ARRAY | Array of commands received (commands are separated by spaces), first element starting at 1. The zero'th element is your application path/name.
CurDir$ | Windows Unix | STRING | Returns the current working directory of your application
IsConsole | Windows Unix | INTEGER | Returns a non-zero number if application is a console, 0 otherwise.
MouseX | Windows | INTEGER | Returns X Coordinate of Mouse Pointer relative to your active Form
MouseY | Windows | INTEGER | Returns Y Coordinate of Mouse Pointer relative to your active Form
ParamStrCount | Windows Unix | INTEGER | Returns number of String parameters received. This variable is used only inside a SUBI or FUNCTIONI declaration.
ParamStr$() | Windows Unix | ARRAY | Used only inside a SUBI or FUNCTIONI declaration. Returns string parameter value, first element starting at 0.
ParamVal() | Windows Unix | ARRAY | Used only inside a SUBI or FUNCTIONI declaration. Returns numeric parameter value, first element starting at 0.
ParamValCount | Windows Unix | INTEGER | Returns number of Numeric parameters received. This variable is used only inside a SUBI or FUNCTIONI declaration.
Screen.ConsoleX | Windows Unix | INTEGER | Returns maximum column for console screen, useful under Unix.
Screen.ConsoleY | Windows Unix | INTEGER | Returns maximum row for console screen, useful under Unix.
Screen.Cursor | Windows | INTEGER | Change global mouse pointer
Screen.Height | Windows | INTEGER | Returns Windows screen Height (not to be confused with Form Height)
Screen.Width | Windows | INTEGER | Returns Windows screen Width
Stack.Int() | Windows Unix | ARRAY | Returns most current stack integer parameter. First element starting at 0.
Stack.Str$() | Windows Unix | ARRAY | Returns most current stack string parameter. First element starting at 0.


Appendix C: Console keywords

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Console Keywords

Console Keywords

Please note that it's possible to use some Console statements in Linux/Unix even if you compiled your program as GUI. However, this is not possible under Windows. The console statements allowed in Linux/Unix without having to compile as CONSOLE are: CLS, PRINT, and INPUT. SLEEP can also be used without consequences.

Keyword Support Usage/Description
CLS Windows Unix CLS
Clears console screen
COLOR Windows Unix COLOR [Fore%][, Back%]
Sets current color attribute, you can ignore either one of the parameters
CSRLIN Windows Unix CurRow% = CSRLIN
Returns current row of cursor
INKEY$ Windows Unix A$ = INKEY$
Returns ASCII key character typed
INPUT Windows Unix INPUT A$
Reads a full line of input from user
LOCATE Windows Unix LOCATE [Y%][, X%]
Moves cursor to Y%, X% (upper left starts at 1,1). You can ignore either one of the parameters
PCOPY Windows PCOPY source, dest
Copy page from source to dest. The visible page is 0. There are 7 off screen pages.
PEEK Windows A% = PEEK([#PageNum,] address)
Returns the char/attribute value at address
POKE Windows POKE [#PageNum,] address, byte
Poke attribute or char at address
POS(0) Windows Unix CurPos% = POS(0)
Returns current position of cursor
PRINT Windows Unix PRINT [#PageNum[;|,]][stuff][;|,][...]
Write to standard output (console). To write to the offscreen buffers, use #PageNum. Where PageNum is 1-7. Only works under Windows.
SETCONSOLETITLE Windows SetConsoleTitle(Title$)
Set console title
SLEEP Windows Unix SLEEP n
Delay for n seconds, which can be a fraction


Appendix C: Detailed Console Keywords

Rapid-Q Documentation by William Yu (c)1999-2000 Appendix C: Detailed Console Keywords

Detailed Console Keywords

Most of these have the same functionality as QBasic, so you could just as easily look them up there. Again, when I refer to Unix, I mean Linux & Unix.

CLS | CONSOLE Statement | Windows/Unix
Clears console screen of all text, and fills the console with the currect background color. CLS also returns the cursor to the home position in the top left corner of the screen.

Syntax: CLS
CLS

Details:
Under Windows, CLS is a CONSOLE statement, under Linux/Unix, CLS is implemented as a system call to clear, so you can safely call CLS without compiling as CONSOLE under Linux/Unix.

COLOR | CONSOLE Statement | Windows/Unix
Sets the current display colors for the console screen.
  • Foreground is the text color (range = 0-31)
  • Background is the screen color (range = 0-7)
0 = black  4 = red       8 = grey        12 = light red
1 = blue   5 = magenta   9 = light blue  13 = light magenta
2 = green  6 = brown    10 = light green 14 = yellow
3 = cyan   7 = white    11 = light cyan  15 = bright white

Syntax: COLOR [foreground][,background]
COLOR 15
COLOR 10, 3
COLOR ,1
COLOR

CSRLIN | CONSOLE Function | Windows/Unix
Returns the current line (row) position of the cursor.

Syntax: CSRLIN
Row% = CSRLIN

GET$ | CONSOLE Function | Windows/Unix
This function is mainly used in CGI programs, but can be used as a general purpose read function. It will read the STDIN.

Syntax: GET$(numeric-expression)
A$ = GET$(10)

Details:
GET$ under Linux/Unix is not a console function. To use GET$, compile your application as CONSOLE or CGI under Windows.

INKEY$ | CONSOLE Function | Windows/Unix
Returns a one- or two-byte string containing a character read from standard input (console). An empty string is returned if no character is waiting there.

Syntax: INKEY$
A$ = INKEY$

Details:
Extended keys are not trapped under Windows. Extended keys under Linux/Unix start with CHR$(27) and LEN(A$) = 2. Extended keys are arrow keys, page up/down, home, end, insert, delete, and F1-F12 keys.

INPUT | CONSOLE Statement | Windows/Unix
Reads a whole line of input from the. This statement causes the program to pause and wait for data until a carriage return is pressed.

Syntax: INPUT ["Prompt string"{;|,}] string-variable
INPUT A$
INPUT "Enter name: "; A$

Details:
INPUT for Rapid-Q is not exactly compatible with QBasic's INPUT. It is more like LINE INPUT. The return variable must be a string variable. Under Windows, INPUT is implemented as a CONSOLE function. Under Linux/Unix INPUT is not considered a CONSOLE function so there's no need to compile as CONSOLE.

LOCATE | CONSOLE Statement | Windows/Unix
Moves cursor to specified position.

Syntax: LOCATE [row][,column]
LOCATE 10, 1
LOCATE ,10
LOCATE 5

Details:
Under Windows you can assume that Row 25 is the last row and Column 80 as the last column. Under Linux/Unix this is dependent on your terminal, but you can use the internal variables Screen.ConsoleX and Screen.ConsoleY to determine the max column and row respectively. The first row and first column always starts at (1,1).

PCOPY | CONSOLE Statement | Windows
Copies one screen page to another.

Syntax: PCOPY sourcepage, destinationpage
PCOPY 0, 1
PCOPY 1, 5

Details:
The visible (on-screen) page is always 0. There are 7 off-screen pages (1 to 7). You can copy from any page onto any other page.

PEEK | CONSOLE Function | Windows
Returns the current character/attribute pair stored at a specified location on the console screen.

Syntax: PEEK([#pagenum,] address)
A% = PEEK(2000) '-- Peek location 2000 on current page
A% = PEEK(1, 2000) '-- Peek location 2000 on page 1

Details:
To understand how to compute the address, use this handy function:
   Char$ = CHR$(PEEK((Row%-1)*160+(Col%-1)*2))
   Attr = PEEK((Row%-1)*160+(Col%-1)*2+1)
As you may notice, all the even memory addresses contain the character, and all the odd numbered addresses contain the attribute. The attribute contains information about the foreground and background color.
   ForeGround% = Attr AND &HF
   BackGround% = Attr SHR 4
Why all the trouble? This is implemented for compatibility with QBasic. The only difference is that you don't use DEF SEG under Rapid-Q, and PEEK only works at the console level.

POKE | CONSOLE Statement | Windows
Writes a byte to the console page.

Syntax: POKE [#pagenum,] address, byte
POKE 2000, ASC("A") '-- Pokes an "A" character at location 2000
POKE 2001, 95 '-- Pokes attribute 95 to location 2000
POKE 1, 2001, 95 '-- Same as above but pokes to page 1

Details:
To understand how to compute the address, use this handy function:
   ChAddress = (Row%-1)*160+(Col%-1)*2
   AttrAddress = (Row%-1)*160+(Col%-1)*2+1
As you may notice, all the even memory addresses contain the character, and all the odd numbered addresses contain the attribute. The attribute contains information about the foreground and background color. To calculate the attribute, try this:
   Attr = (BackGround% SHL 4) OR ForeGround%
Why all the trouble? This is implemented for compatibility with QBasic. The only difference is that you don't use DEF SEG under Rapid-Q, and POKE only works at the console level.

POS | CONSOLE Function | Windows/Unix
Returns the current horizontal (column) position of the cursor.

Syntax: POS(0)
Column% = POS(0)

Details:
Please note that I did not make this function up (ie. its weird syntax), it's implemented for compatibility with QBasic.

PRINT | CONSOLE Statement | Windows/Unix
PRINT outputs data to the screen (or standard output).

Syntax: PRINT [#pagenum,][expressions][{;|,}]
PRINT "Number: "; 45
PRINT A$
PRINT #1, "This prints to screen page 1"

Details:
Expressions can be any string, number, or function. You can optionally use ; or , to print out more expressions. Under QBasic, PRINT can format your data if you use the comma, however, under Rapid-Q the comma and semi-colon have the same effect. Again, under Windows, PRINT is implemented as a CONSOLE function. Under Linux/Unix you do not need to compile as CONSOLE.

SETCONSOLETITLE | CONSOLE Statement | Windows
SetConsoleTitle is implemented as a WinAPI call to SetConsoleTitle but is called as a statement rather than a function (ie. no return value). If you would like a return value, you'll have to call the API function directly.

Syntax: SETCONSOLETITLE string-expression
SETCONSOLETITLE "Hello World!"

SLEEP | CONSOLE Statement | Windows/Unix
Suspends execution of the application for a specified amount of time.

Syntax: SLEEP seconds
SLEEP .5 '-- Delay for half a second

Details:
SLEEP requires a parameter, unlike QBasic. SLEEP waits until the number of seconds specified has elasped. You cannot break out of it by pressing a key (unlike QBasic). Under Windows, SLEEP is implemented as a console function. Under Linux/Unix, you do not need to compile as CONSOLE.


Appendix C: Reserved Keywords

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Reserved Keywords

Reserved Keywords

Most of these have the same functionality as QBasic, so you could just as easily look them up there. Again, when I refer to Unix, I mean Linux & Unix.

Keyword Support Usage/Description
ABS Windows Unix ABS(NumericExpression)
Return absolute value of number
ACOS Windows Unix ACOS(NumericExpression)
Returns arccosine of NumericExpression
ASC Windows Unix ASC(Char$)
Returns the ASCII key value of Char$
Application.Icon Windows Application.Icon = "MYICON.ICO"
Assign global application icon
Application.Minimize Windows Application.Minimize
Minimize your application
Application.Terminate Windows Application.Terminate
Terminates your GUI application
Application.Title Windows Application.Title = "My application"
Assign a new application title
ASIN Windows Unix ASIN(NumericExpression)
Returns arcsine of NumericExpression
ATN Windows Unix ATN(NumericExpression)
Returns arctangent of NumericExpression
BIN$ Windows Unix BIN$(Integer-Number)
Returns the binary representation of the Number (must be a positive integer).
BIND Windows Unix BIND Num TO MyFunc
BIND a function pointer
CALLFUNC Windows Unix CALLFUNC(Num, Param1, Param2, ...)
Call function pointer
CHDIR Windows Unix CHDIR Path$
Change directory
CHR$ Windows Unix CHR$(Byte)
Returns character corresponding to the ascii key value
CINT Windows Unix CINT(NumericExpression)
Implemented for compatibility reasons. Use ROUND instead.
CLNG Windows Unix CLNG(NumericExpression)
Implemented for compatibility reasons. Use ROUND instead.
CONST Windows Unix CONST Variable = Expression
Assigns Variable a constant value
CONVBASE$ Windows Unix CONVBASE$(Str$, FromBase, ToBase)
Returns the representation Str$ FromBase to ToBase representation.
COS Windows Unix COS(NumericExpression)
Returns cosine of an angle given in radians
DATA Windows Unix DATA constant|EXECUTE(...) [, constant|EXECUTE(...), ...]
Stores data for easy retrieval, use READ to read the data.
DATE$ Windows Unix DATE$
Returns the current Date in MM-DD-YYYY format.
DEC Windows Unix DEC(Variable [, DecVal])
Decrements variable by 1 unless otherwise specified
DEF... Windows Unix DEF(...) Variable
See details for more information on this statement
DELETE$ Windows Unix DELETE$(S$, Index, Count)
Deletes Count number of characters from S$ starting at Index
DIM Windows Unix DIM Variable AS DataType
Creates variable of type DataType
DIR$ Windows DIR$[(FileSpec$, Attributes%)]
Returns the next file of FileSpec$
DIREXISTS Windows DIREXISTS(Path$)
Returns 0 if directory does not exist, non-zero otherwise
DOEVENTS Windows DOEVENTS
Polls events, useful when you're in a deep/big loop
END Windows Unix END
Terminates program, only if running as CONSOLE, has no effect if running as GUI
EXP Windows Unix EXP(NumericExpression)
Calculates the exponential function (e raised to the power of NumericExpression)
ENVIRON Windows Unix ENVIRON StringExpression
Set environment string
ENVIRON$ Windows Unix ENVIRON$(environment-string)
Get environment value
EXTRACTRESOURCE Windows Unix EXTRACTRESOURCE ResourceNumber%, FileName$
Extracts a resource to file
FIELD$ Windows Unix FIELD$(StringExpresion, Deliminator, FieldNumber)
Returns a field/token separated by deliminators.
FILEEXISTS Windows Unix FILEEXISTS(FileName$)
Returns 0 if file not found, non-zero otherwise
FIX Windows Unix FIX(NumericExpression)
Truncates fractional number, rounding down towards 0.
FORMAT$ Windows FORMAT$(S$, arg1, arg2, ...)
Returns a formatted string assembled from a format string and a series of arguments (up to 50)
FRAC Windows Unix FRAC(NumericExpression)
Returns the fractional part of the numeric expression.
HEX$ Windows Unix HEX$(NumericExpression)
Returns the HEXidecimal string representation of the NumericExpression
INC Windows Unix INC(Variable [, IncVal])
Increments variable by 1 unless otherwise specified
INP Windows Unix INP(Address)
Returns the byte value read from an I/O port 0..65535
INSERT$ Windows Unix INSERT$(Source$, S$, Index)
Insert Source$ string to string S$ at Index
INSTR Windows Unix INSTR([Start,] SearchString, FindString)
Function returns the position in the SearchString that FindString was found, 0 otherwise
INT Windows Unix INT(NumericExpression)
Convert NumericExpression to a 32-bit INTEGER, truncating decimals.
KILL Windows Unix KILL Filename$
Deletes file
LCASE$ Windows Unix LCASE$(StringExpression)
StringExpression is lowercased
LEFT$ Windows Unix LEFT$(StringExpression, N)
Returns the leftmost N characters of a string
LEN Windows Unix LEN(StringExpression)
Returns the length of string
LOG Windows Unix LOG(NumericExpression)
Returns the natural logarithm of NumericExpression
LBOUND Windows Unix LBOUND(ArrayName[, Dimension])
Returns the lowerbound of an array (Dimension starts at 1)
LFLUSH Windows LFLUSH
Calling this will start printing your document. Make sure all your LPRINTs are executed before calling LFLUSH.
LPRINT Windows LPRINT [Expression][;|,][...]
LPRINT acts exactly like PRINT, except all output is directed to the default printer. Make sure to call LFLUSH. Also see the Printer component for graphical printing.
LTRIM$ Windows Unix LTRIM$(StringExpression)
Returns string with left padded spaces removed
MESSAGEDLG Windows MESSAGEDLG(Msg$, MsgType, MsgButtons, HelpContext)
Displays a message box, see RAPIDQ.INC for proper types & buttons
MID$ Windows Unix MID$(StringExpression, I, N)
Returns string with characters from I to N of StringExpression
MKDIR Windows Unix MKDIR Dir$
Creates new directory
OUT Windows Unix OUT(Address, bytevalue)
Sends a byte value to a machine I/O port 0..65535
PLAYWAV Windows PLAYWAV FileName$, SndOption
Plays a WAV file, see RAPIDQ.INC for sndOptions
POSTMESSAGE Windows POSTMESSAGE(Handle, uMsg, wParam, lParam)
Post message to handle, and does not block. Refer to your favourite WinAPI guide for the proper message numbers
QUICKSORT Windows QUICKSORT(Array-begin, Array-end, ASCEND | DESCEND)
Sort any array, BYTE, WORD, SHORT, STRING, etc...
RANDOMIZE Windows Unix RANDOMIZE [Num]
Use randomize to reseed the random number generator
READ Windows Unix READ variable [, variable, ...]
Reads next DATA statement, stores it in variable.
REDIM Windows Unix REDIM Array(1000) AS INTEGER
Use REDIM to redimension an array preserving existing data. REDIM is equivalent to DIM if the array has not yet been allocated.
RENAME Windows Unix RENAME File1$, File2$
Renames File1$ to File2$
REPLACE$ Windows Unix REPLACE$(S$, R$, Index)
Replaces a string from S$ with R$ starting at Index
REPLACESUBSTR$ Windows Unix REPLACESUBSTR$(Source$, ReplaceStr$, Withstr$)
Replaces the string ReplaceStr$ in Source$ with WithStr$
RESTORE Windows Unix RESTORE [linelabel]
Jumps to specific position in DATA statement.
RESOURCE Windows Unix RESOURCE(number%)
Get numeric value of Resource, mainly for use with ExtractResource, 0 based array.
RESOURCECOUNT Windows Unix RESOURCECOUNT
Get resource count.
REVERSE$ Windows Unix REVERSE$(S$)
Reverses a string
RGB Windows Unix RGB(Red%, Green%, Blue%)
Returns the BGR numeric representation of the color.
RIGHT$ Windows Unix RIGHT$(StringExpression, N)
Returns the righttmost N characters of a string
RINSTR Windows Unix RINSTR([Start,] SearchString, FindString)
Reverse INSTR Function, searching starts from the end of SearchString
RMDIR Windows Unix RMDIR Dir$
Removes directory
RND Windows Unix RND(UpperBound)
Returns a random number, if no upperbound is given, it returns a decimal number. Use RANDOMIZE to reseed.
ROUND Windows Unix ROUND(NumericExpression)
Rounds number to nearest integer.
RTRIM$ Windows Unix RTRIM$(StringExpression)
Returns string with rightmost padded spaces removed
RUN Windows Unix RUN command$
Executes command, but does not block
SENDMESSAGE Windows SENDMESSAGE(Handle, uMsg, wParam, lParam)
Post message to handle, and blocks. Refer to your favourite WinAPI guide for the proper message numbers
SGN Windows Unix SGN(NumericExpression)
Returns the sign of a numeric expression
SHELL Windows Unix SHELL command$
Executes command, and blocks until finished
SHOWMESSAGE Windows Unix SHOWMESSAGE msg$
Popups message in a simple box
SIN Windows Unix SIN(NumericExpression)
Returns sine of an angle given in radians
SPACE$ Windows Unix SPACE$(Num)
Returns string with Num spaces
SQR Windows Unix SQR(NumericExpression)
Returns the square root of NumericExpression, make sure it's non-negative
STR$ Windows Unix STR$(NumericExpression)
Returns the string representation of the numeric expression
STRF$ Windows STRF$(NumericExpression, Format%, Precision%, Digits%)
Converts a floating point or number value to a string
STRING$ Windows Unix STRING$(m, n) or STRING$(m, StringExpression)
Returns a string m characters wide that only contains CHR$(n) character
SWAP Windows Unix SWAP A, B
Exchanges values, so A = B and B = A
TALLY Windows Unix TALLY(SearchString, MatchString)
Returns the number of occurrences of matchstring
TAN Windows Unix TAN(NumericExpression)
Returns tangent of an angle given in radians
TIME$ Windows Unix TIME$
Returns the current time in HH:MM:SS format.
TIMER Windows Unix T! = TIMER
Returns the current TIMER value
UBOUND Windows Unix UBOUND(ArrayName[, Dimension])
Returns the upperbound of array (Dimension starts at 1)
UCASE$ Windows Unix UCASE$(StringExpression)
Returns a string whose characters have been uppercased
VAL Windows Unix VAL(StringExpression)
Returns the closest numeric representation of the string expression
VARPTR Windows Unix VARPTR(variablename)
Returns the address of a variable.
VARPTR$ Windows Unix VARPTR$(address)
Returns the null-terminated string representation of a given address.


Appendix C: Other Detailed Keywords

Rapid-Q Documentation by William Yu (c)1999-2000 Appendix C: Other Detailed Keywords

Other Detailed Keywords

Most of these have the same functionality as QBasic, so you could just as easily look them up there. Again, when I refer to Unix, I mean Linux & Unix.

ABS | MATH Function | Windows/Unix
A math function that returns the absolute value of a numeric expression.

Syntax: ABS(numeric-expression)
A% = ABS(-123)

Details:
The absolute value of function returns the unsigned magnitude of its argument. So, ABS(-1) and ABS(1) are both 1.

ACOS | MATH Function | Windows/Unix
A math function that returns the arccosine of a numeric expression.

Syntax: ACOS(numeric-expression)
D# = ACOS(0.55)

Details:
Numeric-expression is in the range -1 to 1.

ASC | STRING Function | Windows/Unix
A string processing function that returns a numeric value that is the ASCII code for the first character in a string expression.

Syntax: ASC(string-expression)
A% = ASC("A")

APPLICATION.ICON | RAPID-Q Specific | Windows
This is a Rapid-Q specific statement which can be used to assign an icon to the entire application (ie. all forms). It can also be used as a function in which case it returns the icon handle.

Syntax: APPLICATION.ICON
APPLICATION.ICON = "myicon.ico"
IcoHandle% = APPLICATION.ICON

APPLICATION.MINIMIZE | RAPID-Q Specific | Windows
Application.Minimize will minimize your application.

Syntax: APPLICATION.MINIMIZE
APPLICATION.MINIMIZE

APPLICATION.TERIMINATE | RAPID-Q Specific | Windows/Unix
Application.Terminate will ungracefully terminate your application. In most cases you won't need to call this function, but it will terminate your GUI application when it is called. For console applications, you can use the END statement instead.

Syntax: APPLICATION.TERMINATE
APPLICATION.TERMINATE

APPLICATION.TITLE | RAPID-Q Specific | Windows
Application.Title will set/get the application name of your program. This title is displayed on your task bar as well as any ShowMessage dialogs. The default application title is your executable name.

Syntax: APPLICATION.TITLE
APPLICATION.TITLE = "My application"

ASIN | MATH Function | Windows/Unix
A math function that returns the arcsine of a numeric expression.

Syntax: ASIN(numeric-expression)
D# = ASIN(0.55)

Details:
Numeric-expression is in the range -1 to 1.

ATN/ATAN | MATH Function | Windows/Unix
A math function that returns the arctangent of a numeric expression.

Syntax: ATN(numeric-expression)
D# = ATN(0.9)

Details:
Numeric-expression is the angle expressed in radians.

BIN$ | CONVERSION Function | Windows/Unix
A binary conversion function which will convert any positive INTEGER number to its binary representation.

Syntax: BIN$(numeric-expression)
S$ = BIN$(123)

Details:
Negative numbers are not supported, and so results are not defined.

BIND | POINTER Function | Windows/Unix
BIND will bind a variable as a function pointer.

Syntax: BIND variable TO function
DECLARE SUB MyFunc(X AS INTEGER)
BIND A% TO MyFunc

Details:
To invoke this function pointer, use CALLFUNC.

CALLFUNC | POINTER Function | Windows/Unix
CALLFUNC will execute the function pointer that was bound by using BIND.

Syntax: CALLFUNC(fptr, param1, param2, ...)
CALLFUNC(FPtr, 10, 20)
PRINT CALLFUNC(FPtr2, 10, 20)

Details:
Depending on how you BIND your function pointer, you can either call CALLFUNC as a statement or a function. Make sure to supply the necessary number of parameters, else you will receive a compile error. Passing function pointers as parameters is not yet implemented, but you can read up on Chapter 11 to see how to emulate this.

CHDIR | SYSTEM Statement | Windows/Unix
CHDIR will change the current working directory for your application.

Syntax: CHDIR string-expression
CHDIR "c:\windows"

CHR$ | STRING Function | Windows/Unix
A string processing function that returns a one-character string whose ASCII code is the argument.

Syntax: CHR$(numeric-expression)
A$ = CHR$(66)

Details:
Numeric-expression should be in the range 0-255.

CINT | CONVERSION Function | Windows/Unix
A conversion function that converts a numeric expression to an integer by rounding the fractional part of the expression.

Syntax: CINT(numeric-expression)
A% = CINT(66.7)

Details:
Implemented for compatibility with QBasic, you can use the more logical function, ROUND, instead.

CLNG | CONVERSION Function | Windows/Unix
A conversion function that converts a numeric expression to an integer by rounding the fractional part of the expression.

Syntax: CLNG(numeric-expression)
A% = CLNG(66.7)

Details:
Implemented for compatibility with QBasic, you can use the more logical function, ROUND, instead.

CONST | Statement | Windows/Unix
A non-executable statement that declares symbolic constants to use in place of numeric or string values.

Syntax: CONST constantname = expression
CONST False = 0
CONST A$ = "Hi world!"
CONST Char = CHR$(66)
CONST Combine = A$ + Char

Details:
Expression can be any value, numeric or string. Rapid-Q will decipher what the constant value will be bound to (ie. a string or a numeric variable) if the constantname is not followed by a type-declaration character (%. &, !, #, $, etc...).

CONVBASE$ | CONVERSION Function | Windows/Unix
A conversion function which takes the string expression represented in a specified base to be converted to another specified base determined by the arguments passed.

Syntax: CONVBASE$(string-expression, frombase, tobase)
S$ = CONVBASE$("FFD", 16, 2) '-- Convert from base 16 to 2
S$ = CONVBASE$("287", 10, 16) '-- Convert from base 10 to 16

Details:
Negative numbers are not supported.

COS | MATH Function | Windows/Unix
A math function that returns the cosine of an angle given in radians.

Syntax: COS(numeric-expression)
PI = 3.14153
C# = COS(PI)

Details:
Numeric-expression is the angle expressed in radians.

DATA | Statement | Windows/Unix
A non-executable statement that stores the numeric and string constants used by a program's READ statements.

Syntax: DATA {constant|EXECUTE(...)}[,...]
DATA my dog ate my homework, "oh, boy!", 34.4
DATA EXECUTE(LEFT$("Hello", 2, 3))

Details:
Constant is any valid numeric or string constant. If a string constant contains commas, colons, or leading or trailing spaces you want to preserve in your program, you must enclose the string in double quotes. You can also execute code by using the EXECUTE keyword. The return value of this executed code will be the value returned to your READ statement.

DATE$ | SYSTEM Function | Windows/Unix
A function that returns a string containing the current date formatted as MM-DD-YYYY. Where MM = month (1-12), DD = day (1-31) and YY = year (1980-2099)

Syntax: DATE$
PRINT DATE$

Details:
Unlike QBasic where you can set the current date using the DATE$ statement, you cannot do this under Rapid-Q.

DEC | Statement | Windows/Unix
Decrements numeric variable by one, or by the amount specified.

Syntax: DEC(variable [, amount])
DEC(I)
DEC(I, 10)

DEF... | Statement | Windows/Unix
DEFBYTE, DEFDBL, DEFDWORD, DEFINT, DEFLNG, DEFSHORT, DEFSNG, DEFSTR, DEFWORD are declaration statement that names one or more variables and allocates storage space for them.

Syntax: DEFINT variable[(subscripts)] [, ...]
DEFSTR A, B, C="Hello", D, E
DEFINT I=99, J(100,10), K

Details:
You cannot specify a range of variables, for example: DEFINT A-Z works fine under QBasic, but not Rapid-Q. You can initialize each variable as demonstrated above. DEF... statements are equivalent to calling DIM, but can save you a lot of typing. To initialize an array, wrap the values around curly braces {...}. For Example,
DEFINT A(1 TO 10) = {1,2,3,4,5,6,7,8,9,10}
Initializes elements 1 through 10 with the values 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10 respectively.

DELETE$ | STRING Function | Windows/Unix
A function that deletes part of a string.

Syntax: DELETE$(string-expression, start, length)
A$ = DELETE$("Hello world", 2, 3) '-- Result: Ho world

DIM | Statement | Windows/Unix
Declaration statement that names one or more variables and allocates storage space for them.

Syntax: DIM variable[(subscripts)] AS type
DIM A AS INTEGER, B(2,5,3,9,2) AS INTEGER
DIM S AS STRING
DIM Form AS QFORM

Details:
Use the optional (subscripts) to declare the size of arrays, up to 5 dimensions.

DIR$ | SYSTEM Function | Windows
A system function used to obtain the first/next file corresponding to a specified filespec.

Syntax: DIR$[(file-spec, attribute)]
FileName$ = DIR$("*.*", 0) '-- Get first file
FileName$ = DIR$ '-- Get next file

Details:
File-spec specifies a filename or path (which can include wildcards characters). Calling DIR$ with no parameters return additional filename matches. If no matches exist (or all matches have been exhausted), DIR$ returns an empty string. DIR$ returns all regular files as well as any special files specified in the attribute parameter.
Here are some valid file attributes, you can combine
them by using OR (ie. faReadOnly OR faDirectory)

&H1 = faReadOnly       &H8 = faVolumeID
&H2 = faHidden        &H10 = faDirectory
&H4 = faSysFile       &H20 = faArchive
                      &H3F = faAnyFile
To obtain additional information on the currently matched file, use the FileRec properties.
FileRec.FileName    - Returns Windows long file name
FileRec.ShortName   - Returns the short file name
FileRec.Date        - Returns the file date as a string
FileRec.Time        - Returns the file time as a string
FileRec.Size        - Returns the file size
FileRec.FileTime    - Returns the file time as an integer
You can use FileRec.FileTime to compare file times. So a newer file will have a FileTime greater than an older file.

DIREXISTS | SYSTEM Function | Windows
A function that returns 0 if directory does not exist, non-zero otherwise.

Syntax: DIREXISTS(string-expression)
A = DIREXISTS("c:\windows")

DOEVENTS | RAPID-Q Specific | Windows
Returns control to the operating system to process the events in its queue, and returns back control to the program once done.

Syntax: DOEVENTS
DO
DOEVENTS
LOOP

Details:
DoEvents should normally be used for long-running processes (ie. long loops or anything else that eats up the CPU), so that the user can abort the process if necessary. DoEvents can also be used to handle multiple forms.

END | Statement | Windows/Unix
Terminates program as long as there are no windows still open.

Syntax: END
END

Details:
Call END to terminate your application, but if there are any Windows still opened, you have to close them first or use Application.Terminate instead.

ENVIRON | SYSTEM Statement | Windows/Unix
A statement used to set or modify an environment variable.

Syntax: ENVIRON string-expression
ENVIRON "PATH=c:\windows"
ENVIRON "TEST what"

Details:
String-expression must have the form
parametername=text
or
parametername text
Everything to the left of the equal sign or space is assumed to be a parameter, and everything to the right, text. If the parametername has not previously existed in the environment string table, it is appended to the end of the table. If a pametername already exists, it gets deleted and the new parametername is appended to the end of the table.

ENVIRON$ | SYSTEM Function | Windows/Unix
A function that returns an environment string.

Syntax: ENVIRON$(environment-string)
A$ = ENVIRON$("PATH")

Details:
It is not possible, at this time, to retrieve an environment string by its index.

EXP | MATH Function | Windows/Unix
A math function that returns the exponential function (e raised to the power of n).

Syntax: EXP(numeric-expression)
A# = EXP(1)

EXTRACTRESOURCE | RESOURCE Statement | Windows/Unix
A statement that extracts a resource, from the current program, to a file.

Syntax: EXTRACTRESOURCE resource-value, filename
EXTRACTRESOURCE Resource(0), "test.bmp"

Details:
The resource-value is the absolute position of the resource within the current program. To find the absolute position of the resource, see also RESOURCE(), and RESOURCECOUNT.

FIELD$ | STRING Function | Windows/Unix
A function that returns a field (or token) separated by deliminators.

Syntax: FIELD$(Source-string, deliminator-string, field-number)
A$ = FIELD$("John&Doe&555-1234", "&", 2) '-- Returns Doe
A$ = FIELD$("John&&Doe&&555-1234", "&&", 3) '-- Returns 555-1234

FILEEXISTS | SYSTEM Function | Windows/Unix
A function that returns 0 if file does not exist, non-zero otherwise. The current working directory is searched for the file if no path is specified.

Syntax: FILEEXISTS(string-expression)
A = FILEEXISTS("rapidq.exe")

FIX | MATH Function | Windows/Unix
A function that removes the fractional part of a number.

Syntax: FIX(numeric-expression)
A% = FIX(342.97)

FORMAT$ | STRING Function | Windows
A function that returns a formatted string assembled from a Pascal style format string and a series of arguments. The Pascal style format string closely resembles C style format strings, but definitely not VB compatible.

Syntax: FORMAT$(Format-string, arg1, arg2, ...)
A$ = FORMAT$("Location: %s %4d %-10.4g", "Any", 1234, 55.39) '-- Returns Location: Any 1234 55.39
Details:
Format strings passed to the string formatting routines contain two types of objects--plain characters and format specifiers. Plain characters are copied verbatim to the resulting string. Format specifiers fetch arguments from the argument list and apply formatting to them. Format specifiers have the following form:
"%" [index ":"] ["-"] [width] ["." prec] type
A format specifier begins with a % character. After the % come the following, in this order:
An optional argument index specifier, [index ":"]
An optional left justification indicator, ["-"]
An optional width specifier, [width]
An optional precision specifier, ["." prec]
The conversion type character, type
The following table summarizes the possible values for type:
d | Decimal. The argument should be an integer value. The value is converted to a string of decimal digits. If the format string contains a precision specifier, it indicates that the resulting string must contain at least the specified number of digits; if the value has less digits, the resulting string is left-padded with zeros.
e | Scientific. The argument should be a floating-point value. The value is converted to a string of the form "-d.ddd...E+ddd". The resulting string starts with a minus sign if the number is negative. One digit always precedes the decimal point. The total number of digits in the resulting string (including the one before the decimal point) is given by the precision specifier in the format string--a default precision of 15 is assumed if no precision specifier is present. The "E" exponent character in the resulting string is always followed by a plus or minus sign and at least three digits.
f | Fixed. The argument should be a floating-point value. The value is converted to a string of the form "-ddd.ddd...". The resulting string starts with a minus sign if the number is negative. The number of digits after the decimal point is given by the precision specifier in the format string--a default of 2 decimal digits is assumed if no precision specifier is present.
g | General. The argument should be a floating-point value. The value is converted to the shortest possible decimal string using fixed or scientific format. The number of significant digits in the resulting string is given by the precision specifier in the format string--a default precision of 15 is assumed if no precision specifier is present. Trailing zeros are removed from the resulting string, and a decimal point appears only if necessary. The resulting string uses fixed point format if the number of digits to the left of the decimal point in the value is less than or equal to the specified precision, and if the value is greater than or equal to 0.00001. Otherwise the resulting string uses scientific format.
n | Number. The argument should be a floating-point value. The value is converted to a string of the form "-d,ddd,ddd.ddd...". The "n" format corresponds to the "f" format, except that the resulting string contains thousand separators.
m | Money. The argument should be a floating-point value. The value is converted to a string that represents a currency amount.
s | String. The argument must be a string. The string or character is inserted in place of the format specifier. The precision specifier, if present in the format string, specifies the maximum length of the resulting string. If the argument is a string that is longer than this maximum, the string is truncated.
x | Hexadecimal. The argument should be an integer value. The value is converted to a string of hexadecimal digits. If the format string contains a precision specifier, it indicates that the resulting string must contain at least the specified number of digits; if the value has fewer digits, the resulting string is left-padded with zeros.

Conversion characters may be specified in uppercase as well as in lowercase--both produce the same results.
An index specifier sets the current argument list index to the specified value. The index of the first argument in the argument list is 0. Using index specifiers, it is possible to format the same argument multiple times. For example Format$("%d %d %0:d %d", 10, 20) produces the string "10 20 10 20".

FRAC | MATH Function | Windows/Unix
A function that returns the fractional part of a number.

Syntax: FRAC(numeric-expression)
A# = FRAC(342.97)

HEX$ | CONVERSION Function | Windows/Unix
A function that returns the hexidecimal (base 16) representation of the (base 10) numeric expression.

Syntax: HEX$(numeric-expression)
A$ = HEX$(123)

Details:
Negative numbers are supported. In the Windows version, the string is pre-padded with 0's to fit the string length of 8.

IIF | Function | Windows/Unix
The immediate IF function returns one of two parts depending on the evaluation of an expression. Notice that both parts are evaluated, whether the expression returned true or false, so watch for undesirable side effects.

Syntax: IIF(expression, true-expr, false-expr)
A$ = IIF(6 > 5, "TRUE", "FALSE") '-- returns TRUE

INC | Statement | Windows/Unix
Increments numeric variable by one, or by the amount specified.

Syntax: INC(variable [, amount])
INC(I)
INC(I, 10)

INP | I/O Function | Windows/Unix
A device I/O function that returns the byte value read from an I/O port.

Syntax: INP(port)
A% = INP(&H3C9)

Details:
Port is any word value between 0 and 65535.

INSERT$ | STRING Function | Windows/Unix
A function that returns a string with an inserted substring beginning at a specified index.

Syntax: INSERT$(insert-string, source-string, index-number)
A$ = INSERT$("hi", "Hello", 3) '-- returns Hehillo

INSTR | STRING Function | Windows/Unix
A function that compares 2 strings and returns the position of the find-string with respect to the search-string. If found, INSTR returns the index position of the find-string, 0 otherwise.

Syntax: INSTR([start,] search-string, find-string)
A% = INSTR("Hello", "ll") '-- returns 3
A% = INSTR(4, "hehe they", "he") '-- returns 7

INT | MATH Function | Windows/Unix
A function that returns the largest integer less than or equal to a numeric-expression. Fractional part is truncated.

Syntax: INT(numeric-expression)
A& = INT(342.97)

KILL | SYSTEM Statement | Windows/Unix
A statement that removes a disk file.

Syntax: KILL filespec
KILL "mydocuments.txt"
KILL "*.c"

LCASE$ | STRING Function | Windows/Unix
A string function that returns a string expression with all letters lower-case.

Syntax: LCASE$(string-expression)
A$ = LCASE$("HELLO") '-- returns hello

LEFT$ | STRING Function | Windows/Unix
A string function that returns a string consisting of the leftmost n characters of a string.

Syntax: LEFT$(string-expression, n)
A$ = LEFT$("Hello",2) '-- returns he

LEN | STRING Function | Windows/Unix
A function that returns the number of characters in a string.

Syntax: LEN(string-expression)
A% = LEN("HELLO") '-- returns 5

Details:
LEN will not return the number of bytes required by a variable. This option is available under QBasic.

LOG | MATH Function | Windows/Unix
A math function that returns the natural logarithm of a numeric expression.

Syntax: LOG(numeric-expression)
A# = LOG(10)

LBOUND | ARRAY Function | Windows/Unix
A function that returns the lower bound of the array.

Syntax: LBOUND(arrayname [,dimension])
DIM A(-50 TO 100) AS INTEGER
L% = LBOUND(A) '-- Returns -50

Details:
If the array has multiple dimensions, you can use the optional dimension argument to check the lower bound of each one.

LFLUSH | PRINTER Statement | Windows
A statement used to begin a print job.

Syntax: LFLUSH
LPRINT "print this line"
LFLUSH '-- call this to start printing

Details:
You should call LFLUSH after you're satisfied that you want to start printing. If you don't call LFLUSH, then whenever your application terminates is when your document will start its print job.

LPRINT | PRINTER Statement | Windows
A statement just like PRINT except all output is directed to the default printer. Make sure to call LFLUSH to start the print job.

Syntax: LPRINT [expressions][{;|,}][...]
LPRINT "print this line"
LFLUSH

Details:
You should call LFLUSH after you're satisfied that you want to start printing. If you don't call LFLUSH, then whenever your application terminates is when your document will start its print job.

LTRIM$ | STRING Function | Windows/Unix
A string function that returns a string with leading spaces removed.

Syntax: LTRIM$(string-expression)
A$ = LTRIM$(" Hello") '-- returns Hello

MESSAGEDLG | RAPID-Q Specific | Windows
Displays a message box with an icon and a user defined caption.

Syntax: MESSAGEDLG(string-expression, msgType, msgButtons, helpContext)
IF MessageDlg("Close this form?", mtWarning, mbYes OR mbNo, 0) = mrNo THEN
'-- Don't close form
END IF

Details:
msgType is used to display the type of icon that will be displayed in your message box.
0 = mtWarning      3 = mtConfirmation
1 = mtError        4 = mtCustom
2 = mtInformation
msgButtons is used to display custom dialog buttons. To display more than one message button, just OR them.
1 = mbYes       32 = mbAbort
2 = mbNo        64 = mbRetry
4 = mbOK       128 = mbIgnore
8 = mbCancel   256 = mbAll
16 = mbHelp
helpContext is ignored for now.

MID$ | STRING Function | Windows/Unix
A string function that returns a string with chracters i to n of string-expression.

Syntax: MID$(string-expression, i, n)
A$ = MID$("Hello",3,2) '-- returns ll

Details:
You cannot use MID$ in this way:
MID$(A$, 1, 1) = "G"
Under QBasic, this valid statement replaces the first character from A$ with "G". To acheive the same effect under Rapid-Q, please use the REPLACE$ string function.

MKDIR | SYSTEM Statement | Windows/Unix
A statement that creates a new directory.

Syntax: MKDIR pathspec
MKDIR "abc"

Details:
MKDIR will not rewrite a directory if one already exists, if no path is specified, the directory is created in the current working directory.

OUT | I/O Statement | Windows/Unix
A device I/O statement that sends a byte value to a machine I/O port.

Syntax: OUT port, value
OUT &H3C9, 128

Details:
  • Port is any word value between 0 and 65535.
  • Value is any byte value between 0 and 255.

    • PLAYWAV | RAPID-Q Specific | Windows
    Plays a .wav file.

    Syntax: PLAYWAV wavfilename, sndOptions
    PLAYWAV "welcome.wav", SND_ASYNC OR SND_LOOP

    Details:
    sndOptions determine how the wav file is played back.
    0 = SND_SYNC     '-- waits for wav to finish
1 = SND_ASYNC    '-- background play
3 = SND_LOOP     '-- Loop wav once finished playing
    You can combine SYNC or ASYNC with LOOP by OR'ing them. If your WAV file is not finished playing when you close your application, you will receive an access violation.

    POSTMESSAGE | RAPID-Q Specific | Windows
    A WinAPI call to PostMessage, does not block.

    Syntax: POSTMESSAGE hWnd, uMsg, wParam, lParam
    POSTMESSAGE Form.Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0

    Details:
    PostMessage is a WinAPI call so instead of filling this entire page with information you can look up this function in your WinAPI manual/help file.

    QUICKSORT | SORTING Statement | Windows/Unix
    QUICKSORT, aptly named, can be used to sort your arrays of any type, except Objects/UDTs of course. It, obviously, uses the QuickSort algorithm to perform the sort.

    Syntax: QUICKSORT(Array-begin, Array-end, ASCEND|DESCEND)
    DIM A(1000) AS INTEGER
    '-- put stuff in A
    QUICKSORT(A(10), A(500), ASCEND) '-- sorts elements 10..500

    Details:
    The pivot element in the above example is A(10), so if you want randomness, you'll have to replace A(10) with some random element from A(10)..A(500) in the above example. You can also sort multi-dimensional arrays and "span sort" arrays.

    Span sorting:
               DIM A(1 TO 100) AS LONG
           DIM B(1 TO 100) AS LONG
           DIM C(1 TO 100) AS LONG

           '--- puts some values into array A, B, C
           RANDOMIZE TIMER
           FOR I = 1 TO 100
               A(I) = RND(50000)
               B(I) = RND(50000)
               C(I) = RND(50000)
           NEXT

           QUICKSORT A(1), C(100), ASCEND
           PRINT A(1)," ",B(1)," ",C(1)
    As long as you DIM the arrays "side by side" they will share a contiguous space of memory, this means you can sort from the start of memory address A(1) to the end of memory address C(100). This technique is not recommended, but if you can find a use for it, go ahead.

    RANDOMIZE | MATH Statement | Windows/Unix
    Initializes (reseeds) the random-number generator.

    Syntax: RANDOMIZE [numeric-expression]
    RANDOMIZE TIMER

    Details:
    If argument is omitted, randomize will default as RANDOMIZE TIMER.

    READ | Statement | Windows/Unix
    A statement that reads values from a DATA statement and assigns the values to variables.

    Syntax: READ variablelist
    READ A%, S$, P(1,2)

    Details:
    Variablelist is made up of one or more variables, separated by commas, which are to receive the data. The variables may be string or numeric.

    REDIM | Statement | Windows/Unix
    Declaration statement that changes the space allocated to an array that has already been declared by DIM, preserving as much of the data as possible.

    Syntax: REDIM variable[(subscripts)] AS type
    DIM B(20) AS INTEGER
    REDIM B(100) AS INTEGER

    Details:
    If the array has not yet been declared by DIM, REDIM will be equivalent to calling DIM. You cannot change the data type for the array, ie. you cannot redefine array B to be something other than an INTEGER (as in the above example). Combining arrays is a by-product of REDIM.
    DIM A(100) AS INTEGER
DIM B(100) AS INTEGER
REDIM A(200) AS INTEGER   '-- Combines A and B together
    What the above code does is preserve the data in A as well as combining the array B. so index from 100 to 200 is the data for B and 0 to 100 is the data for A. Clarification: Array B has not been modified, it still maintains its own address space and will not overwrite A's data and vice versa.

    REM | Comment | Windows/Unix
    A BASIC declaration that allows explanatory remarks to be inserted in a program. It's suggested that you use ' to start your comments instead.

    Syntax: REM remark
    REM This is a comment, nothing is executed
    ' This is another comment

    RENAME | SYSTEM Statement | Windows/Unix
    A statement that renames a file. If file already exists the operation is not executed.

    Syntax: RENAME file1, file2
    RENAME "abc.txt", "xyz.txt"

    REPLACE$ | STRING Function | Windows/Unix
    A function that replaces a portion of a string with another.

    Syntax: REPLACE$(source-string, replace-string, index)
    A$ = REPLACE$("Hello", "J", 1) '-- returns Jello

    REPLACESUBSTR$ | STRING Function | Windows/Unix
    A function that replaces a substring with another string. All occurrences will be replaced. The length of the replacement string does not need to match the length of the replaced string.

    Syntax: REPLACESUBSTR$(source-string, replace-string, replacement-string)
    A$ = REPLACESUBSTR$("abcdefgabcdefg", "abc", "99") '-- returns 99defg99defg

    RESOURCE | RESOURCE Function | Windows/Unix
    A function that returns the absolute position of the resource from the current program.

    Syntax: RESOURCE(numeric-expression)
    EXTRACTRESOURCE Resource(0), "test.bmp"

    Details:
    RESOURCE() is an array consisting of 0 to RESOURCECOUNT-1 elements. Element 0 corresponds to the first $RESOURCE handle you specify and so on. If numeric-expression is not in the range 0 to RESOURCECOUNT-1, this function returns 0.

    RESOURCECOUNT | RESOURCE Function | Windows/Unix
    A function that returns the number of resources in the current program.

    Syntax: RESOURCECOUNT
    A% = RESOURCECOUNT

    RESTORE | Statement | Windows/Unix
    A statement that allows DATA statements to be reread from a specified line.

    Syntax: RESTORE [{linelabel | linenumber}]
    RESTORE

    Details:
    If the argument is omitted, the next READ statement which executes will read the first item in the first DATA statement in the program. Linelabel or Linenumber identifies the DATA statement you want the next READ statement to use. The first item from that line will be read.

    REVERSE$ | STRING Function | Windows/Unix
    A function that reverses (or mirrors) a string.

    Syntax: REVERSE$(string-expression)
    A$ = REVERSE$("Hello") '-- returns olleH

    RGB | CONVERSION Function | Windows/Unix
    A conversion function that takes the red, green and blue parameters and combines them to form a BGR numeric representation.

    Syntax: RGB(redvalue, greenvalue, bluevalue)
    C = RGB(255, 0, 255)

    Details:
    Values range from 0-255. Values outside this range produce undefined results.

    RIGHT$ | STRING Function | Windows/Unix
    A function that returns the rightmost n characters of a string.

    Syntax: RIGHT$(string-expression, n)
    A$ = RIGHT$("Hello", 3) '-- returns llo

    RINSTR | STRING Function | Windows/Unix
    Reverse INSTR is a function that compares 2 strings and returns the position of the find-string with respect to the search-string. Instead of starting the search from left to right, like INSTR, RINSTR searches right to left (ie. the reverse of INSTR). If found, RINSTR returns the index position of the find-string, 0 otherwise.

    Syntax: RINSTR([start,] search-string, find-string)
    A% = RINSTR("Hello World", "l") '-- returns 10
    A% = RINSTR(4, "hehe they", "he") '-- returns 3

    RMDIR | SYSTEM Statement | Windows/Unix
    A statement that removes a directory.

    Syntax: RMDIR directory
    RMDIR "abc"

    RND | MATH Function | Windows/Unix
    A function that returns a random number whose sequence is generated by calling RANDOMIZE.

    Syntax: RND[(upper-bound)]
    A% = RND(10)

    Details:
    If no upper-bound is given, RND returns a decimal number in the range 0 to 1.

    ROUND | MATH Function | Windows/Unix
    A math function that converts a number to an integer by rounding the fractional part of the expression.

    Syntax: ROUND(numeric-expression)
    A% = ROUND(3.5) '-- Returns 3
    A% = ROUND(3.51) '-- Returns 4

    RTRIM$ | STRING Function | Windows/Unix
    A string function that returns a string with trailing spaces removed.

    Syntax: RTRIM$(string-expression)
    A$ = RTRIM$("Hello ") '-- returns Hello

    RUN | SYSTEM Statement | Windows/Unix
    A statement that executes a specified program without blocking.

    Syntax: RUN filespec
    RUN "rapidq.exe"

    SENDMESSAGE | RAPID-Q Specific | Windows
    A WinAPI call to SendMessage, blocks until message is processed.

    Syntax: SENDMESSAGE hWnd, uMsg, wParam, lParam
    SENDMESSAGE Form.Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0

    Details:
    SendMessage is a WinAPI call so instead of filling this entire page with information you can look up this function in your WinAPI manual/help file.

    SGN | MATH Function | Windows/Unix
    A math function that indicates the sign of a numeric expression.

    Syntax: SGN(numeric-expression)
    A% = SGN(-123) '-- Returns -1

    Details:
    If numeric-expression is positive, SGN returns +1.
    If numeric-expression is zero, SGN returns 0.
    If numeric-expression is negative, SGN returns -1.

    SHELL | SYSTEM Statement/Function | Windows
    SHELL can be called as a statement or as a function. It has the same functionality as RUN except that it blocks your application until the executed one has ended.

    Syntax: SHELL command
    SHELL "rapidq.exe"
    Syntax: SHELL(command, showCMD)
    PID = SHELL("rapidq.exe", SW_SHOWNORMAL)

    Details:
    If calling SHELL as a function, the return value is the process ID of the executed program, and will not block your program. showCMD can be any of the following:
    0 = SW_HIDE              6 = SW_MINIMIZE
1 = SW_SHOWNORMAL        7 = SW_SHOWMINNOACTIVE
2 = SW_SHOWMINIMIZED     8 = SW_SHOWNA
3 = SW_SHOWMAXIMIZED     9 = SW_RESTORE
4 = SW_SHOWNOACTIVATE   10 = SW_SHOWDEFAULT
5 = SW_SHOW

    SHOWMESSAGE | RAPID-Q Specific | Windows/Unix
    A statement used to display a generic popup message box.

    Syntax: SHOWMESSAGE string-expression
    SHOWMESSAGE "Hello world!"

    SIN | MATH Function | Windows/Unix
    A math function that returns the sine of an angle given in radians.

    Syntax: SIN(numeric-expression)
    PI = 3.14153
    C# = SIN(PI)

    Details:
    Numeric-expression is the angle expressed in radians.

    SIZEOF | MEMORY Function | Windows/Unix
    A function that returns the size, in bytes, of a data type.

    Syntax: SIZEOF(datatype)
    PRINT SIZEOF(MyUDT)
    PRINT SIZEOF(INTEGER)

    Details:
    To calculate the size of a UDT, you must first DIM it.
    ie. DIM MyUDT AS TMyUDT

    SPACE$ | STRING Function | Windows/Unix
    A string function that returns a string of spaces of length n.

    Syntax: SPACE$(n)
    A$ = SPACE$(5)

    SQR | MATH Function | Windows/Unix
    A math function that returns the square root of a number.

    Syntax: SQR(numeric-expression)
    A# = SQR(9) '-- returns 3

    STR$ | CONVERSION Function | Windows/Unix
    A conversion function that returns a string representation of the value of a numeric expression.

    Syntax: STR$(numeric-expression)
    A$ = STR$(99)

    STRF$ | CONVERSION Function | Windows
    A conversion function that returns a formatted string representation of the value of a numeric expression.

    Syntax: STRF$(numeric-expression, Format%, Precision%, Digits%)
    A$ = STRF$(99.9934, ffGeneral, 4, 4)
    A$ = STRF$(12345678, ffNumber, 8, 0)

    Details:
    Precision% specifies how many decimal places to calculate.
    The following are valid Formats:
    0 = ffGeneral      2 = ffFixed
1 = ffExponent     3 = ffNumber
    ffGeneral converts to the shortest possible decimal string, where trailing zeros are removed. Digits% range from values of 0 to 4.
    ffExponent converts to scientific notation of the form -d.ddd...E+dddd. Digits% range from values of 0 to 4.
    ffFixed converts to fixed point format of the form -ddd.ddd... Digits% range from values of 0 to 18.
    ffNumber converts to a number format of the form -d,ddd,ddd.ddd... Where the resulting string contains thousand separators.

    STRING$ | STRING Function | Windows/Unix
    A string function that returns a string whose characters all have a given ASCII code or whose characters are all the first character of a string expression.

    Syntax: STRING$(m, n)
    A$ = STRING$(9, 65) '-- Returns AAAAAAAAA
    Syntax: STRING$(m, string-expression)
    A$ = STRING$(9, "ABC") '-- Returns AAAAAAAAA

    SWAP | Statement | Windows/Unix
    An assignment statement that exchanges the values of 2 variables.

    Syntax: SWAP variable1, variable2
    SWAP A$, B$

    Details:
    Variable1 and variabl2 should be of the same type, but Rapid-Q won't complain.

    TALLY | STRING Function | Windows/Unix
    Tally counts the number of occurrences of MatchString within a SearchString.

    Syntax: TALLY(search-string, match-string)
    Count& = TALLY("abcdefghijklmnabc", "abc") '-- returns 2

    TAN | MATH Function | Windows/Unix
    A math function that returns the tangent of an angle given in radians.

    Syntax: TAN(numeric-expression)
    T# = TAN(90)

    Details:
    Numeric-expression is the angle expressed in radians.

    TIME$ | SYSTEM Function | Windows/Unix
    A function that returns a string containing the current time formatted as HH:MM:SS. Where HH = hour (0-23), MM = minute (0-59) and SS = seconds (0-59)

    Syntax: TIME$
    PRINT TIME$

    Details:
    Unlike QBasic where you can set the current date using the TIME$ statement, you cannot do this under Rapid-Q.

    TIMER | SYSTEM Function | Windows/Unix
    A function that returns the number of seconds elasped since midnight.

    Syntax: TIMER
    T! = TIMER

    Details:
    Timer value for Linux/Unix is the number of seconds elasped since your program started.

    UBOUND | ARRAY Function | Windows/Unix
    A function that returns the upper bound of the array.

    Syntax: UBOUND(arrayname [,dimension])
    DIM A(-50 TO 100) AS INTEGER
    L% = UBOUND(A) '-- Returns 100

    Details:
    If the array has multiple dimensions, you can use the optional dimension argument to check the upper bound of each one.

    UCASE$ | STRING Function | Windows/Unix
    A string function that returns a string expression with all letters upper-case.

    Syntax: UCASE$(string-expression)
    A$ = UCASE$("Hello") '-- returns HELLO

    VAL | CONVERSION Function | Windows/Unix
    A conversion function that returns a numeric representation of the string expression.

    Syntax: VAL(string-expression)
    A = VAL("995")

    VARPTR | ADDRESS Function | Windows/Unix
    A function that returns the address, ie. pointer to, of the given variable name. Variable must be a declared variable, ie. not a component variable such as QForm.Caption

    Syntax: VARPTR(variablename)
    Addr& = VARPTR(MyString$)
    Addr& = VARPTR(MyArray(0))

    Details:
    The variable can be an array, but with the Windows version VARPTR cannot handle string arrays.

    VARPTR$ | ADDRESS Function | Windows/Unix
    A function that returns the string representation of a given address.

    Syntax: VARPTR$(address)
    S$ = VARPTR$(279027343)


Appendix C: Trouble Shooting

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Trouble Shooting

How to debug your programs

In most cases, it's either a typo, or you're trying to use a function which is not supported under Rapid-Q. This occurs most often when you don't have $TYPECHECK ON. I can't stress this enough, unless you've used Rapid-Q for awhile, I strongly encourage everybody to turn this directive on. Rapid-Q has a very poor checking mechanism, and relies heavily on the programmer to write proper code. For Example:
    PRINT SPC(10)
SPC is not supported in Rapid-Q (in QBasic, SPC just skips spaces). If typechecking is off, the above statement is perfectly valid. SPC is a variable, initialized to 0, and (10) has no effect (ie. the number 10 is pushed on the stack, but no operation is done), so the above output will be 0.

Passing by reference
Only QObjects and Arrays are passed by reference, all other variables are passed by value. To pass a variable by reference, you can either explicitly specify this by adding BYREF to your parameter list, or prepend an @ symbol to any variables you want passed by reference when calling the function. Do not use the @ symbol for Array or QObjects since they are passed by reference by default. Read more about this in Chapter 3 or Appendix C: Procedures. Typechecking is done only for Arrays and QObjects, since you can't pass an array of integers to a SUB that expects an array of doubles. You should get an error message if you try this, however, for all other variables which are passed by value, NO checking is done. Which means you could easily pass an integer to a SUB expecting a string. So becareful that you know the type of parameters for your SUB/FUNCTION, since Rapid-Q won't complain. Also make sure if you have DECLARE SUBs, that your SUB will have matching parameters, including matching parameter names.

Using Undocumented features
Rapid-Q has some undocumented features, most of which are in a beta-like stage. You can embed SUBs or FUNCTIONs but they can only be one level deep, and there are some consequences with using them. If you don't know what an embedded SUB looks like, take this for example:
    SUB MySub
      DIM I AS INTEGER

      SUB MyChildSub (X AS INTEGER)
        DIM N AS DOUBLE

        PRINT "In Child Sub"
      END SUB

      CALL MyChildSub(100)
    END SUB
There are some special issues involved, such as all variables are local to the SUBs that follow. Meaning, the variable I is local to SUB MyChildSub. Also, since Rapid-Q doesn't actually clean things up, you can actually call MyChildSub in your main program as well. This is a problem I'm working to correct when I find the time. One other feature which might interest people is postfix ++ and --
    DIM I AS INTEGER

    I++           '-- same as I = I + 1
    I--           '-- same as I = I - 1
    I -= 10       '-- same as DEC(I, 10)
    I += 15       '-- same as INC(I, 15)
Arrays are a special case, anything but Arrays can be incremented/decremented. Rapid-Q doesn't do any optimizing, so the above code and the given translation runs exactly the same.

Other errors
If you don't have a clue as to what is causing your programs to crash, your only hope is to put several PRINT statements in your program and incrementally check each block of code so that it works properly. If you're using Unix or Linux, try using gdb, sometimes it will give you some useful information, but most of the time it's not really that helpful in this kind of setting.

Contents


Appendix C: Detailed Keyword List

Rapid-Q Documentation by William Yu (c)1999 Appendix C: Detailed Keyword List

Reserved Keywords

Most of these have the same functionality as QBasic, so you could just as easily look them up there. Again, when I refer to Unix, I mean Linux & Unix.

CLS | CONSOLE Statement | Windows/Unix
Clears console screen of all text, and fills the console with the currect background color. CLS also returns the cursor to the home position in the top left corner of the screen.

Syntax: CLS
CLS

Details:
Under Windows, CLS is a CONSOLE statement, under Linux/Unix, CLS is implemented as a system call to clear, so you can safely call CLS without compiling as CONSOLE under Linux/Unix.

COLOR | CONSOLE Statement | Windows/Unix
Sets the current display colors for the console screen.
  • Foreground is the text color (range = 0-31)
  • Background is the screen color (range = 0-7)
0 = black  4 = red       8 = grey        12 = light red
1 = blue   5 = magenta   9 = light blue  13 = light magenta
2 = green  6 = brown    10 = light green 14 = yellow
3 = cyan   7 = white    11 = light cyan  15 = bright white

Syntax: COLOR [foreground][,background]
COLOR 15
COLOR 10, 3
COLOR ,1
COLOR

CSRLIN | CONSOLE Function | Windows/Unix
Returns the current line (row) position of the cursor.

Syntax: CSRLIN
Row% = CSRLIN

INKEY$ | CONSOLE Function | Windows/Unix
Returns a one- or two-byte string containing a character read from standard input (console). An empty string is returned if no character is waiting there.

Syntax: INKEY$
A$ = INKEY$

Details:
Extended keys are not trapped under Windows. Extended keys under Linux/Unix start with CHR$(27) and LEN(A$) = 2. Extended keys are arrow keys, page up/down, home, end, insert, delete, and F1-F12 keys.

INPUT | CONSOLE Statement | Windows/Unix
Reads a whole line of input from the. This statement causes the program to pause and wait for data until a carriage return is pressed.

Syntax: INPUT ["Prompt string"{;|,}] string-variable
INPUT A$
INPUT "Enter name: "; A$

Details:
INPUT for Rapid-Q is not exactly compatible with QBasic's INPUT. It is more like LINE INPUT. The return variable must be a string variable. Under Windows, INPUT is implemented as a CONSOLE function. Under Linux/Unix INPUT is not considered a CONSOLE function so there's no need to compile as CONSOLE.

LOCATE | CONSOLE Statement | Windows/Unix
Moves cursor to specified position.

Syntax: LOCATE [row][,column]
LOCATE 10, 1
LOCATE ,10
LOCATE 5

Details:
Under Windows you can assume that Row 25 is the last row and Column 80 as the last column. Under Linux/Unix this is dependent on your terminal, but you can use the internal variables Screen.ConsoleX and Screen.ConsoleY to determine the max column and row respectively. The first row and first column always starts at (1,1).

PCOPY | CONSOLE Statement | Windows
Copies one screen page to another.

Syntax: PCOPY sourcepage, destinationpage
PCOPY 0, 1
PCOPY 1, 5

Details:
The visible (on-screen) page is always 0. There are 7 off-screen pages (1 to 7). You can copy from any page onto any other page.

PEEK | CONSOLE Function | Windows
Returns the current character/attribute pair stored at a specified location on the console screen.

Syntax: PEEK([#pagenum,] address)
A% = PEEK(2000) '-- Peek location 2000 on current page
A% = PEEK(1, 2000) '-- Peek location 2000 on page 1

Details:
To understand how to compute the address, use this handy function:
   Char$ = CHR$(PEEK((Row%-1)*160+(Col%-1)*2))
   Attr = PEEK((Row%-1)*160+(Col%-1)*2+1)
As you may notice, all the even memory addresses contain the character, and all the odd numbered addresses contain the attribute. The attribute contains information about the foreground and background color.
   ForeGround% = Attr AND &HF
   BackGround% = Attr SHR 4
Why all the trouble? This is implemented for compatibility with QBasic. The only difference is that you don't use DEF SEG under Rapid-Q, and PEEK only works at the console level.

POKE | CONSOLE Statement | Windows
Writes a byte to the console page.

Syntax: POKE [#pagenum,] address, byte
POKE 2000, ASC("A") '-- Pokes an "A" character at location 2000
POKE 2001, 95 '-- Pokes attribute 95 to location 2000
POKE 1, 2001, 95 '-- Same as above but pokes to page 1

Details:
To understand how to compute the address, use this handy function:
   ChAddress = (Row%-1)*160+(Col%-1)*2
   AttrAddress = (Row%-1)*160+(Col%-1)*2+1
As you may notice, all the even memory addresses contain the character, and all the odd numbered addresses contain the attribute. The attribute contains information about the foreground and background color. To calculate the attribute, try this:
   Attr = (BackGround% SHL 4) OR ForeGround%
Why all the trouble? This is implemented for compatibility with QBasic. The only difference is that you don't use DEF SEG under Rapid-Q, and POKE only works at the console level.

POS | CONSOLE Function | Windows/Unix
Returns the current horizontal (column) position of the cursor.

Syntax: POS(0)
Column% = POS(0)

Details:
Please note that I did not make this function up (ie. its weird syntax), it's implemented for compatibility with QBasic.

PRINT | CONSOLE Statement | Windows/Unix
PRINT outputs data to the screen (or standard output).

Syntax: PRINT [#pagenum,][expressions][{;|,}]
PRINT "Number: "; 45
PRINT A$
PRINT #1, "This prints to screen page 1"

Details:
Expressions can be any string, number, or function. You can optionally use ; or , to print out more expressions. Under QBasic, PRINT can format your data if you use the comma, however, under Rapid-Q the comma and semi-colon have the same effect. Again, under Windows, PRINT is implemented as a CONSOLE function. Under Linux/Unix you do not need to compile as CONSOLE.

SETCONSOLETITLE | CONSOLE Statement | Windows
SetConsoleTitle is implemented as a WinAPI call to SetConsoleTitle but is called as a statement rather than a function (ie. no return value). If you would like a return value, you'll have to call the API function directly.

Syntax: SETCONSOLETITLE string-expression
SETCONSOLETITLE "Hello World!"

SLEEP | CONSOLE Statement | Windows/Unix
Suspends execution of the application for a specified amount of time.

Syntax: SLEEP seconds
SLEEP .5 '-- Delay for half a second

Details:
SLEEP requires a parameter, unlike QBasic. SLEEP waits until the number of seconds specified has elasped. You cannot break out of it by pressing a key (unlike QBasic). Under Windows, SLEEP is implemented as a console function. Under Linux/Unix, you do not need to compile as CONSOLE.


Rapid-Q Documentation by William Yu

  • Rapid-Q is a multi-platform, multi-purpose BASIC compiler/interpreter.
  • Rapid-Q is created by William Yu
  • Rapid-Q is free for commercial or non-commercial use.
  • Rapid-Q comes with no warranties, or guarantees.
  • Rapid-Q is currently in a beta stage, but is fully functional.

Table of Contents