Rapid-Q Preface

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

A lot has changed since the initial release of Rapid-Q, but one thing that hasn't changed is the fact that Rapid-Q is constantly being upgraded almost daily. The overall goal still exists, to provide an alternative BASIC programming language that's not only FREE, but good and easy to use. Being a BASIC programmer at heart, I looked through the eyes of a user, and added the features and ease of use that I like to see in a good programming language. Some of the features you see are spawned in part by our excellent Rapid-Q user base. Requesting features is one way this project can succeed, since there are many out there that share the same vision. Perhaps in the future, some of these features will become standard in all BASIC languages. If you're familiar with either QBasic, PowerBasic, or even VisualBasic, you'll be able to program in Rapid-Q in no time. The advanced features that Rapid-Q offers need not be used at all, but is available when you get more comfortable with the language itself. For example, Rapid-Q offers object/component creation, function pointers, procedures with infinite parameters, variants, and overloaded macros, while still maintaining all the fundamental features that most BASIC programmers are familiar with, ie. GOTO, GOSUB, line numbers, etc... This makes converting legacy code much easier. The only feature which deviates from traditional BASIC languages is file handling. I believe that once you understand how file and memory streams work, this can be a huge benefit, rather than a hassle. For those who aren't aware, Rapid-Q is a 32-bit multiplatform GUI and CONSOLE BASIC compiler/interpreter for Windows, Linux, and Unix. Rapid-Q compiles your BASIC source code into byte-code, which is normally attached to an interpreter, but can also be run from other programming languages using specialized DLLs.

About this document
These chapters were written and rewritten as new features were added, which means that it's quite possible you'll find some inconsistent or obsolete comments and code. If you spot one of these, please send me an e-mail so I can remove/change it.

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. I'm also maintaining a knowledge base of some of the many questions that I've received from fellow Rapid-Q users. You can find a link to this on our homepage. Another site that I maintain is the All Basic Code Archives at http://www.basicguru.com/abc/ which consists of over 2600 BASIC source codes and hundreds of BASIC related resources.

Rapid-Q Audience
Being a BASIC programming language, I've targeted BASIC programmers, primarily beginner to intermediate BASIC programmers, but even advanced programmers have used Rapid-Q at some point. My future goal is to integrate Rapid-Q in a classroom, such as in junior/senior high school, or even in college.

The Future of Rapid-Q
Obviously expanding Rapid-Q by adding new features is something that will continue in the future, but I also plan on open sourcing Rapid-Q when I've done all I can. This of course can't be guaranteed, and there's no telling when this decision will be made. It's likely that the Linux/Unix version will be open source sooner than the Windows version.

Comments & Suggestions
I appreciate all comments, suggestions and constructive criticism. I would also like to extend thanks to all beta testers for their help and suggestions. The best way to voice your opinion is on our mailing list, this way we can all discuss the problem or suggestions that you may have. However, I don't discourage individual e-mails, so feel free to contact me and I'll try to get back to you ASAP.

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
      • $MACRO
      • $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 Accepting user input
    • 6.5 Trapping extended keys
    • 6.6 Mixing CONSOLE with GUI
    • 6.7 Linux/Unix console
    Chapter 7: Introduction to streams
    • 7.1 File streams
      • Reading/Writing numbers and strings
    • 7.2 Memory streams
      • Copying between streams
    • 7.3 Saving/Loading UDTs and Arrays
    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
    • 9.8 API conversion table
    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 Templates and property sets
    • 10.9 Creating custom events
    • 10.10 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
    Chapter 15: COM Programming
    • 15.1 Supported COM extensions
      • COM clients (automation controllers)
      • Active Documents
      • How to register COM objects
    • 15.2 About QOLEOBJECT
    • 15.3 About QOLECONTAINER
    Appendix A: Rapid-Q Component/Object Reference
    • APPLICATION (Windows/Linux)
      • Properties, Methods Application examples
    • 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
    • QOPENDIALOG (Windows/Linux)
      • Properties, Methods, QOpenDialog examples
    • QOLECONTAINER
      • Properties, Methods, QOleContainer examples
    • QOLEOBJECT
      • Properties, Methods, QOleObject 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 (Windows/Linux)
      • Properties, Methods, QStringList examples
    • QTABCONTROL
      • Properties, Methods, Events, QTabControl examples
    • QTIMER (Windows/Linux)
      • Properties, Events, QTimer examples
    • QTRACKBAR
      • Properties, Methods, Events, QTrackBar examples
    • QTREEVIEW
      • Properties, Methods, Events, QTreeView examples
    Appendix B: Rapid-Q DirectX Component/Object Reference
    • QDXIMAGELIST
      • Properties, Methods, Events, QDXImageList examples
    • QDXSCREEN
      • Properties, Methods, Events, QDXScreen examples
    • QDXSOUND
      • Properties, Methods QDXSound 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
    • Rapid-Q supported Data Types
      • BYTE, WORD, INTEGER, VARIANT, etc...
    • 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
      • Command$, CurDir$, 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-2000 Chapter 1

1. Rapid-Q Overview

Rapid-Q is a programming language, a BASIC programming language to be precise. It is multiplatform, although not completely compatible in terms of the graphical interface, but the underlying language is more or less compatible between platforms. Rapid-Q is available for Windows, Linux, and Unix (Solaris and HP-UX are supported). You can use Rapid-Q to create both GUI and CONSOLE applications, including CGI applications. Rapid-Q generates byte-code as opposed to the native opcode of your processor. This requires an interpreter to read and execute the byte-codes, however, this interpreter is embedded in all your applications, so no extra files are necessary when you distribute your executable. The biggest issue is speed, but depending on what you're using Rapid-Q for, this may not be a factor. Rapid-Q was originally created to provide a free implementation of a BASIC programming language for Windows.

1.1 How slow is Rapid-Q anyway?
Although Rapid-Q is based on compiling your sources to byte-code, execution isn't as slow as many think. Your programs will obviously slow down 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 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/her 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 200KB for virtual, global, and heap memory combined. This is because all variables and objects are created dynamically. The heap/stack 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 byte-code 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 byte-code 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 byte-code 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. The only agreement you have to worry about is that if you choose to use Rapid-Q, you assume any and all consequences, direct or indirectly from the use of Rapid-Q. 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.


Chapter 2: Rapid-Q Fundamentals

Rapid-Q Documentation by William Yu (c)1999-2000 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 an 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. If any of these files are missing, please report the problem to me or the webmaster of the site you downloaded Rapid-Q from. These are the main (4) programs that you will need to develop and compile your Rapid-Q source codes. The IDE is strictly optional, so if your distribution excludes this file, don't fret. 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 your program, your source code 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. 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-2000 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. Enclosing the filename between quotes will search for that file in the current directory, and specified include paths. Enclosing the filename between < and > will search for that file in the current directory, specified include paths and the environment search paths.
Usage:
    $INCLUDE "RAPIDQ.INC"
    $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. Enclosing the filename between quotes will search for that file in the current directory, and specified include paths. Enclosing the filename between < and > will search for that file in the current directory, specified include paths and the environment search paths.
Usage:
    $RESOURCE RES_BMP1 AS "CLOUDS.BMP"
    $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, BYTECODE, DECIMAL, DIM, EXPLICIT, GTK, ICON, INKEY$, and WEAKTYPE 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 BYTECODE
    Compile as byte code only.

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

    $OPTION DIM BYTE
    $OPTION DIM WORD
    $OPTION DIM DWORD
    $OPTION DIM SHORT
    $OPTION DIM INTEGER
    $OPTION DIM LONG
    $OPTION DIM SINGLE
    $OPTION DIM DOUBLE
    $OPTION DIM STRING
    $OPTION DIM VARIANT
    This changes the default type
    for an undeclared variable.
    By default, all undeclared variables are
    assumed to be of type DOUBLE
    if no suffix is provided.

    $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

    $OPTION ICON "path\file.ico"
    This changes the default icon
    of your executable file.

    $OPTION INKEY$ DEFAULT
    $OPTION INKEY$ TRAPALL
    This allows INKEY$ to accept/reject
    certain extended characters.
    TRAPALL will trap Shift/Ctrl/Alt/Menu
    as well as Caps/Num/Scroll lock.

    $OPTION VBDLL ON
    $OPTION VBDLL OFF
    This determines how DLLs are handled.
    If VBDLL is enabled (ON), your DLL
    declarations in Rapid-Q will mimic VB's
    such that your code can be used the
    same way in both languages.
    This option is OFF by default.

    $OPTION WEAKTYPE ON
    $OPTION WEAKTYPE OFF
    WeakType is disabled (OFF) by default
    WeakType allows for faster parsing
    and may help in porting some VB code.
    It should not generally be used,
    unless you know the code is okay.

$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

$MACRO
MacroName[(Parameters, ...)] MacroDefinition
A Macro simply replaces a definition with another. It can be treated like a function if you supply parameters. Rapid-Q allows Macros to be embedded within another Macro (foward only to avoid recursion), token pasting using ##, and even macro overloading. You can also redefine operators and special characters except quotes. A definition can extend to multiple lines by using the colon as a line separator. A $MACRO directive is global if it preceeds any $INCLUDE directives. ie. the included files have access to those Macro definitions. A $MACRO directive only affects the module level (ie. the current file) if used in an $INCLUDE file. So if A depends on B and B has some $MACRO directives, then those $MACRO directives only affect B and A has no access to them unless redeclared in module A.
Notes:
If you use the $MACRO directive, you are forcing Rapid-Q to preprocess your code, which will prolong the compilation process. Rapid-Q normally performs a single-pass compilation process.
Usage:
    $MACRO ~ ,
    This redefines the comma character
    Try: ? STRING$(10 ~ "A")

    $MACRO strcat(a,b) a=a+b
    Implements a STRCAT function
    strcat(a$,"abc") translates to a$=a$+"abc"

    $MACRO VARID(x) V##x
    An example of token pasting
    DEFINT VARID(1) translates to DEFINT V1

    $MACRO TWO_PI (2*PI)
    $MACRO PI 3.14159
    Embedded Macros (forward only).
    Can't embed itself as a parameter.
    This avoids rescanning & recursion.

    $MACRO ADD(a,b,c,d) ADD(a,b)+ADD(c,d)
    $MACRO ADD(x,y) x+y
    $MACRO ADD(x,y,z) x+y+z
    An example of macro overloading

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 visual components? They're basically just wrapper code that implement all the features of the Windows API control (or under Linux, whatever GUI API you're using) without all the headaches involved in using the 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, variants, udts, and arrays). To pass a variable by reference, you need to prepend an @ symbol. The second catch is that only a maximum of 10 parameters can be accepted (except when calling an API function, then it's limited to 25). 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. Here's another situation to demonstrate the scope of variable names:
       DIM I AS INTEGER

       SUB Scope (I AS INTEGER)
         DIM I AS INTEGER
         PRINT I
       END SUB

       PRINT I
In fact, the line DIM I AS INTEGER is a wasted statement, since the variable I is shadowed by the parameter name I. Rapid-Q will warn you about this, but won't error out.


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-2000 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 (you can also define custom shapes for your forms, using the method SHAPEFORM):
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
You can use MouseX and MouseY to track the position of the mouse on a form, but these 2 methods are being faded out. It is better just to handle the OnMouseMove event which pass the X and Y coordinates of the mouse position relative to the component.

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 Accepting user input
You can accept user input via the INPUT statement or by the INKEY$ function. Rapid-Q's INPUT statement is not like "normal" Basic INPUT that you may be familiar with. It is more like a LINE INPUT in that it will prompt for a complete line of information and only terminates if the user hits the enter key.
   INPUT "What is your age? ", Age
A quoted string can follow an INPUT statement, then a comma or semi-colon, followed by a variable. The input statement will store the result in the variable, string or numeric. The INPUT statement will block until the user has hit the enter key. For non-blocking keyboard inputs, try using INKEY$. It's a bit confusing to use at first, but it allows for customized keyboard handling. Let's use the same example above to demonstrate how this is done using INKEY$. However, in this version, we can customize input and filter out non-numeric characters.
   PRINT "What is your age? ";
   AGE$ = ""
   DO
     DO
       A$ = INKEY$
     LOOP UNTIL LEN(A$)
     IF A$ = CHR$(13) THEN EXIT DO
     IF A$ >= "0" AND A$ <= "9" THEN PRINT A$;:AGE$=AGE$+A$
   LOOP
   PRINT
   PRINT "You are "; AGE$; " years old."
Notice that if you press a non-numeric key, that character is not echoed. This is because we've restricted input to characters 0..9 only. Although the example is much longer than the previous one, we have customized our input using INKEY$ and that provides so much more power than INPUT. Another advantage of using INKEY$ is that you can also trap extended keys.

6.5 Trapping Extended Keys
Extended keys are 2 bytes in length, the first byte is an ESC character, which can be ignored, and the second byte is the virtual key code. In the Windows version, you can add the option to trap all keys, including shift, ctrl, key, caps lock, num lock, scroll lock, and that PopupMenu key (if you're using a Windows specific keyboard, no not the StartMenu Key, the other one, if it exists on your keyboard). You can turn on/off this option anytime you wish:
   $OPTION INKEY$ TRAPALL

   ' trap all keys including shift, alt, ctrl, caps/num/scroll lock
   ' and the PopupMenu key

   $OPTION INKEY$ DEFAULT

   ' traps all extended keys except the ones listed above
If you've used QBasic, you probably know the scan codes inside out, so all the virtual key codes that Rapid-Q dishes out is exactly the same scan codes you'd see in QBasic. The following code is an example of how to trap/parse extended keys, particularly the arrow keys:
   DO
     DO
       A$ = INKEY$
     LOOP UNTIL LEN(A$)

     IF LEN(A$) = 2 THEN
       SELECT CASE RIGHT$(A$, 1)
         CASE "P"
           PRINT "Down arrow key pressed."
         CASE "H"
           PRINT "Up arrow key pressed."
         CASE "M"
           PRINT "Right arrow key pressed."
         CASE "K"
           PRINT "Left arrow key pressed."
         CASE ELSE
           PRINT "Extended key "; A$
       END SELECT
     END IF

   LOOP UNTIL A$ = CHR$(27)
Even if you didn't know the scan codes, you can look at the output of the above example to figure them out.

6.6 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.7 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 for 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
Another approach is to store the value into a variable, you can use the generic Read and Write routines.
     File.Read(A&)          '-- Read a long value and store in A&
     File.Write(B#)         '-- Write a double value B#

     '-- or similarily, with more work:
     A& = File.ReadNum(Num_LONG)
     File.WriteNum(B#, Num_DOUBLE)
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. To test if you've reached the end of the file, you can either compare File.Position with File.Size or see if File.EOF is true (-1). 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.

7.3 Saving/Loading UDTs and Arrays
Saving and loading UDTs is as simple as passing the UDT to QFileStream or QMemoryStream.
    TYPE TTest
        S AS STRING*8
        N AS INTEGER
    END TYPE

    DIM Test AS TTest
    DIM File AS QFileStream

    File.Open("test.txt", fmCreate)
    File.WriteUDT(Test)
    File.Close
In the above example, 12 bytes was saved to the file test.txt. 8 bytes for the fixed string S, and 4 bytes for N. To retrieve the UDT, use the method ReadUDT.
    File.Open("test.txt", fmOpenRead)
    File.ReadUDT(Test)
Saving/Loading arrays is equally easy.
    DIM A(1 TO 100) AS LONG
    DIM File AS QFileStream

    File.Open("test.txt", fmCreate)
    File.SaveArray(A(1), 100)
    File.Close
The first parameter of SaveArray is the starting array element to save, this could be any value from 1 to 100 in the above example. The next parameter specifies how many elements of the array to save. In this case we choose to save all 1..100 elements. Similarly, we can use LoadArray to retrieve our data:
    File.Open("test.txt", fmOpenRead)
    File.LoadArray(A(1), 100)
Streams are very popular in most high level languages for file/memory manipulation, but does take some time to get used to, especially if you're a die-hard BASIC user.


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. 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 can take resource handles, you can just pass it as a parameter:
    $RESOURCE Bomb_WAV AS "BOMB.WAV"

    PlayWav(Bomb_WAV, 1)      '-- 1 = background play

    SLEEP 5                   '-- Wait until wav is finished
As for other types, you can extract the resource to be manipulated.
    $RESOURCE Whatever_TYPE AS "text.txt"

    ExtractResource(Resource(0), "text.txt")
After you're done using it, you can simply delete the file. 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-2000 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
What is a DLL? It's a Dynamic Link Library which contain exported functions which can be used by any programming language that support DLLs. So you could write your DLL in Delphi or C++ and use those functions in Rapid-Q. DLLs work by loading in the same process space as your program, so you have access to their exported functions. DLLs in Rapid-Q 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 any UDT you create.
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, the only problem I see is STRINGs, especially if you're using VisualBasic or PowerBasic. Please use pointers to strings in your parameters to avoid using OLE to allocate the string itself. Rapid-Q won't use OLE to allocate the string, since I don't anticipate many DLLs that don't use pointers to strings.

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$.

9.8 API conversion table
A lot of people have requested an API guide to convert their WinAPI declarations in C or VB to use with Rapid-Q, so here is a basic summary with some brief explanations. Special thanks to Mayuresh S. Kadu for this WIN32 API in VB guide.
C data type | Pascal | VB | Rapid-Q
ATOM | SHORT | byval as INTEGER | SHORT
BOOL | BOOLEAN | byval as LONG | LONG
BYTE | BYTE | byval as BYTE | BYTE
CHAR | CHAR | byval as BYTE | BYTE
CHAR[20] | STRING[20] | as STRING | N/A in API Declarations
COLORREF | LONGINT | byval as LONG | LONG
DWORD | DWORD | byval as LONG | DWORD
Windows handles ie. HDC | Windows Handles | byval as LONG | LONG
INT, UINT | INTEGER, DWORD | byval as LONG | INTEGER, DWORD
LONG | LONGINT | byval as LONG | LONG
LPARAM | LONGINT | byval as LONG | LONG
LPDWORD | ^DWORD | as LONG | BYREF as DWORD
LPINT, LPUINT | ^INTEGER | as LONG | BYREF as LONG
LPRECT | ^TRECT | as ANY | QRECT
LPSTR, LPCSTR | PCHAR | byval as STRING | BYREF as STRING
LPVOID | LONGINT | as ANY | LONG
LPWORD | ^WORD | as INTEGER | BYREF as WORD
LRESULT | LONGINT | byval as LONG | LONG
NULL | NIL | byval as LONG | LONG
SHORT | SHORT | byval as INTEGER | SHORT
WORD | WORD | byval as INTEGER | WORD
WPARAM | LONGINT | byval as LONG | LONG

For those data types in red, they are pointers to the variable. In Rapid-Q, this requires using VARPTR in passing the address of the variable, and not the value of the variable. Here's some sample conversions:
  In VB:
        DECLARE SUB Test LIB "USER32" ALIAS "What" _
                     (byval L AS LONG, byval S AS STRING)

        Test (1230, "Hello world!")

  In Rapid-Q:
        DECLARE SUB Test LIB "USER32" ALIAS "What" _
                     (byval L AS LONG, byval S AS STRING)

        Test (1230, "Hello world!")
Nothing different there, note that Rapid-Q doesn't use BYVAL, so you can ignore putting them there. In the above example, the string is passed by reference, ie. the address of the string is passed, not the string itself. Here's an example which passes the whole string (not the address, so it involves OLE to allocate space for the string), this works fine in VB but not in Rapid-Q:
  In VB:
        DECLARE SUB Test LIB "USER32" ALIAS "What" _
                     (byval L AS LONG, S AS STRING)

        Test (1230, "Hello world!")

  In Rapid-Q:
        Not possible, since it doesn't use OLE to allocate the string.
How about NULL strings? Here's another situation (please note that I don't use VB much so it may be possible to declare S as STRING and pass it a vbNullString, I'm not really sure so I'll play it safe):
  In VB:
        DECLARE SUB Test LIB "USER32" ALIAS "What" _
                     (byval L AS LONG, byval S AS LONG)

        Test (1230, 0&)

  In Rapid-Q:
        DECLARE SUB Test LIB "USER32" ALIAS "What" _
                     (byval L AS LONG, byval S AS LONG)

        Test (1230, 0&)
So what if we want to pass a string instead of a NULL string, then you'd need to use VARPTR:
  In VB or Rapid-Q:
        DIM S AS STRING
        S = "Hello world!"

        Test (1230, VARPTR(S))
A NULL string basically means an address of 0. VARPTR just returns the address of a variable. How about other pointers, like LPWORD? A WORD is just an unsigned 16-bit number, VB only supports signed 16-bit numbers called INTEGERs, but the general idea is to remove the byval keyword when passing variables by reference:
  In VB (doesn't support WORD, so use next best):
        DECLARE SUB Test LIB "USER32" ALIAS "Another" _
                     (L AS INTEGER)

        DIM L AS INTEGER

        Test (L)

  In Rapid-Q:
        DECLARE SUB Test LIB "USER32" ALIAS "Another" _
                     (BYREF L AS WORD)

        DIM L AS WORD

        Test (L)
In Rapid-Q, use BYREF when passing variables by reference, in VB you don't need to use BYREF, as the above example demonstrates.


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
In Rapid-Q, all methods, properties, and events can be overridden. In fact, you can override a method and treat it like it were a property or custom event. Once you override this method/property, you won't be able to access the inherited one (since it's hidden). To access this property or method, you must explicitly call the SUPER class as demonstrated below. Becareful if using WITH Super ... END WITH, since all properties/methods will be referenced as the super class. 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
            PRINT Super.Left
        END SUB
     END TYPE
In the above example, we've overriding 2 properties of QCanvas, and 1 method. As you'll see, QDiamondBox has a property named Left which overrides the Left property of QCanvas. To use the Left property of the super class, we just use the provided invocation Super.Left instead of QDiamondBox.Left. 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" component 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... 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 (you can also use the reserved word this), 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 possible to define new events for our components, but this will be covered later For now 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 (composition)
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 Templates and property sets
We have yet to cover how one creates their own custom events, so we'll get to that very soon, however, there are a few more interesting techniques, one called templates which you can use in your TYPE definition, and another called property sets. We will get to property sets later in this section, but let's start with templates. A template type definition may look a bit odd, but it was more or less modelled after C++.
    TYPE NewClass<DataType> EXTENDS QOBJECT
        N AS DataType
    END TYPE
Directly after declaring the new type, you can define the template <parameters>. In the above example, our only parameter is DataType, but you are allowed infinitely many parameters. Unlike C++ though, you don't specify the type of parameter, just the name. Now when you DIM this new type, you have to pass it that one extra template parameter:
    DIM MyClass1 AS NewClass<INTEGER>
    DIM MyClass2 AS NewClass<STRING>
Notice now how this works, the property N of MyClass1 is bound to an INTEGER data type, while MyClass2 has an N property which is bound to a STRING data type. Here are some other examples:
    TYPE Arrays<DataType, Size> EXTENDS QOBJECT
        Item(Size) AS DataType

        SUB Clear
            DIM N AS DataType
            DIM I AS LONG
            DIM V AS VARIANT

            WITH Arrays
                V = .Item(0)
                IF VARTYPE(V) = 2 THEN
                    '-- String data type
                    FOR I = 0 TO Size
                        .Item(I) = ""
                    NEXT
                ELSE
                    '-- Integer/Float
                    FOR I = 0 TO Size
                        .Item(I) = 0
                    NEXT
                END IF
            END WITH
        END SUB
    END TYPE

    DIM IntArray AS ARRAYS<INTEGER, 100>
    DIM StrArray AS ARRAYS<STRING, 50>

    IntArray.Clear
    IntArray.Item(1) = 99
    StrArray.Clear
    StrArray.Item(1) = "Hello world"

    PRINT IntArray.Item(1)
    PRINT StrArray.Item(1)
The use of templates can help reduce the amount of code by reusing the same TYPE for our INTEGER and STRING arrays. Now that we've covered templates, let's move on now to property sets. A property set is just a collection of properties, with one major difference, you can do special processing when a user sets the property. We will start with a somewhat useless example
    TYPE TForm EXTENDS QFORM
        Focus AS LONG PROPERTY SET Set_Focus

        PROPERTY SET Set_Focus (Handle AS LONG)
            WITH TForm
                .Focus = Handle
                IF .Focus THEN
                    SetFocus(Handle)
                END IF
            END WITH
        END PROPERTY
    END TYPE

    CREATE Form AS TForm
        CREATE Edit AS QEDIT
        END CREATE
        Focus = Edit.Handle
    END CREATE
Nevermind the function SetFocus, it's just an API call. In the above example, Focus is a property set, whenever you assign a value to this property, it automatically calls the routine Set_Focus as outlined in the SET parameter with the parameter being the value being assigned to it. Of course, you may be wondering why you'd even need this since it's equivalent to doing this:
    TYPE TForm EXTENDS QFORM
        SUB Focus (Handle AS LONG)
            IF Handle THEN
               SetFocus(Handle)
            END IF
        END SUB
    END TYPE

    CREATE Form AS TForm
        CREATE Edit AS QEDIT
        END CREATE
        Focus(Edit.Handle)
    END CREATE
As you may notice in this example, since Focus is a SUB, you can't retrieve the value (like in our previous example). In this case, you'd have to use another name such as GetFocus to check which handle has the focus. In the previous example, we can read and write the property and perform special processing when the property is assigned, which is what we wanted. Take for example, how the BorderStyle of QFORM is changed, when we assign a new value to BorderStyle, this initiates a sequence of events, but since BorderStyle is a property set, we don't need to define a SUB to set the style and a FUNCTION to retrieve the value.
    TYPE TForm EXTENDS QFORM
        GetStyle AS LONG
        SUB BorderStyle (Style AS LONG)
            TForm.GetStyle = Style
            SendMessage(TForm.Handle, etc...)
        END SUB
    END TYPE

    CREATE Form AS TFORM
        BorderStyle(bsNone)
        Caption = STR$(Form.GetStyle)
    END CREATE
That's a real waste as you can see, so you'd probably use property sets in that case. Obviously you won't need property sets if you don't require any special processing when assigning a value to a property. If you do decide to use property sets, there are some rules to follow: 1. Property and parameter should be of the same type; 2. Only simple types and QObjects are allowed to be property sets, so this excludes arrays and UDTs. The compiler will warn you if you violate these rules, but sometimes the error messages aren't so clear.

10.9 Custom events
Custom events are triggered by the programmer, ie. you. Let's try to come up with a situation where we would need to trigger an event. Take for example the QSOCKET component. It's completely void of any events, what if we want to know when the server is ready? Obviously we can keep polling to see when this occurs, but wouldn't it be nice if it was triggered for you, and then you can write an event handler to do what you want. I won't actually write the complete example, just the necessary parts to demonstrate how to create your own custom events:
    '-- Define, but don't implement, a template function
    DECLARE SUB ServerReady_EventTemplate (Socket AS LONG)

    TYPE TSocket EXTENDS QSOCKET
        OnServerReady AS EVENT(ServerReady_EventTemplate)
        Timer1 AS QTIMER
        Sock AS LONG

        EVENT Timer1.OnTimer
            WITH TSocket
                IF .IsServerReady(.Sock) AND .OnServerReady > 0 THEN
                    '-- OnServerReady  > 0 is to check whether pointer is null
                    '-- ie. is there really an event handler assigned
                    '-- If assigned, then trigger the event
                    CALLFUNC(.OnServerReady, .Sock)
                END IF
            END WITH
        END EVENT

        CONSTRUCTOR
            OnServerReady = 0
            Timer1.Enabled = 1
            Timer1.Interval = 500
        END CONSTRUCTOR
    END TYPE

    SUB ServerReady (Sock AS LONG)
        PRINT Sock;" is ready."
    END SUB

    CREATE Socket AS QSOCKET
        OnServerReady = ServerReady
    END CREATE
It might be a good idea to go through the next chapter on Function Pointers, since this is basically how custom events work. OnServerReady is really a function pointer, which points to a SUB (if assigned, if not, it is equivalent to 0). A declaration of the template SUB is required, this is to provide CALLFUNC with the necessary parameter types, if any. It may seem a bit confusing at first, since it takes some time getting used to the syntax and the idea of triggering an event. However, creating custom events has many benefits and uses, so learning how to create your own events could greatly simplify the use of your component or even extend the functionality of others (such as the above example).

10.10 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 provides slightly better precision than QTimer, and controls the frame rate so that your program doesn't run too fast. It may 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 (not necessary but recommended).


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 BLOB, by default can hold up to 65535 bytes (a LONGBLOB should be able to handle 2^32-1 bytes). If you want to change the buffer size, you'll have to read up on it (max_allowed_packet). 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.


Chapter 15: COM Programming

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

15. COM Programming

Component Object Model (COM) and Distributed COM (or DCOM), is a specification that defines object creation and communication between objects. Rapid-Q only supports client-side COM programming (ie. you will not be able to create COM servers in Rapid-Q). Since work is still be being done, some of the information in this chapter may change in the future.

15.1 Supported COM extensions
COM has many extended services which have grown over time. Unfortunately Rapid-Q is limited to only a few:
  • COM clients (or Automation controllers) is implemented in QOLEOBJECT
  • Active Documents is implemented in QOLECONTAINER
Automation controllers can be used to drive automation servers such as MS WORD over a local machine or remotely. So what are the benefits of automating a server? Well, since the server can be invoked by another machine, this can free up resources and CPU cycles needed on your client system. Since you could automate an application from across a network (or the internet), you don't need the application to reside on your machine to do some useful work on it. Imagine automating machinery from your home. Active documents is similar to automation, however, the "document" (more like ActiveX control) is embedded into your application. Once embedded, you can use automation to control the behaviour of the document. Rapid-Q does not support Type Libraries, so vtable binding is not possible. Speaking of binding, a COM server is usually registered on your computer the first time it is run or installed. For .DLLs or .OCXs, this may not always be the case, so to register a COM server manually, you can use Window's regsvr32 program.
    regsvr32 myprog.dll
You can type that in your MS-DOS command line prompt, or via Start|Run. There are also programming examples to register a COM object, see the Windows API help file for more information.

15.2 About QOLEOBJECT
As mentioned in the previous section, QOLEOBJECT implements an automation controller. This component works similarly to VB (no, VB does not have a QOLEOBJECT component), except for a few things which are either implemented in another way or is not yet supported. Let's look at some examples comparing the 2 methods:

    ' Both examples invoke MS WORD
    ' in VB
    DIM Obj AS OBJECT

    Set Obj = CreateObject("Word.Basic")
    ' or just DIM Obj AS Word.Basic
    Obj.AppShow

    ' in Rapid-Q
    DIM Obj AS QOLEOBJECT

    Obj.CreateObject("Word.Basic")
    Obj.AppShow
Note that type checking is off for OBJECT and QOLEOBJECT, so when you invoke Obj.AppShow this calls the method AppShow in MS WORD. You may notice that Rapid-Q also supports the Invoke method. This is to eliminate ambiguity but also to provide a work around. So what if MS WORD has a method called CreateObject? In Rapid-Q this causes a problem since CreateObject is a valid method of QOLEOBJECT, so that method will be called, not the one in MS WORD. The work around is to use the Invoke method.
    ' in Rapid-Q
    DIM Obj AS QOLEOBJECT

    Obj.CreateObject("Word.Basic")
    Obj.Invoke("CreateObject") ' Call CreateObject method in MS WORD
Obviously you shouldn't run the above example, MS WORD doesn't have a CreateObject method, but you get the idea. Setting and getting properties can be done similarly:
    ' in Rapid-Q
    DIM Obj AS QOLEOBJECT

    Obj.CreateObject("Gif89.Gif89.1")
    Obj.AutoStart = 1
    Obj.Invoke("AutoStart") = 1 ' this also works
So what's not supported in Rapid-Q? Several data types and arrays are not supported yet, as well as events. Also there isn't a "set" method available. ie:
    ' in VB
    DIM ADOCommand AS ADODB.Command
    DIM ADOConnection AS ADODB.Connection

    set ADOCommand.ActiveConnection = ADOConnection
The line in red is not yet available in Rapid-Q. See the Appendix section on QOLEOBJECT, you will find a method called InvokeCopy which does the samething, but unfortunately isn't fully functional as of this writing.

15.3 About QOLECONTAINER
QOLECONTAINER is basically a container for embedding ActiveX components or Active documents. This component is very similar to QOLEOBJECT, it is again type check free, so you can automate the control like you would automating servers. You may find yourself using the Invoke method more often than not, since QOLECONTAINER does have a lot of properties and methods already defined. Another way to avoid this problem is the assign the Container method of QOLEOBJECT. This creates a reference to the object, and so you can use QOLEOBJECT to automate the control. For those that aren't familiar, ActiveX controls are reusable visual controls which are heavily used in VB. Again, the limitations are obvious, Rapid-Q doesn't support ActiveX events, type libraries, and a few others mentioned before.
    '-- A short example
    DIM Form AS QFORM
    DIM Obj AS QOLECONTAINER

    Obj.Parent = Form
    Obj.CreateObject("gif89.gif89.1")
Since an ActiveX control is a visible component, you'll note that the QOLECONTAINER requires a parent property. You'll also have to be wary of the fact that the ActiveX component could update/refresh the component even before the form is shown, so you'll receive a Can't focus a disabled or invisible window when that happens. QOLECONTAINER has an AutoShow property which can be set to False meaning that the ActiveX control should not be displayed when created. You can use the method Show of QOLECONTAINER to display the control at anytime after creating the object. There is also another way to avoid the error message from popping up, see the Appendix section on QOLECONTAINER for a complete example.


Appendix A: APPLICATION

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

APPLICATION Component

This object is global, and need not be created.

Application Properties
Field | Type | R/W | Default | Support
ExeName | STRING | R | WXG
The executable name of the application, path name is excluded (use COMMAND$(0) for full path information).
Handle | INTEGER | R | W
hInstance of the application.
HelpFile | STRING | RW | W
HelpFile specifies the name of the file the application uses to display help.
HintColor | INTEGER | RW | clInfoBk | W
HintColor determines the color of the hint boxes for the Help Hints.
HintHidePause | INTEGER | RW | 2500 | W
HintHidePause specifies the time interval to wait before hiding the Help Hint if the mouse has not moved from the control or menu item.
HintPause | INTEGER | RW | 500 | W
HintPause specifies the time interval that passes before the control's Help Hint appears when the user places the mouse pointer on a control or menu item.
HintShortPause | INTEGER | RW | 50 | W
HideShortPause specifies the pause to wait before bringing up a hint if a hint has already been shown.
Icon | STRING | RW | W
Specify an icon filename to appear as the default icon of your application.
IcoHandle | RESOURCE | W | W
Specify an icon resource to appear as the default icon of your application.
Example:
$RESOURCE game_ICO AS "game.ico"
Application.IcoHandle = game_ICO
ShowHint | INTEGER | RW | True | W
Title | STRING | RW | W

Application Methods
Method | Type | Description | Params | Support
HelpCommand | SUB (Command AS WORD, Data AS LONG) | Accesses the Help commands in the WinHelp API | 2 | W
HelpContext | SUB (Context AS LONG) | Bring up the Application's HelpFile at specifed Context ID | 1 | W
HelpJump | SUB (JumpID AS STRING) | Brings up the HelpFile and displays the screen in the Help file that has the JumpID | 1 | W
Minimize | SUB | Minimize Application | 0 | W
Terminate | SUB | Terminates Application | 0 | WXG

Application Examples
  Application.HintColor = &H00FF00

  CREATE Form AS QFORM
      CREATE Button AS QBUTTON
          Hint = "Button Hint"
          ShowHint = 1
      END CREATE
      ShowModal
  END CREATE


Appendix A: CLIPBOARD

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

CLIPBOARD Component

This object is global, and need not be created.

ClipBoard Properties
Field | Type | R/W | Default
Format | ARRAY of WORD | RW
Format is a list of all the format the Clipboard contains. There are too may formats to fit on this page, not to mention all the custom formats you may have registered. Check your WinAPI help file for a list.
FormatCount | INTEGER | R
FormatCount contains the number of formats in the Format array.
Text | STRING | RW
Text specifies the current contents of the Clipboard as a string.

ClipBoard Methods
Method | Type | Description | Params
Clear | SUB | Clear clipboard | 0
Deletes contents of the Clipboard.
Close | SUB | Free clipboard for other processes | 0
Closes the Clipboard if it is open. The Clipboard can be opened multiple times, so the Clipboard will remain opened until it has been closed the same number of times it has been opened.
GetAsHandle | FUNCTION (Format AS WORD) AS LONG | Returns handle of specified format | 1
GetAsHandle returns the data from the Clipboard in a raw Windows handle for the specified format.
GetAsText | FUNCTION (length%) AS STRING | Returns text of length% | 1
GetAsText returns the text contents of the Clipboard. See also Text property.
HasFormat | FUNCTION (Format AS WORD) AS SHORT | Returns true or false if the format exists or not | 1
HasFormat indicates if the Clipboard object contains a particular format. Returns 0 if format is absent, non-zero otherwise if format is present.
Open | SUB | Begin critcal section | 0
Opens the Clipboard and prevents other applications from changing its contents until the Clipboard is closed.
SetAsHandle | SUB (Format AS WORD, Handle AS LONG) | Set handle and format | 2
SetAsHandle places the data in the given format as a Windows handle.
SetAsText | SUB (Text$) | Set text of clipboard | 1
SetAsText sets the text contents of the Clipboard. See also Text property.

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
Aborted determintes if the user aborted the print job.
Capabilities.Copies | INTEGER | R
Capabilities.Copies indicates whether the print is capable of printing multiple copies.
Capabilities.Orientation | INTEGER | R
Capabilities.Orientation indicates whether the print is capable of different orientations.
Capabilities.Collate | INTEGER | R
Capabilities.Collate indicates whether the print is capable of collating.
Copies | INTEGER | RW
Number of copies to print.
CopyMode | INTEGER | RW | cmBlackNess
Font | QFONT | W
Fonts | ARRAY of STRING | R
FontsCount | INTEGER | R
Handle | INTEGER | R
Orientation | INTEGER | RW
Orientation determines if the print job prints vertically or horizontally on a page.
Valid orientation values are:
0 = poPortrait (Vertical print)
1 = poLandscape (Horizontal print)
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
Title is the text that appears in the Print Manager and on network header pages.

Printer Methods
Method | Type | Description | Params
Abort | SUB | Abort printing the document | 0
BeginDoc | SUB | Starts new document to print | 0
BeginDoc sends a print job to the printer.
EndDoc | SUB | Nothing is printed until this is called | 0
EndDoc will start the print job.
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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7
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 | RW | W
Use BMP to assign a new bitmap file, or to store BMP in the image cache.
Examples:
DIM Bitmap AS QBITMAP
Bitmap.BMP = "whatever.bmp"
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
Example (copies QIMAGE to bitmap at 10,10):
DIM Destination AS QRECT
DIM Source AS QRECT
DIM Image AS QIMAGE
DIM Bitmap AS QBITMAP
Image.BMP = "whatever.bmp"

WITH Destination
.Top = 10
.Left = 10
.Right = .Left+Image.Width
.Bottom = .Top+Image.Height
END WITH
WITH Source
.Top = 0
.Left = 0
.Right = Image.Width
.Bottom = Image.Height
END WITH
Bitmap.CopyRect(Destination, Image, Source)
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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7 | 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 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-2000 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
Align determines how the control aligns within its parent control.
BMP | STRING | RW | W
Use BMP to assign a new bitmap file, or to use BMP in a draw statement.
Examples:
DIM button AS QBUTTON
button.BMP = "whatever.bmp"
Details:
You can hold multiple images on a single bitmap, but they must be of the same size and next to each other in a horizontal row.
The "first" bitmap appears when the button is up.
The "second" bitmap appears when the button disabled.
The "third" bitmap appears when the button is down (clicked).
You have to tell Rapid-Q how many images are in your bitmap by assigning the number to NumBMPs.
BMPHandle | RESOURCE | W | W
Assign a BMP resource handle to appear on the selected button.
Example:
$RESOURCE game_BMP AS "game.bmp"
DIM button AS QBUTTON
button.bmpHandle = game_BMP
Cancel | INTEGER | RW | False | W
If Cancel is True, the button's OnClick event handler executes when the user presses the Escape key.
Caption | STRING | RW | WXG
Caption specifies the text that appears on the button. To underline a character, include an ampersand (&) symbol before the character.
Color | INTEGER | RW | X
Cursor | INTEGER | RW | crDefault | W
Default | INTEGER | RW | False | W
If Default is True, the button's OnClick event handler executes when the user presses the Enter key.
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
Layout determines where the bitmap image appears on the button.
0 = blBMPLeft -- image appears at the left side of the caption
1 = blBMPRight -- image appears at the right side of the caption
2 = blBMPTop -- image appears above the caption
3 = blBMPBottom -- image appears below the caption
Left | INTEGER | RW | 0 | WXG
ModalResult | INTEGER | RW | mrNone | W
NumBMPs | INTEGER | RW | W
NumBMPs determines the number of images within the bitmap button.
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
ShowHint | INTEGER | RW | False | WXG
Spacing | INTEGER | RW | 4 | W
Determines the separation, in pixels, between the image and the caption.
TabOrder | INTEGER | RW | W
Tag | INTEGER | RW | WXG
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

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-2000 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
Align determines how the control aligns within its parent control.
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
Tag | INTEGER | RW | WXG
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
Example (copies QIMAGE to canvas at 10,10):
DIM Destination AS QRECT
DIM Source AS QRECT
DIM Image AS QIMAGE
Image.BMP = "whatever.bmp"

SUB CanvasPaint (Sender AS QCANVAS)
WITH Destination
.Top = 10
.Left = 10
.Right = .Left+Image.Width
.Bottom = .Top+Image.Height
END WITH
WITH Source
.Top = 0
.Left = 0
.Right = Image.Width
.Bottom = Image.Height
END WITH
Sender.CopyRect(Destination, Image, Source)
END SUB

DIM Canvas AS QCANVAS
Canvas.OnPaint = CanvasPaint
Draw | SUB (x%, y%, BMP) | Draw Bitmap on Canvas | 3 | WG
Details:
BMP can be any BMP property from QBitmap, QImage, QImageList, etc. any component with a BMP property is fine.
Examples:
DIM Image1 AS QIMAGE
Image1.BMP = "whatever.bmp"
DIM Image2 AS QBITMAP
Image2.BMP = "whatever.bmp"

SUB CanvasPaint (Sender AS QCANVAS)
Sender.Draw(0, 0, Image1.BMP)
Sender.Draw(50, 50, Image2.BMP)
END SUB

DIM Canvas AS QCANVAS
Canvas.OnPaint = CanvasPaint
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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7 | 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
Tag | INTEGER | RW | WXG
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-2000 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
Align determines how the control aligns within its parent control.
Color | INTEGER | RW | W
CopyMode | INTEGER | RW | cmBlackness | W
Cursor | INTEGER | RW | crDefault | W
DropDownCount | INTEGER | RW | 8 | W
DropDownCount is the maximum number of items displayed in the drop-down list.
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
ItemHeight | INTEGER | RW | W
ItemIndex | INTEGER | RW | -1 | WXG
ItemIndex indicates which item in the drop-down list is selected. If no item is selected, then ItemIndex is -1.
Left | INTEGER | RW | 0 | WXG
MaxLength | INTEGER | RW | W
MaxLength is the maximum number of characters the user can type into the edit portion of the combobox.
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
Style determines the display style of the combobox.
0 = csDropDown -- A drop-down list with an edit box for manually entered text.
1 = csSimple -- A drop-down list with an edit box and a fixed list (list box) underneath.
2 = csDropDownList -- A drop-down list with no edit box for manual entry.
3 = csOwnerDrawFixed -- Owner-draw drop-down list with an edit box. Each item in the list is the height specified by the ItemHeight property.
4 = csOwnerDrawVariable -- Owner-draw drop-down list with an edit box. Each item can have varying heights.
TabOrder | INTEGER | RW | W
Tag | INTEGER | RW | WXG
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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7 | 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. Make sure to download the optional comport libraries to use this component.

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-2000 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
Align determines how the control aligns within its parent control.
AllowAllUp | INTEGER | RW | False | W
AllowAllUp specifies whether all buttons in the group can be unselected at the same time.
BMP | STRING | W | WX
Use BMP to assign a new bitmap file, or to use BMP in a draw statement.
Examples:
DIM coolbutton AS QCOOLBTN
coolbutton.BMP = "whatever.bmp"
Details:
You can hold multiple images on a single bitmap, but they must be of the same size and next to each other in a horizontal row.
The "first" bitmap appears when the button is up.
The "second" bitmap appears when the button disabled.
The "third" bitmap appears when the button is clicked.
The "fourth" bitmap appears when the button stays down.
You have to tell Rapid-Q how many images are in your bitmap by assigning the number to NumBMPs.
BMPHandle | RESOURCE | W | W
Caption | STRING | RW | WXG
Cursor | INTEGER | RW | crDefault | W
Down | INTEGER | RW | False | WX
Down specifies whether the button is selected (down) or unselected (up).
Enabled | INTEGER | RW | True | WXG
Flat | INTEGER | RW | False | WX
Flat determines whether the button has a 3D border that provides a raised or lowered look.
Font | QFONT | W | W
GroupIndex | INTEGER | RW | 0 | W
GroupIndex allows buttons to work together as a group. If GroupIndex is 0, the button behaves independently of all other buttons.
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Layout | INTEGER | RW | blBMPLeft | W
Layout determines where the bitmap image appears on the button.
0 = blBMPLeft -- image appears at the left side of the caption
1 = blBMPRight -- image appears at the right side of the caption
2 = blBMPTop -- image appears above the caption
3 = blBMPBottom -- image appears below the caption
Left | INTEGER | RW | 0 | WXG
NumBMPs | INTEGER | RW | W
NumBMPs determines the number of images within the bitmap button.
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
ShowHint | INTEGER | RW | False | WXG
Spacing | INTEGER | RW | 4 | W
Determines the separation, in pixels, between the image and the caption.
TabOrder | INTEGER | RW | W
Tag | INTEGER | RW | WXG
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-2000 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
Align determines how the control aligns within its parent control.
AutoSize | INTEGER | RW | True | W
AutoSize determines whether the edit control should adjust its size automatically to accomodate the height of the text.
BorderStyle | INTEGER | RW | bsSingle | W
CharCase | INTEGER | RW | ecNormal | W
CharCase determines the case of the text within the edit control.
0 = ecNormal -- The text of the edit box displays in mixed case.
1 = ecUpperCase -- The text of the edit box displays in uppercase.
2 = ecLowerCase -- The text of the edit box displays in lowercase.
Color | INTEGER | RW | W
EditText | STRING | RW | W
EditText is the value of the text for the edit control after it is formatted using InputMask
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
InputMask is the mask that represents what text is valid for the edit control
IsMasked | INTEGER | R | False | W
IsMasked indicates whether a mask exists for the edit control.
Left | INTEGER | RW | 0 | WXG
MaxLength | INTEGER | RW | 0 | WXG
Modified | INTEGER | RW | W
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PasswordChar | STRING | RW | W
PasswordChar indicates the character, if any, to display in place of the actual characters typed in the control. An empty string indicates that text should be displayed normally.
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
Tag | INTEGER | RW | WXG
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

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

' Example on how to handle OnKeyDown event

SUB EditKeyDown (Key AS WORD, Shift AS INTEGER, Sender AS QEDIT)
    SELECT CASE Key
        CASE 27
            SHOWMESSAGE "Escape key pressed!"
        CASE 13
            SHOWMESSAGE "Enter key pressed!"
    END SELECT
END SUB

CREATE Form AS QFORM
    Center
    CREATE Edit AS QEDIT
        OnKeyDown = EditKeyDown
    END CREATE
    ShowModal
END CREATE
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-2000 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
Align determines how the control aligns within its parent control.
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Directory | STRING | RW
Directory is the directory that contains all the files listed in the file listbox.
Drive | STRING | RW
Enabled | INTEGER | RW | True
ExtendedSelect | INTEGER | RW | True
ExtendedSelect determines if the user can select a sequential range of items in the file listbox.
Filename | STRING | RW
FileName is the name of the selected file in the listbox, including the pathname.
Font | QFONT | W
Height | INTEGER | RW
Hint | STRING | RW
Item | ARRAY of STRING | RW
ItemCount | INTEGER | R
ItemHeight | INTEGER | RW
ItemIndex | INTEGER | RW
ItemIndex specifies the index of the selected item in the file listbox. If no item is selected, ItemIndex equals -1.
Left | INTEGER | RW | 0
Mask STRING RW *.*
MultiSelect | INTEGER | RW | False
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
SelCount | INTEGER | R
Selected | ARRAY of INTEGER | RW
ShowHint | INTEGER | RW | False
ShowIcons | INTEGER | RW | False
ShowIcons determines whether images should appear next to the file names.
TabOrder | INTEGER | RW
Tag | INTEGER | RW
TopIndex | INTEGER | RW
TopIndex specifies the index number of the item that appears at the top of the file listbox.
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
FileTypes determine which files are displayed in the file listbox according to their attributes.
0 = ftReadOnly -- Display files with read-only attribute.
1 = ftHidden -- Display files with hidden attribute.
2 = ftSystem -- Displays system files.
3 = ftVolumeID -- Displays volume name.
4 = ftDirectory -- Displays directories.
5 = ftArchive -- Display files with archive attribute.
6 = ftNormal -- Display files with no special attributes.
Example:
$INCLUDE "RAPIDQ.INC"
DIM FileListBox AS QFILELISTBOX
FileListBox.AddFileTypes(ftDirectory, ftHidden)
DelFileTypes | SUBI | Remove certain file types from list | INTEGER, Infinite
Update | SUB | Updates/refreshes file list | 0

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 = "*.*"
   AddFileTypes(ftDirectory)          '' Add Directories
   DelFileTypes(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-2000 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
EOF | INTEGER | R | WXG
EOF specifies whether the file pointer has reached the end of file.
Handle | INTEGER | R | W
LineCount | INTEGER | R | WXG
LineCount determines how many lines there are in the file. Note that LineCount ignores the CR character, and will only detect LF, so it treats CRLF as one line, but LFLF as 2 lines.
Position | INTEGER | RW | WXG
Position specifies the current position of the file pointer, any read/write operations will begin from here.
Size | INTEGER | R | WXG
Size determines the size of the file in bytes.

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
Use CopyFrom to copy a QFILESTREAM or a QMEMORYSTREAM to the current filestream.
Details:
If Bytes% = 0 then the Stream is reset to position 0 and the whole stream is then copied.
Example:
$INCLUDE "RAPIDQ.INC"
DIM File1 AS QFILESTREAM
DIM File2 AS QFILESTREAM

File1.Open("test.txt", fmCreate)
File2.Open("oldtest.txt", fmOpenRead)
File1.CopyFrom(File2, 123) '-- Copy 123 bytes from File2
ExtractRes | SUB (Resource AS LONG) | Extract resource to filestream | 1 | WXG
Extracts a resource from your program to the filestream.
Details:
The parameter Resource is not the resource handle, but the absolute position of the resource within your file. This requires that you use the keyword Resource(n) to specify the resource number.
Example (dumping all resources):
$INCLUDE "RAPIDQ.INC"
$RESOURCE res_1 as "res.1"
$RESOURCE res_2 as "res.2"

DIM File1 AS QFILESTREAM

File1.Open("test.txt", fmCreate)

FOR I = 0 TO ResourceCount-1
    File1.ExtractRes(Resource(I))
NEXT
LoadArray | SUB (Array(), NumElements&) | Load data into array | 2 | WXG
Open | SUB (FileName$, Method%) | Open a file, Method% see RAPIDQ.INC | 2 | WXG
Read | SUB (variable) | Generic Read, determines the storage space and saves data in variable | 1 | WXG
Datasize is automatically determined, and the value is stored into the variable.
Example:
$INCLUDE "RAPIDQ.INC"
DIM File1 AS QFILESTREAM
DIM B AS BYTE, I AS INTEGER

File1.Open("test.txt", fmOpenRead)
File1.Read(B) '-- Read a byte
File1.Read(I) '-- Read an integer
ReadLine | FUNCTION () AS STRING | Reads an entire line, supports UNIX files | 0 | WXG
ReadNum | FUNCTION (n) AS DOUBLE | Read n bytes, returns number | 1 | WXG
ReadBinStr | FUNCTION (n) AS STRING | Read n bytes, returns the binary string | 1 | WXG
ReadStr | FUNCTION (n) AS STRING | Read n bytes, returns the text string | 1 | WXG
ReadUDT | SUB (MyType) | Read and store data in a MyType structure | 1 | WXG
SaveArray | SUB (Array(), NumElements&) | Save array | 2 | WXG
Seek | SUB (Position%, From%) | Seek to Position%, From% see RAPIDQ.INC | 2 | WXG
Write | SUB (variable) | Generic Write, determines the storage space and saves data to file | 1 | 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 | 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)
  S$ = File.ReadStr(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(Person)


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
Charset | INTEGER | RW | DEFAULT_CHARSET | W
Color | INTEGER | RW | W
FontCount | INTEGER | R | W
FontName | ARRAY of STRING | R | W
Handle | INTEGER | RW | W
Name | STRING | RW | WX
Pitch | INTEGER | RW | fpDefault | W
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-2000 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...

W = Windows, X = Rapid-Q/XForms, G = Rapid-Q/GTK

QForm Properties
Field | Type | Read/Write | Default Value | 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
BorderStyle specifies the appearance and behaviour of the form border.
0 = bsNone -- Not resizeable; no visible border line or caption bar
1 = bsSingle -- Not resizeable; single-line border
2 = bsSizeable -- Standard resizeable border
3 = bsDialog -- Not resizeable; standard dialog box border
4 = bsToolWindow -- Like bsSingle but with a smaller caption
5 = bsSizeToolWin -- Like bsSizeable but with a smaller caption
Caption | STRING | RW | WXG
Caption is the text that appears as the title of your form.
ClientHeight | INTEGER | RW | WXG
The height of the form's client area, ie. the usable area inside the form's border.
ClientWidth | INTEGER | RW | WXG
The width of the form's client area, ie. the usable area inside the form's border.
Color | INTEGER | RW | clBtnFace | W
Color of the form.
Cursor | INTEGER | RW | crDefault | W
Cursor that appears when the mouse pointer is over the form.
Font | QFONT | W | W
Sets font property. Used for TextOut method.
FormStyle | INTEGER | RW | fsNormal | W
Get or set the form's style. Only fsNormal is supported.
Handle | INTEGER | R | W
Get the form's handle for WinAPI calls.
Height | INTEGER | RW | WXG
Get or set the form's vertical size (in pixels).
Hint | STRING | RW | W
The hint string that appears when the user moves the mouse pointer over the form. It is not displayed unless ShowHint is true.
IcoHandle | RESOURCE | W | W
Assign an icon resource handle to appear as the icon for your form.
Example:
$RESOURCE game_ICO AS "game.ico"
DIM Form AS QFORM
Form.IcoHandle = game_ICO
Icon | STRING | W | W
Assign an icon filename to appear as the icon for your form.
KeyPreview | INTEGER | RW | False | W
Specify whether keyboard events should occur on the form before they occur on the active control. Not all keys will be redirected.
Left | INTEGER | RW | 0 | WXG
Specifies the left edge of the form relative to the desktop screen.
ModalResult | INTEGER | W | W
Assigning a value to ModalResult will close the form when it is displayed modally.
0 = mrNone
1 = mrOk
2 = mrCancel
3 = mrAbort
4 = mrRetry
5 = mrIgnore
6 = mrYes
7 = mrNo
8 = mrAll
Parent | QFORM | W | W
Assigning a parent will remove the second form from the taskbar.
PopupMenu | QPOPUPMENU | W | W
Popupmenus are displayed when user right clicks on the form.
Example:
DIM PopupMenu AS QPOPUPMENU
DIM Form AS QFORM
Form.PopupMenu = PopupMenu
ShowHint | INTEGER | RW | False | W
If True then the hint popup message can be displayed.
Top | INTEGER | RW | 0 | WXG
Visible | INTEGER | RW | False | WXG
Specifies the visibility of the form.
Width | INTEGER | RW | 320 | WXG
WindowState | INTEGER | RW | wsNormal | W
Specifies how the form appears on the screen.
0 = wsNormal -- form appears neither maximized nor minimized
1 = wsMinimized -- form is minimized
2 = wsMaximized -- form is maximized

 QForm Methods
Method | Type | Description | Params | Support
AddBorderIcons | SUBI | Add Border Icons | INTEGER, Infinite | W
Valid border icons are:
0 = biSystemMenu -- The form icon
1 = biMinimize -- The minimize icon
2 = biMaximized -- The maximize icon
3 = biHelp -- The help icon
Example:
$INCLUDE "RAPIDQ.INC"
DIM Form AS QFORM
Form.AddBorderIcons(biHelp)
Center | SUB | Used to center a form | 0 | WXG
Circle | SUB (x1%, y1%, x2%, y2%, c%, fill%) | Draw & Fill Circle/Ellipse | 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
Example (copies QIMAGE to form at 10,10):
DIM Destination AS QRECT
DIM Source AS QRECT
DIM Image AS QIMAGE
Image.BMP = "whatever.bmp"

SUB FormPaint (Sender AS QFORM)
WITH Destination
.Top = 10
.Left = 10
.Right = .Left+Image.Width
.Bottom = .Top+Image.Height
END WITH
WITH Source
.Top = 0
.Left = 0
.Right = Image.Width
.Bottom = Image.Height
END WITH
Sender.CopyRect(Destination, Image, Source)
END SUB

DIM Form AS QFORM
Form.OnPaint = FormPaint
DelBorderIcons | SUBI | Remove Border Icons | INTEGER, Infinite | W
Valid border icons are:
0 = biSystemMenu -- The form icon
1 = biMinimize -- The minimize icon
2 = biMaximized -- The maximize icon
3 = biHelp -- The help icon
Example:
$INCLUDE "RAPIDQ.INC"
DIM Form AS QFORM
Form.DelBorderIcons(biMinimize)
Details:
Deleting icon may not necessarily remove it from the form's title bar, but the icon will be greyed out.
Draw | SUB (x%, y%, BMP) | Draw Bitmap on Canvas | 3 | W
Details:
BMP can be any BMP property from QBitmap, QImage, QImageList, etc. any component with a BMP property is fine.
Examples:
DIM Image1 AS QIMAGE
Image1.BMP = "whatever.bmp"
DIM Image2 AS QBITMAP
Image2.BMP = "whatever.bmp"

SUB FormPaint (Sender AS QFORM)
Sender.Draw(0, 0, Image1.BMP)
Sender.Draw(50, 50, Image2.BMP)
END SUB

DIM Form AS QFORM
Form.OnPaint = FormPaint
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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7 | W
ShapeForm | SUB (Filename$|Resource, TransparentColor&) | Shapes form as outline of image | 2 | W
Details:
The first parameter can either be a filename to the BMP file, or a BMP resource file. The second parameter indicates which color is transparent.
Example 1:
DIM Form AS QFORM
Form.ShapeForm("image.bmp", &HFFFFFF)
Example 2:
$RESOURCE image_BMP AS "image.bmp"

DIM Form AS QFORM
Form.ShapeForm(image_BMP, &HFFFFFF)
Show | SUB | Used to show form when hidden | 0 | WX
ShowModal | FUNCTION AS SHORT | 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
Details:
BMP can be any BMP property from QBitmap, QImage, QImageList, etc. any component with a BMP property is fine.
Examples (Double original size):
DIM Image1 AS QIMAGE
Image1.BMP = "whatever.bmp"

SUB FormPaint (Sender AS QFORM)
DIM R AS QRECT
R.Left = 0
R.Top = 0
R.Right = Image1.Width*2
R.Bottom = Image1.Height*2
Sender.StretchDraw(R Image1.BMP)
END SUB

DIM Form AS QFORM
Form.OnPaint = FormPaint
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
Details:
fc% = foreground color
bc% = background color
For a transparent background, set bc% parameter to -1

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
OnHint | SUB (Hint AS STRING) | Hint is displayed | 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-2000 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
Align determines how the control aligns within its parent control.
BackColor | INTEGER | RW | clWhite
BackColor specifies the background color of the component.
BorderStyle | INTEGER | RW | bsSingle
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
ForeColor | INTEGER | RW
ForeColor specifies the color of the progress meter.
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
ShowText determines whether the progress text (as a percent) should be displayed.
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
Tag | 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
Tag | INTEGER | RW
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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7
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-2000 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
Align determines how the control aligns within its parent control.
Autosize | INTEGER | RW | False
AutoSize determines whether the image control resizes to accommodate the image it displays.
BMP | STRING | RW
Use BMP to assign a new bitmap file, or to store BMP in the image cache.
Examples:
DIM Image AS QIMAGE
Image.BMP = "whatever.bmp"
BMPHandle | RESOURCE | W
Center | INTEGER | RW | False
Center positions the image so that it is centered in the image control.
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
IncrementalDisplay specifies whether partial renderings of the image are drawn periodically during slow operations or on large compressed images.
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
Stretch resizes the image so that it exactly fits the bounds of the image control.
Tag | INTEGER | RW
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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7
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-2000 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 | clNone
BkColor determines which background color to use when drawing an image. Setting BkColor to clNone specifies no background color, ie. the image is drawn transparently. Setting BkColor to clDefault specifies using the imagelists background color when drawing.
BlendColor | INTEGER | RW | clNone
BlendColor determines which foreground color to use when drawing an image. Setting BlendColor to clNone specifies no blend color, while setting BlendColor to clDefault specifies the system highlight color for the foreground.
Count | INTEGER | R
Count returns the number of images in the imagelist.
DrawingStyle | INTEGER | RW | dsNormal
DrawingStyle specifies the style to be used when the imagelist is drawing an image.
0 = dsFocused -- Draws the image blending 25% with the system highlight color. This only affects imagelists which contain masks.
1 = dsSelected -- Draws the image blending 50% with the system highlight color. This only affects imagelists which contain masks.
2 = dsNormal -- Draws the image using the color specified in the BkColor property. If the BkColor is clNone then the image is drawn transparently using the mask.
3 = dsTransparent -- Draws using the mask regardless of the BkColor setting.
GetBMP | ARRAY of IMAGES/BMP | R
GetBMP returns the image specified by their index.
Examples:
DIM ImageList AS QIMAGELIST
DIM Button AS QBUTTON

ImageList.AddBMPFile("whatever.bmp", 0)
Button.BMP = Imagelist.GetBMP(0)
GetICO | ARRAY of IMAGES/ICO | R
Handle | INTEGER | RW
Height | INTEGER | RW
ImageType | INTEGER | RW | itImage
ImageType determines whether the imagelist will use the image or the associated image mask when drawing.
Masked | INTEGER | RW | True
Masked specifies whether the imagelist contains transparent or non-transparent images.
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
Draw | SUB (QIMAGE/QBITMAP/QCANVAS/QDXSCREEN, X%, Y%, Index%) | Draw on canvas at (X,Y) with image index% in ImageList | 4
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-2000 Appendix A: QLABEL

QLABEL Component

QLabel is a non-windowed control used to display 2D, 3D, and/or rotated text on a form/container. Note that rotated labels only work with true type fonts.

QLabel Properties
Field | Type | R/W | Default | Support
Align | INTEGER | RW | alNone | W
Align determines how the control aligns within its parent control.
Alignment | INTEGER | RW | taLeftJustify | W
Alignment determines the horizontal placement of the text within the label.
0 = taLeftJustify -- The text appears lined up along the left edge of the label.
1 = taRightJustify -- The text appears lined up along the right edge of the label.
2 = taCenter -- The text is horizontally centered in the label.
Angle | INTEGER | RW | 0 | W
Angle determines how the label is rotated. Specify a degree from 0 to 360.
Autosize | INTEGER | RW | False | W
AutoSize determines whether the size of the label automatically resizes to accommodate the text.
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
LabelStyle | INTEGER | RW | tsNone | W
LabelStyle determines whether the label is displayed as 3D or 2D.
0 = lsNone -- The text appears as normal 2d text.
1 = lsRaised -- The text appears as 3d.
2 = lsRecessed -- The text appears engraved.
Layout | INTEGER | RW | tlTop | W
Layout determines the vertical placement of the text within the label.
0 = tlTop -- The text appears at the top of the label.
1 = tlCenter -- The text is vertically centered in the label.
2 = tlBottom -- The text appears along the bottom of the label.
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
Tag | INTEGER | RW | WXG
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-2000 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
Align determines how the control aligns within its parent control.
BorderStyle | INTEGER | RW | bsSingle | W
Color | INTEGER | RW | WX
Columns | INTEGER | RW | 0 | W
Columns specifies the number of columns, in a multi-column listbox, that are visible without having to scroll.
CopyMode | INTEGER | RW | cmBlackness | W
Cursor | INTEGER | RW | crDefault | W
Enabled | INTEGER | RW | True | WXG
ExtendedSelect | INTEGER | RW | True | WX
ExtendedSelect determines if the user can select a sequential range of items in the listbox.
Font | QFONT | W | W
Height | INTEGER | RW | WXG
Hint | STRING | RW | WXG
Item | ARRAY of STRING | RW | WXG
Item contains the strings that appear in the listbox.
ItemCount | INTEGER | R | WXG
ItemHeight | INTEGER | RW | W
ItemIndex | INTEGER | RW | WXG
Left | INTEGER | RW | 0 | WXG
MultiSelect | INTEGER | RW | False | WX
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
SelCount | INTEGER | R | W
Selected | ARRAY of INTEGER | RW | WX
ShowHint | INTEGER | RW | False | WXG
Sorted | INTEGER | RW | False | WG
Sorted specifies whether the items in a listbox are arranged alphabetically.
Style | INTEGER | RW | lbStandard | W
Style determines whether the listbox is standard or owner-draw.
0 = lbStandard -- All items are strings, with each item the same height.
1 = lbOwnerDrawFixed -- Each item in the listbox is the height specified by the ItemHeight property.
2 = lbOwnerDrawVariable -- Items in the listbox can be of varying heights.
TabOrder | INTEGER | RW | W
TabWidth | INTEGER | RW | 0 | W
Tag | INTEGER | RW | WXG
Text | STRING | RW | W
Text defines the items in the listbox as CRLF terminated strings.
Top | INTEGER | RW | 0 | WXG
TopIndex | INTEGER | RW | W
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
LoadFromFile | SUB (FileName AS STRING) | Load file to list | 1 | 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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7 | W
SaveToFile | SUB (FileName AS STRING) | Save list to file | 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 | 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-2000 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
     Checked AS INTEGER     '' If CheckBoxes is enabled and item is checked
     Handle AS INTEGER      '' Read-only
     ImageIndex AS INTEGER
     Index AS INTEGER       '' Read-only
     Selected 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
Align determines how the control aligns within its parent control.
BorderStyle | INTEGER | RW | bsSingle
CheckBoxes | INTEGER | RW | False
CheckBoxes specifies whether checkboxes appear next to the items in the listview.
Color | INTEGER | RW
Column | ARRAY of ColumnType | RW
ColumnClick | INTEGER | RW | True
ColumnClick determines whether the column header behaves like a button.
ColumnsCount | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
GridLines | INTEGER | RW | False
GridLines determines whether lines are drawn separating items in the list.
Handle | INTEGER | R
Height | INTEGER | RW
HideSelection | INTEGER | RW | False
HideSelection determines whether the listview gives a visual indication of which item is selected when focus shifts to another control.
Hint | STRING | RW
HotTrack | INTEGER | RW | False
HotTrack specifies whether list items are highlighted when the mouse passes over them.
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
RowSelect determines whether an entire row in the listview can be selected.
SelCount | INTEGER | RW
Selected | ARRAY of INTEGER | RW
ShowColumnHeaders | INTEGER | RW | True
ShowHint | INTEGER | RW | False
SmallImages | QIMAGELIST | W
SortType | INTEGER | RW | stNone
SortType determines if and how the items in the list are automatically sorted.
0 = stNone -- No sorting is done.
2 = stText -- Items are sorted according to their caption property.
StateImages | QIMAGELIST | W
SubItem | 2D ARRAY of STRING | RW
TabOrder | INTEGER | RW
Tag | 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-2000 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
Handle | INTEGER | R | W
Parent | QFORM | W | WXG

QMainMenu Methods
Method | Type | Description | Params | Support
AddItems | SUBI | Add items to mainmenu | QMENUITEMs, Infinite | WXG
DelIndex | SUB (index AS LONG) | Delete items, by index, from menu | 1 | W
DelItems | SUBI | Delete items from menu | QMENUITEMs, Infinite | W
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
LineCount determines how many lines there are in the memorystream. Note that LineCount ignores the CR character, and will only detect LF, so it treats CRLF as one line, but LFLF as 2 lines.
Pointer | INTEGER | R | WXG
Pointer specifies the memory address of the memorystream.
Position | INTEGER | RW | WXG
Position specifies the current position of the memory pointer, any read/write operations will begin from here.
Size | INTEGER | RW | WXG
Size determines the number of bytes allocated to the memorystream.

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 		2 WXG
Use CopyFrom to copy a QFILESTREAM or a QMEMORYSTREAM to the current memorystream.
Details:
If Bytes% = 0 then the Stream is reset to position 0 and the whole stream is then copied.
Example:
$INCLUDE "RAPIDQ.INC"
DIM File1 AS QFILESTREAM
DIM Mem AS QMEMORYSTREAM

File1.Open("test.txt", fmOpenRead)
Mem.CopyFrom(File1, 123) '-- Copy 123 bytes from File1
ExtractRes | SUB (Resource AS LONG) | Extract resource to memorystream | 1 | WXG
Extracts a resource from your program to the memorystream.
Details:
The parameter Resource is not the resource handle, but the absolute position of the resource within your file. This requires that you use the keyword Resource(n) to specify the resource number.
Example (dumping all resources):
$INCLUDE "RAPIDQ.INC"
$RESOURCE res_1 as "res.1"
$RESOURCE res_2 as "res.2"

DIM Mem AS QMEMORYSTREAM

FOR I = 0 TO ResourceCount-1
    Mem.ExtractRes(Resource(I))
NEXT
LoadArray | SUB (Array(), NumElements&) | Load data into array | 2 | WXG
MemCopyFrom | SUB (Address&, Bytes&) | Copies contents of Address& to memorystream | 2 | WXG
MemCopyTo | SUB (Address&, Bytes&) | Copies contents to Address& | 2 | WXG
Read | SUB (variable) | Generic Read, determines the storage space and saves data in variable | 1 | WXG
ReadLine | FUNCTION () AS STRING | Reads an entire line | 0 | W
ReadNum | FUNCTION (n) AS DOUBLE | Read n bytes, returns number | 1 | WXG
ReadStr | FUNCTION (n) AS STRING | Read n bytes, returns the string | 1 | WXG
ReadBinStr | FUNCTION (n) AS STRING | Read n bytes, returns the binary string | 1 | W
ReadUDT | SUB (MyType) | Read and store data in a MyType structure | 1 | WXG
SaveArray | SUB (Array(), NumElements&) | Save array | 2 | WXG
Seek | SUB (Position%, From%) | Seek to Position%, From% see RAPIDQ.INC | 2 | WXG
Write | SUB (variable) | Generic Write, determines the storage space and saves data to memory | 1 | 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

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

  DIM Mem AS QMemoryStream
  DIM I AS INTEGER

  I = 12
  Mem.Write(I)
  S$ = "Hello world!"
  Mem.Write(S$)
  Mem.Position = 0
  Mem.Read(I)
  S$ = SPACE$(I)
  Mem.Read(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(Person)


Appendix A: QMENUITEM

Rapid-Q Documentation by William Yu (c)1999-2000 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
Caption specifies the text of the menu item.
Checked | INTEGER | RW | W
Checked specifies whether a check mark should appear beside the caption.
Command | INTEGER | R | W
Command is the Windows command ID associated with the menu item.
Count | INTEGER | R | W
Count is the number of subitems of the menu item.
Enabled | INTEGER | RW | True | W
Handle | INTEGER | R | W
Hint | STRING | RW | W
MenuIndex | INTEGER | RW | W
MenuIndex is index of the menu item within its parent menu.
RadioItem | INTEGER | RW | False | W
RadioItem specifies whether the menu item is mutually exclusive with other menu items in its group.
ShortCut | STRING | RW | W
ShortCut specifies the key combination users can type to quickly access the menu item.
Tag | INTEGER | RW | WXG
Visible | INTEGER | RW | True | W
Visible determines whether the menu item should be displayed.

QMenuItem Methods
Method | Type | Description | Params | Support
AddItems | SUBI | Add Subitems to MenuItem | QMENUITEMs, Infinite | WXG
DelIndex | SUB (index AS LONG) | Delete items, by index, from menu | 1 | W
DelItems | SUBI | Delete items from menu | QMENUITEMs, Infinite | W
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-2000 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
Connected specifies whether you are currently connected to a MySQL server. Use the Connect method to establish a connection.
DB | ARRAY of STRING | R | WXG
DB returns a database list that are currently available on the MySQL server.
DBCount | INTEGER | R | WXG
DBCount returns the number of databases that are currently available on the MySQL server.
ColCount | INTEGER | R | WXG
ColCount returns the number of columns in the table. ColCount is used after an SQL query to determine the number of columns in the resulting table.
FieldCount | INTEGER | R | WXG
FieldCount returns the number of columns in the table. FieldCount is used after an SQL query to determine the number of columns in the resulting table.
Field.Decimals | INTEGER | R | WXG
Field.Decimals returns the number of decimals in the field.
Field.Flags | INTEGER | R | WXG
Field.Flags returns the flag settings. Refer to MYSQL.INC for supported values.
Field.Length | INTEGER | R | WXG
Field.Length returns the width of the column.
Field.MaxLength | INTEGER | R | WXG
Field.MaxLength returns the maximum width of the selected set. A result set can have multiple fields (or columns), Field.MaxLength returns the largest of these.
Field.Name | STRING | R | WXG
Field.Name returns the name of the column.
Field.Table | STRING | R | WXG
Field.Type | INTEGER | R | WXG
Field.Type returns the type of field. Refer to MYSQL.INC for supported values.
Length | ARRAY of INTEGER | R | WXG
Length returns the length of each field. Make sure a call to FetchLengths is made.
Row | ARRAY of STRING | R | WXG
Row returns the value stored in the particular Row for the current result set. The value is also dependent on the Field (or column). For example, Row(3) returns the value stored in Row 3 and whatever Column, ie. 2. Which is different from Row(3) of Column 3 for example.
RowCount | INTEGER | R | WXG
Table | ARRAY of STRING | R | WXG
Table returns a list of tables for the current database.
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
' 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: QOLEOBJECT

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

QOLEOBJECT Component

QOleObject implements an automation client. Type checking is disabled for this component, see examples on how this can help you. This component is currently in an experimental stage. Longs, Doubles, and Strings are currently supported, other data types may be added later.

QOleObject Properties
Field Type R/W Default

QOleObject Methods
Method | Type | Description | Params
Container | QOLECONTAINER | W
CreateObject | FUNCTION (ClassName AS STRING) AS INTEGER | Create COM object, with actual name or CLSID | 1
CreateRemote | FUNCTION (Host AS STRING, ClassName AS STRING) AS INTEGER | Create remote COM object, with actual name or CLSID | 2
Free | SUB | Release object | 0
GetIDofName | FUNCTION (Name AS STRING) AS INTEGER | Returns the ID of an identifier, good for checking if it exists. Returns -1 if name is not found. | 1
GetObject | FUNCTION (ClassName AS STRING) AS INTEGER | Get active COM object, with actual name or CLSID | 1
Invoke | FUNCTIONI (ID AS STRING, Params, ...) AS VARIANT | Invoke method/property | Infinite
InvokeCopy | SUB (ID AS STRING, Object AS QOLEOBJECT) | Copy object (might not work... yet) | 2

QOleObject Events
Event Type Occurs when... Params

QOleObject Examples
' This example requires MS WORD
' If you're using a localized version with a foreign language,
' you'll have to adjust the parameter names to match.
' Comments in italics indicate the old style syntax before
' type checking was disabled.  You can choose either approach.

$ESCAPECHARS ON

DIM Object AS QOLEOBJECT

'Object.CreateObject("{000209FE-0000-0000-C000-000000000046}")
Object.CreateObject("Word.Basic")
'Object.Invoke("AppShow")
Object.AppShow
'Object.Invoke("AppMaximize", "", 1)
Object.AppMaximize("", 1)
'Object.Invoke("FileNew")
Object.FileNew

PRINT Object.Bold  '-- is bold enabled?

Object.Insert("Hello world!\n")
Object.Bold

PRINT Object.Bold  '-- Bold should be enabled

Object.Insert("Rapid-Q is awesome!\n")
Object.Bold(0)     '-- Turn Bold off

SLEEP 5

Object.Free


Appendix A: QOLECONTAINER

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

QOLECONTAINER Component

QOleContainer is an ActiveX container whose properties and methods can be accessed similar to QOleObject.

QOleContainer Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
AllowInPlace | INTEGER | RW | True
AutoShow | INTEGER | RW | True
BorderStyle | INTEGER | RW | bsSingle
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Handle | INTEGER | R
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW | 0
Modified | INTEGER | RW | False
Parent | QFORM/QPANEL/QTABCONTROL | W
ShowHint | INTEGER | RW | False
SizeMode | INTEGER | RW | smClip
State | INTEGER | RW | osEmpty
TabOrder | INTEGER | RW
Tag | INTEGER | RW
Top | INTEGER | RW | 0
Width | INTEGER | RW
Visible | INTEGER | RW | True

QOleContainer Methods
Method | Type | Description | Params
CreateObject | FUNCTION (ClassName AS STRING) AS INTEGER | Create new embedded object | 1
Free | SUB | Release object | 0
Invoke | FUNCTIONI (ID AS STRING, Params, ...) AS VARIANT | Invoke method/property | Infinite

QOleContainer Events
Event | Type | Occurs when... | Params
OnKeyDown | SUB (Key AS Word, Shift AS INTEGER) | Key held down | 2
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1
OnKeyUp | SUB (Key AS Word, Shift AS INTEGER) | User releases a key | 2
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
OnObjectMove | SUB (Rect AS QRECT) | OLE Object has moved or resized | 1
OnResize | VOID | After OLE container is resized | 0

QOleContainer Examples
' This example requires GIF89.DLL which can be found on
' Rapid-Q's knowledge base page.
' Make sure to register the .DLL if you haven't already
' c:\blah> regsvr32 gif89.dll

' Note, example works best if you load an animated GIF file.

CREATE Form AS QFORM
    Caption = "Animated GIFs"
    Center
    Visible = 1
    CREATE GifAnimation AS QOLECONTAINER
        Align = alClient
        CreateObject("Gif89.Gif89.1")
        '-- FileName is a property in GIF89.DLL
        FileName = "anim.gif"
    END CREATE
    Visible = 0
END CREATE

Form.ShowModal

GifAnimation.Free


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
Handle | INTEGER | R
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
Tag | 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
Tag | INTEGER | RW | WXG
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
Tag | INTEGER | RW | WXG
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-2000 Appendix A: QPOPUPMENU

QPOPUPMENU Component

QPopupMenu provides a popup menu selection control

QPopupMenu Properties
Field | Type | R/W | Default
Alignment | INTEGER | RW | paLeft
Alignment determines where the pop-up menu appears when the user clicks the right mouse button.
0 = paLeft - Pop-up menu appears with its top left corner under the mouse pointer
1 = paRight = Pop-up menu appears with its top right corner under the mouse pointer
2 = paCenter - Pop-up menu appears with the top center of the menu under the mouse pointer
AutoPopup | INTEGER | RW | True
AutoPopup determines whether the pop-up menu appears automatically when the user clicks the right mouse button.
Handle | INTEGER | R
Handle is the Windows menu handle for the menu.
Tag | INTEGER | RW
Tag stores an integer value, but is not used internally.
WindowHandle | INTEGER | RW
WindowHandle is the handle of the window that uses the menu.

QPopupMenu Methods
Method | Type | Description | Params
AddItems | SUBI | Add Item to Menu | QMENUITEMs, Infinite
DelIndex | SUB (index AS LONG) | Delete items, by index, from menu | 1
DelItems | SUBI | Delete items from 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
OnPopup | VOID | Just before the pop-up menu appears | 0

QPopupMenu Examples
  DIM PopupMenu AS QPopupMenu
  DIM Item1 AS QMenuItem
  DIM Item2 AS QMenuItem

  Item1.Caption = "Item 1"
  Item2.Caption = "Item 2"
  PopupMenu.AddItems(Item1, Item2)

  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
Tag | INTEGER | RW | WXG
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-2000 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
Align determines how the control aligns within its parent control.
Alignment | INTEGER | RW | taLeftJustify | W
Alignment determines how the text is aligned within the edit control.
BorderStyle | INTEGER | RW | bsSingle | W
Color | INTEGER | RW | W
Enabled | INTEGER | RW | True | WXG
Font | QFONT | W | WX
Handle | INTEGER | R | W
Height | INTEGER | RW | WXG
HideScrollBars | INTEGER | RW | True | WG
HideSelection | INTEGER | RW | True | W
Hint | STRING | RW | WG
Left | INTEGER | RW | 0 | WXG
Line | ARRAY of STRING | RW | WXG
LineCount | INTEGER | RW | WXG
Modified | INTEGER | R | WG
Parent | QFORM/QPANEL/QTABCONTROL | W | WXG
PopupMenu | QPOPUPMENU | W | W
Plaintext | INTEGER | RW | False | W
Readonly | INTEGER | RW | False | WXG
ScrollBars | INTEGER | RW | ssNone | WXG
SelAttributes | QFONT | W | W
SelLength | INTEGER | RW | WXG
SelLength is the number of characters that are selected.
SelStart | INTEGER | RW | WXG
SelStart is the position of the first selected character in the text. If there is no selected text, SelStart indicates the position of the cursor.
SelText | STRING | RW | WXG
SelText is the selected portion of the edit control's text.
ShowHint | INTEGER | RW | False | WG
TabOrder | INTEGER | RW | W
Tag | INTEGER | RW | WXG
Text | STRING | RW | WXG
Top | INTEGER | RW | 0 | WXG
WantTabs | INTEGER | RW | False | W
WantTabs determines whether the user can insert tab characters into the text.
Width | INTEGER | RW | WXG
WhereX | INTEGER | R | WXG
WhereY | INTEGER | R | WXG
Wordwrap | INTEGER | RW | True | W
Visible | INTEGER | RW | True | WXG

QRichedit Methods
Method | Type | Description | Params | Support
AddStrings | SUBI | Add strings | STRING, Infinite | WXG
Clear | SUB | Clear entire text | 0 | WXG
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 | WXG
LoadFromStream | SUB (Stream AS QFILESTREAM/QMEMORYSTREAM) | Load text from a stream | 1 | WX
PasteFromClipboard | SUB | Paste text from clipboard | 0 | W
SaveToFile | SUB (FileName$) | Save text to a file | 1 | WXG
SaveToStream | SUB (Stream AS QFILESTREAM/QMEMORYSTREAM) | Save text to a stream | 1 | W
SelectAll | SUB | Selects all text from Richedit | 0 | WXG

QRichedit Events
Event | Type | Occurs when... | Params | Support
OnChange | VOID | Text changes | 0 | WG
OnKeyDown | SUB (Key AS WORD, Shift AS INTEGER) | Key held down | 2 | WG
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1 | WG
OnKeyUp | SUB (Key AS WORD, Shift AS INTEGER) | Key released | 2 | WG
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-2000 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
Align determines how the control aligns within its parent control.
Cursor | INTEGER | RW | crDefault | W
Enabled | INTEGER | RW | True | WX
Handle | INTEGER | R | W
Height | INTEGER | RW | WX
Hint | STRING | RW | WX
Kind | INTEGER | RW | sbHorizontal | WX
Kind specifies whether the scrollbar is horizontal or vertical.
0 = sbHorizontal -- Scrollbar is horizontal.
1 = sbVertical -- Scrollbar is vertical.
LargeChange | INTEGER | RW | 1 | WX
LargeChange determines how much Position changes when the user clicks on the scrollbar on either side of the thumb or pressed PageUp or PageDown.
Left | INTEGER | RW | 0 | WX
Max | INTEGER | RW | 100 | WX
Min | INTEGER | RW | 0 | WX
PageSize | INTEGER | RW | 1 | W
PageSize specifies the distance along the trackbar.
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
SmallChange determines how much Position changes when the user clicks the arrow buttons on the scrollbar or presses the arrow keys.
TabOrder | INTEGER | RW | W
Tag | INTEGER | RW | WXG
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.
'' And quite useless because an RGB function is already implemented!
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-2000 Appendix A: QSCROLLBOX

QSCROLLBOX Component

QScrollBox is a scrolling window control.

QScrollBox Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
Align determines how the control aligns within its parent control.
AutoScroll | INTEGER | RW | True
AutoScroll specifies whether scrollbars appear automatically on the scrolling windowed control if it is not large enough to display all of its controls.
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
HorzIncrement determines how far the display moves when the user clicks one of the small end arrows on the scrollbar.
HorzMargin | INTEGER | RW | 0
HorzMargin specifies the minimum number of pixels that must separater each control from the edge of the scrollbox.
HorzPosition | INTEGER | RW | 0
HorzPosition specifies the position of the thumb tab on the scrollbar.
HorzRange | INTEGER | RW | 0
HorzRange determines how far the scrollbox can move.
HorzTracking | INTEGER | RW | False
HorzTracking determines whether the scrollbox moves before the thumb tab is released.
HorzVisible | INTEGER | RW | True
Left | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
Tag | 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

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

QScrollBox 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-2000 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
Family specifies the address family.
LParam | INTEGER | RW | FD_CONNECT | W
LParam specifies the message to capture when you set WMessage and handle the message processing by assigning a new WndProc to your form.
MySocket | INTEGER | R | WXG
MySocket stores the result of operations such as Open. So instead of using the return value of Open, you can use the property MySocket.
Parent | QFORM | W | W
Protocol | INTEGER | RW | IPPROTO_IP | W
Tag | INTEGER | RW | WXG
Transferred | INTEGER | R | WXG
Type | INTEGER | RW | SOCK_STREAM | W
WMessage | INTEGER | RW | 0 | W
WMessage specifies a user defined message to be passed to your form for non-blocking calls, ie. Connecting.

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
ReadByte | FUNCTION (Socket%) AS BYTE | Read a single byte | 2 | WXG
ReadLine | FUNCTION Message$(Socket%) | Read complete line | 1 | WXG
Write | SUB (Socket%, Message$, NumBytes%) | Sends NumBytes% from Message$ | 3 | WXG
WriteByte | SUB (Socket%, B AS BYTE) | Sends a single byte | 2 | 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-2000 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
Align determines how the control aligns within its parent control.
Beveled | INTEGER | RW | True
Beveled determines whether the splitter looks beveled along the edge that moves.
ClientHeight | INTEGER | RW
ClientWidth | INTEGER | RW
Color | INTEGER | RW
Cursor | INTEGER | RW | crHSplit
Enabled | INTEGER | RW | True
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW
MinSize | INTEGER | RW | 30
MinSize is the minimum size, in pixels, of the client area the splitter must leave on the form.
Parent | QFORM/QPANEL/QTABCONTROL | W
ShowHint | INTEGER | RW | False
Tag | INTEGER | RW
Top | INTEGER | RW
Visible | INTEGER | RW | True
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-2000 Appendix A: QSTATUSBAR

QSTATUSBAR Component

QStatusBar implements a Windows status bar.

QStatusBar Internal Types
   TYPE PanelType           '' ie. StatusBar.Panel(0).Caption
     Alignment AS INTEGER   '' Specifies the text alignment, default is taLeftJustify
     Caption AS STRING
     Width AS INTEGER
   END TYPE
QStatusBar Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alBottom
Align determines how the control aligns within its parent control.
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Handle | INTEGER | R
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
SimplePanel determines whether the statusbar displays a single panel or multiple panels.
SimpleText | STRING | RW
SimpleText contains the string that is displayed in the statusbar when SimplePanel is true.
SizeGrip | INTEGER | RW | True
SizeGrip determines whether the statusbar is resizable at runtime.
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-2000 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
Align determines how the control aligns within its parent control.
BorderStyle | INTEGER | RW | bsSingle
Cell | 2D ARRAY of STRING | RW
Cell(X, Y) is an array of strings, one string for each cell in the grid.
X = Column, Y = Row
Col | INTEGER | RW
Col is the index of the column that contains the selected cell.
ColCount | INTEGER | RW | 5
Color | INTEGER | RW
ColumnList | ARRAY of STRING | RW
ColumnList maintains a list of strings deliminated by LF for use in Columned lists.
ColumnStyle | ARRAY of INTEGER | RW | gcsNone
ColumnStyle determines the style of each column.
0 = gcsList -- Column with a drop-down list for each item
1 = gcsEllipsis -- Column with an ellipsis button for each item
2 = gcsNone -- Normal column
ColWidths | ARRAY of INTEGER | RW
ColWidths is an indexed array giving the width in pixels of all the columns in the grid.
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
FixedColss is the number of columns on the left of the grid that cannot be scrolled.
FixedRows | INTEGER | RW | 1
FixedRows is the number of rows on the top of the grid that cannot be scrolled.
Font | QFONT | W
GridHeight | INTEGER | RW
GridLineWidth | INTEGER | RW | 1
GridWidth | INTEGER | RW
Handle | INTEGER | R
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW | 0
LeftCol | INTEGER | RW
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
Row | INTEGER | RW
Row is the index of the row that contains the selected cell.
RowCount | INTEGER | RW | 5
RowHeights | ARRAY of INTEGER | RW
RowHeights is an indexed array giving the height in pixels of all the rows in the grid.
ScrollBars | INTEGER | RW | ssBoth
Separator | STRING | RW
Separator determines how the stringgrid should parse (ie. read/write) grid data. For example, you can save the grid data to a file, with each item deliminated by the Separator.
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
TabStops | ARRAY of INTEGER | RW
Tag | 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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7
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
OnEllipsisClick | SUB (Col%, Row%) | Pull down list is clicked | 2
OnKeyDown | SUB (Key AS Word, Shift AS INTEGER) | Key held down | 2
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1
OnKeyUp | SUB (Key AS Word, Shift AS INTEGER) | User releases a key | 2
OnListDropDown | SUB (Col%, Row%, BYREF S AS STRING) | Pull down list is clicked. S is a string with items separated by a new line character. | 3
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

'------------------------------------------------------------------
' Pulldown list example

$INCLUDE "RAPIDQ.INC"
$ESCAPECHARS ON

CONST AgeList = "10\n11\n12\n13\n14\n15\n16\n17\n18\n19"

SUB EllipsisClick (Col AS LONG, Row AS LONG, Sender AS QSTRINGGRID)
    Sender.Cell(Col, Row) = "Comments"+STR$(Row)
END SUB

CREATE Form AS QFORM
    CREATE Grid AS QSTRINGGRID
        Align = alClient
        AddOptions(goEditing)
        FixedRows = 1
        FixedCols = 0
        ColCount = 3
        RowCount = 5
        DefaultRowHeight = 20
        ColumnStyle(0) = gcsList
        ColumnStyle(1) = gcsEllipsis
        ColumnList(0) = AgeList
        Cell(0,0) = " Age"
        Cell(1,0) = " Comments"
        OnEllipsisClick = EllipsisClick
    END CREATE
    Caption = "Dropdown list example"
    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 | Support
Duplicates | INTEGER | RW | dupIgnore | W
Item | ARRAY of STRING | RW | WXG
ItemCount | INTEGER | R | WXG
Sorted | INTEGER | RW | False | W
Text | STRING | RW | WXG

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

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
Tag | 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-2000 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
Interval determines the amount of time, in milliseconds, that passes before the timer component initiates another OnTimer event.
Tag | 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-2000 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
Align determines how the control aligns within its parent control.
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Frequency | INTEGER | RW
Frequency specifies the increment between tick marks on the trackbar.
Handle | INTEGER | R
Height | INTEGER | RW
Hint | STRING | RW
Left | INTEGER | RW | 0
LineSize | INTEGER | RW | 1
LineSize is the amount the value of Position changes when the user presses the arrow keys.
Max | INTEGER | RW | 10
Max specifies the maximum Position of the trackbar.
Min | INTEGER | RW | 0
Min specifies the minimum Position of the trackbar.
Orientation | INTEGER | RW | tbHorizontal
Orientation specifies whether the trackbar is horizontal or vertical.
0 = tbHorizontal -- Min position is on the left, Max is on the right.
1 = tbVertical -- Min position is on the top, Max is on the bottom.
PageSize | INTEGER | RW | 2
PageSize specifies the amount Position is changed when the PageUp or PageDown key is pressed, or when the bar is clicked.
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
Position | INTEGER | RW
Position contains the current position of the slider.
SelEnd | INTEGER | RW
SelEnd specifies the position of the end point of the selection range.
SelStart | INTEGER | RW
SelStart specifies the position of the starting point of the selection range.
ShowHint | INTEGER | RW | False
TabOrder | INTEGER | RW
TickMarks | INTEGER | RW | tmBottomRight
TickMarks specifies the location of the tick marks.
0 = tmBottomRight -- Tick marks are on the bottom or right of the trackbar depending on the value of Orientation.
1 = tmTopLeft -- Tick marks are on the top or left of the trackbar depending on the value of Orientation.
2 = tmBoth -- Tick marks are on both sides of the trackbar.
TickStyle | INTEGER | RW | tsAuto
TickStyle specifies how tick marks are place on the trackbar.
0 = tsNone -- No tick marks are displayed.
1 = tsAuto -- Trackbar displays tick marks automatically for each increment in its range.
2 = tsManual -- Trackbar displays tick marks at either end. Use SetTick to set a tick in other positions
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 A: QTREEVIEW

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

QTREEVIEW Component

QTreeView displays a hierarchical list of items. Items are ordered by their index.

QTreeView Internal Types
   TYPE TreeNodeType           '' ie. TreeView.Item(0).Text
     Text AS STRING
     ImageIndex AS INTEGER
     StateIndex AS INTEGER
     SelectedIndex AS INTEGER
     Count AS INTEGER          '' Read only
     Level AS INTEGER          '' Read only
     IsVisible AS INTEGER      '' Read only
     Handle AS INTEGER         '' Read only
     HasChildren AS INTEGER
     Selected AS INTEGER
   END TYPE
QTreeView Properties
Field | Type | R/W | Default
Align | INTEGER | RW | alNone
BorderStyle | INTEGER | RW | bsSingle
Color | INTEGER | RW
Cursor | INTEGER | RW | crDefault
Enabled | INTEGER | RW | True
Font | QFONT | W
Handle | INTEGER | RW
Height | INTEGER | RW
HideSelection | INTEGER | RW | False
Hint | STRING | RW
Images | QIMAGELIST | W
Indent | INTEGER | RW | 19
Item | ARRAY of TreeNodeType | RW
ItemCount | INTEGER | RW
ItemIndex | INTEGER | RW
Left | INTEGER | RW | 0
Parent | QFORM/QPANEL/QTABCONTROL | W
PopupMenu | QPOPUPMENU | W
ReadOnly | INTEGER | RW | False
ShowButtons | INTEGER | RW | True
ShowHint | INTEGER | RW | False
ShowLines | INTEGER | RW | True
ShowRoot | INTEGER | RW | True
SortType | INTEGER | RW | stText
StateImages | QIMAGELIST | W
TabOrder | INTEGER | RW
Tag | INTEGER | RW
Top | INTEGER | RW | 0
TopIndex | INTEGER | RW
Width | INTEGER | RW
Visible | INTEGER | RW | True

QTreeView Methods
Method | Type | Description | Params
AddItems | SUBI | Add items to treeview | STRING, Infinite
AddChildItems | SUB (Index%, S1$, S2$, ...) | Add child item at Index% | Minimum 2
Clear | SUB | Clear all items in treeview | 0
Collapse | SUB (Index%, Recurse%) | Collapses node | 2
DelItems | SUBI | Delete items from treeview | INTEGER, Infinite
Expand | SUB (Index%, Recurse%) | Expand node, revealing its childs | 2
FullCollapse | SUB | Collapses all nodes | 0
FullExpand | SUB | Expands all nodes | 0
GetItemAt | FUNCTION (X%, Y%) AS LONG | Get the index node at X,Y | 2
InsertItem | SUB (Index%, String$) | Insert item at Index% | 2
LoadFromFile | SUB (Filename AS STRING) | Load items from file | 1
SaveToFile | SUB (Filename AS STRING) | Save items to file | 1
Sort | SUB | Sort all items from A-Z | 0

QTreeView Events
Event | Type | Occurs when... | Params
OnClick | VOID | TreeView was clicked on | 0
OnChange | SUB (Index%) | Selection (not modification) has changed from one item to another | 1
OnChanging | SUB (Index%, AllowChange%) | Selection is about to be changed | 2
OnCollapse | SUB (Index%) | Just after a node has been collapsed | 1
OnCollapsing | SUB (Index%, AllowCollapse%) | A node is about to be collapsed | 2
OnDblClick | VOID | TreeView was double clicked on | 0
OnDeletion | SUB (Index%) | A node in the tree is deleted | 1
OnEdited | SUB (Index%, BYREF S$) | After the user edits a text of a node | 2
OnEditing | SUB (Index%, AllowEdit%) | The user starts to edit the text | 2
OnExpand | SUB (Index%) | After a node is expanded | 1
OnExpanding | SUB (Index%, AllowExpansion%) | A node is about to be expanded | 2
OnGetImageIndex | SUB (Index%) | The treeview looks up the ImageIndex of a node | 1
OnGetSelectedIndex | SUB (Index%) | The treeview looks up the SelectedIndex of a node | 1
OnKeyDown | SUB (Key AS Word, Shift AS INTEGER) | Key held down | 2
OnKeyPress | SUB (Key AS BYTE) | User presses a key | 1
OnKeyUp | SUB (Key AS Word, Shift AS INTEGER) | User releases a key | 2
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

QTreeView Examples
'' Tree view example, hot tracking through items

SUB TreeViewChange (Node AS INTEGER, AllowChange AS INTEGER, Sender AS QTREEVIEW)
    IF Node = 8 THEN AllowChange = 0
END SUB

SUB TreeViewMouseMove (X AS INTEGER, Y AS INTEGER, Shift AS INTEGER, Sender AS QTREEVIEW)
    I = Sender.GetItemAt(X,Y)
    IF I >= 0 THEN Sender.ItemIndex = I
END SUB

CREATE Form AS QFORM
    Center
    CREATE TreeView AS QTREEVIEW
        Align = 5
        AddItems "1","2","3"
        AddChildItems 0, "Sub 1", "Sub 2", "Sub 3"
        AddChildItems 4, "Sub 1", "Sub 2", "Sub 3"
        FullExpand
        OnChanging = TreeViewChange
        OnMouseMove = TreeViewMouseMove
    END CREATE
END CREATE

'-- No real purpose, just change all items
FOR I = 0 TO TreeView.ItemCount-1
    TreeView.Item(I).Text = STR$(I)
NEXT

Form.ShowModal


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 imagelist | 1
LoadFromResource | SUB (Resource_Handle) | Load imagelist from resource handle | 1
LoadFromStream | SUB (Stream AS QFILESTREAM/QMEMORYSTREAM) | Load imagelist from stream | 1

QDXImageList Events
Event Type Occurs when... Params

QDXImageList Examples
' Target practise w/DirectX for Rapid-Q by William Yu
' Move using arrow keys, to shoot, press SPACEBAR

$APPTYPE GUI
$TYPECHECK ON
$INCLUDE "RAPIDQ.INC"
$RESOURCE ships_DXG AS "ships.dxg"

DECLARE SUB DXTimerExpired
DECLARE SUB InitStars
DECLARE SUB KeyDown (Key AS BYTE, Shift AS BYTE)

CONST ScreenX = 400
CONST ScreenY = 300
CONST MaxStars = 150        '' Depending on your system, adjust as needed.

TYPE StarType
  X(MaxStars) AS INTEGER
  Y(MaxStars) AS INTEGER
  Z(MaxStars) AS INTEGER
END TYPE

DIM DXTimer AS QDXTimer
    DXTimer.Enabled = True
    DXTimer.Interval = 10
    DXTimer.OnTimer = DXTimerExpired
DIM Stars AS StarType
DIM MyShipX AS INTEGER
    MyShipX = 50
DIM EnemyShipX AS INTEGER
    EnemyShipX = ScreenX + 45
DIM EnemyShipY AS INTEGER
    EnemyShipY = 20
DIM Shoot AS INTEGER, ShootX AS INTEGER, ShootY AS INTEGER
    Shoot = False
DIM Hit AS INTEGER, HitCount AS INTEGER
    Hit = False

InitStars

CREATE Form AS QForm
  Center
  Caption = "DirectX Target Practise"
  ClientWidth = ScreenX
  ClientHeight = ScreenY
  'BorderStyle = bsNone           '' Setup fullscreen
  CREATE DXScreen AS QDXScreen
    Init(ScreenX, ScreenY)
    Align = alClient
    'FullScreen = True            '' Fullscreen mode
    Cursor = crNone              '' Hide Mouse
    CREATE DXImageList AS QDXImageList
      LoadFromResource(SHIPS_DXG)
    END CREATE
  END CREATE
  OnKeyDown = KeyDown
  ShowModal
END CREATE

SUB KeyDown (Key AS BYTE, Shift AS BYTE)
  SELECT CASE Key
    CASE 27
      Form.Close
    CASE 39
      MyShipX = MyShipX + 4
    CASE 37
      MyShipX = MyShipX - 4
    CASE IS = 32 AND Shoot = False
      Shoot = True
      ShootX = MyShipX + 20
      ShootY = ScreenY - 58
  END SELECT
END SUB

SUB InitStars
  DIM I AS INTEGER

  RANDOMIZE TIMER

  FOR I = 1 TO MaxStars
    Stars.X(I) = RND(ScreenX)
    Stars.Y(I) = RND(ScreenY)
    Stars.Z(I) = RND(3)
  NEXT I
END SUB

SUB DXTimerExpired
  DIM I AS INTEGER

  DXScreen.Fill(0)
  FOR I = 1 TO MaxStars
    SELECT CASE Stars.Z(I)
      CASE 0
        DXScreen.Pixel(Stars.X(I),Stars.Y(I)) = clWhite
        Stars.Y(I) = Stars.Y(I) + 3
      CASE 1
        DXScreen.Pixel(Stars.X(I),Stars.Y(I)) = &HAAAAAA
        Stars.Y(I) = Stars.Y(I) + 2
      CASE ELSE
        DXScreen.Pixel(Stars.X(I),Stars.Y(I)) = &H555555
        Stars.Y(I) = Stars.Y(I) + 1
    END SELECT
    IF Stars.Y(I) > ScreenY THEN
      Stars.Y(I) = -1
      Stars.X(I) = RND(ScreenX)
    END IF
  NEXT I
  DXScreen.TextOut(10,10,"FPS: "+STR$(DXTimer.FrameRate), clWhite, -1)
  IF Hit THEN
    DXScreen.Circle(ShootX-HitCount/2,ShootY-20,ShootX+4+HitCount/2,ShootY-20+4+HitCount,&H2090FF,&H2090FF)
    IF HitCount = 0 THEN
      Hit = False
    ELSE
      HitCount = HitCount - 2
    END IF
  ELSE
    IF Shoot THEN
      SELECT CASE ShootX
        CASE EnemyShipX TO EnemyShipX+45
          IF ShootY > EnemyShipY AND ShootY < EnemyShipY+45 THEN
            EnemyShipX = ScreenX + 45
            EnemyShipY = EnemyShipY + 45
            Shoot = False
            Hit = True
            HitCount = 40
          END IF
      END SELECT
      DXScreen.Circle(ShootX,ShootY,ShootX+4,ShootY+4,&H2090FF,&H2090FF)
      IF ShootY < -4 THEN
         Shoot = False
      ELSE
         ShootY = ShootY - 4
      END IF
    END IF
    EnemyShipX = EnemyShipX - 2
    DXImageList.Draw(1, EnemyShipX, EnemyShipY, 0)
    IF EnemyShipX < -45 THEN
      EnemyShipX = ScreenX + 45
      EnemyShipY = EnemyShipY + 45
    END IF
  END IF
  DXImageList.Draw(0, MyShipX, ScreenY - 55, 0)
  DXScreen.Flip
END SUB


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
RoundRect | SUB (x1%, y1%, x2%, y2%, x3%, y3%, c%) | Draws & Fills a rounded rectangle | 7
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: QDXSOUND

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

QDXSOUND Component

QDXSound implements DirectSound.

QDXSound Properties
Field | Type | R/W | Default
AutoUpdate | INTEGER | RW | True
AutoUpdate determines whether to let the internal thread update the sound buffer every 50ms, or let the programmer control the updates.
BufferLength | INTEGER | RW | 1000
BufferLength specifies how many bytes to read into the buffer for playing. For heavy computations or deeply nested loops, it's a good idea to extend the BufferLength so that the music can play uninterrupted.
FileName | STRING | RW
FileName specifies the .WAV file.
Frequency | INTEGER | RW
Frequency specifies the reproduction frequency. Do not set the frequency before loading a file, since a default frequency for the .WAV file will be given to you when you load a new sound file.
Looped | INTEGER | RW | False
Looped specifies whether to replay the sound file after it has finished playing.
Pan | INTEGER | RW | 0
Pan specifies the relative volume of the right and left channels within the range from -100 to 100. A value of -100 mutes the right channel, and a value of 100 mutes the left channel.
Parent | QFORM | W
Playing | INTEGER | R
Playing determines whether the sound file is currently playing.
Position | INTEGER | RW
Use Position to set/get the current playing position of the sound file.
Size | INTEGER | R
Size returns the file size of the .WAV file in bytes.
StickyFocus | INTEGER | RW | False
StickyFocus determines whether to keep playing even if the application loses focus.
Tag | INTEGER | RW
Tag is not used internally, it is reserved storage space for the programmer.
Volume | INTEGER | RW
Volume specifies the output volume for the current sound as a percentage. Setting volume to 0 mutes the sound, while setting volume to 100 plays the sound with "normal volume" (ie. your current sound settings for your computer).

QDXSound Methods
Method | Type | Description | Params
Play | SUB | Start playing sound | 0
Stop | SUB | Stop playing sound | 0
Update | SUB | Update sound buffer | 0

QDXSound Events
Event Type Occurs when... Params

QDXSound Examples
'-- DirectSound example for Rapid-Q by William Yu

$TYPECHECK ON
$INCLUDE "RAPIDQ.INC"

DECLARE SUB exitItemClick (sender AS QMENUITEM)
DECLARE SUB openItemClick (sender AS QMENUITEM)
DECLARE SUB formShow (sender AS QFORM)
DECLARE SUB playButtonClick (sender AS QBUTTON)
DECLARE SUB stopButtonClick (sender AS QBUTTON)
DECLARE SUB positionTrackBarChange (sender AS QTRACKBAR)
DECLARE SUB freqTrackBarChange (sender AS QTRACKBAR)
DECLARE SUB volumeTrackBarChange (sender AS QTRACKBAR)
DECLARE SUB panTrackBarChange (sender AS QTRACKBAR)

CREATE form AS QFORM
    width = 360
    height = 300
    center
    CREATE dxSound AS QDXSOUND
    END CREATE
    CREATE mainMenu AS QMAINMENU
        CREATE fileMenu AS QMENUITEM
            caption = "&File"
            CREATE openItem AS QMENUITEM
                caption = "&Open..."
                onClick = openItemClick
            END CREATE
            CREATE breakItem1 AS QMENUITEM
                caption = "-"
            END CREATE
            CREATE exitItem AS QMENUITEM
                caption = "E&xit"
                onClick = exitItemClick
            END CREATE
        END CREATE
    END CREATE
    CREATE panTrackBar AS QTRACKBAR
        left = 10
        top = 10
        width = 200
        height = 30
        tickStyle = tsManual
        min = -100
        max = 100
        onChange = panTrackBarChange
        enabled = FALSE
    END CREATE
    CREATE panLabel AS QLABEL
        left = 215
        top = 20
        caption = "Pan 0dB"
    END CREATE
    CREATE volumeTrackBar AS QTRACKBAR
        left = 10
        top = 60
        width = 200
        height = 30
        tickStyle = tsManual
        min = 0
        max = 100
        position = 100
        onChange = volumeTrackBarChange
        enabled = FALSE
    END CREATE
    CREATE volumeLabel AS QLABEL
        left = 215
        top = 70
        caption = "Volume 100%"
    END CREATE
    CREATE freqTrackBar AS QTRACKBAR
        left = 10
        top = 110
        width = 200
        height = 30
        tickStyle = tsManual
        max = 44100
        position = 22050
        min = 0
        onChange = freqTrackBarChange
        enabled = FALSE
    END CREATE
    CREATE freqLabel AS QLABEL
        left = 215
        top = 120
        caption = "Frequency 22050Hz"
    END CREATE
    CREATE positionTrackBar AS QTRACKBAR
        left = 10
        top = 160
        width = 200
        height = 30
        tickStyle = tsManual
        onChange = positionTrackBarChange
        enabled = FALSE
    END CREATE
    CREATE positionLabel AS QLABEL
        left = 215
        top = 170
        caption = "Position 0 / 0"
    END CREATE
    CREATE playButton AS QBUTTON
        left = 30
        top = 210
        caption = "&Play"
        enabled = FALSE
        onClick = playButtonClick
    END CREATE
    CREATE stopButton AS QBUTTON
        left = 110
        top = 210
        caption = "&Stop"
        enabled = FALSE
        onClick = stopButtonClick
    END CREATE
    onShow = formShow
    showModal
END CREATE

SUB formShow (sender AS QFORM)
    panTrackBar.setTick(0)
    volumeTrackBar.setTick(50)
    freqTrackBar.setTick(22050)
    dxSound.looped = FALSE
END SUB

SUB exitItemClick (sender AS QMENUITEM)
    form.close
END SUB

SUB openItemClick (sender AS QMENUITEM)
    DIM openDialog AS QOPENDIALOG

    openDialog.filter = "*.wav|*.wav"
    IF openDialog.execute THEN
        dxSound.fileName = openDialog.fileName
        panTrackBar.enabled = TRUE
        volumeTrackBar.enabled = TRUE
        freqTrackBar.enabled = TRUE
        positionTrackBar.enabled = TRUE
        playButton.enabled = TRUE
        stopButton.enabled = TRUE
        positionTrackBar.position = 0
        positionTrackBar.max = dxSound.size
        freqTrackBar.position = dxSound.frequency
        freqTrackBarChange(freqTrackBar)
        positionTrackBarChange(positionTrackBar)
    END IF
END SUB

SUB playButtonClick (sender AS QBUTTON)
    dxSound.play
    WHILE dxSound.playing
        doEvents
        positionTrackBar.position = dxSound.position
        positionLabel.caption = "Position "+STR$(positionTrackBar.position)+" / "+STR$(dxSound.size)
    WEND
END SUB

SUB stopButtonClick (sender AS QBUTTON)
    dxSound.stop
    dxSound.position = 0
    positionTrackBar.position = 0
END SUB

SUB positionTrackBarChange (sender AS QTRACKBAR)
    dxSound.position = sender.position
    positionLabel.caption = "Position "+STR$(sender.position)+" / "+STR$(dxSound.size)
END SUB

SUB freqTrackBarChange (sender AS QTRACKBAR)
    dxSound.frequency = sender.position
    freqLabel.caption = "Frequency "+STR$(sender.position)+"Hz"
END SUB

SUB volumeTrackBarChange (sender AS QTRACKBAR)
    dxSound.volume = sender.position
    volumeLabel.caption = "Volume "+STR$(sender.position)+"%"
END SUB

SUB panTrackBarChange (sender AS QTRACKBAR)
    dxSound.pan = sender.position
    panLabel.caption = "Pan "+STR$(sender.position)+"dB"
END SUB


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
AddFrame | SUB (Frame AS QD3DFrame) | Add a frame to this frame | 1
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
DeleteLight | SUB (Light AS QD3DLight) | Removes light object from frame | 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/QD3DMeshBuilder) | Apply wrap to mesh | 1
ApplyRelative | SUB (F AS QD3DFrame, M AS QD3DMesh/QD3DMeshBuilder) | 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
String index [] 1 Returns a character from a string
ie. s$[2]
returns the second character in string s$
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"
Addition & 4 Same as using '+' but maintained for compatibility with other BASIC languages, such as VB.
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 their first bits are set
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: Rapid-Q Supported Data Types

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

Introduction to Data Types

A data type is just a definition. It is used to bind a variable to its definition and cannot be changed once bound (except for VARIANT type variables). For example, if a variable is bound to a STRING data type, it cannot change itself to an INTEGER definition. A variable can be assigned any one of these supported data types, BYTE, WORD, DWORD, SHORT, LONG/INTEGER, SINGLE, DOUBLE, STRING, VARIANT, and fixed-length strings. There are also such things as User Defined Data Types, which will be discussed in another section. Some BASIC implementations hold INTEGER as a 16-bit value, while Rapid-Q chooses to go 32-bit. So if you're worried about converting your old code, make sure to replace all occurrences of INTEGER with SHORT.

How to use data types
Since Rapid-Q is a BASIC language, there are 2 ways to define your variables. You can choose to do it explicitly using DIM
    DIM myNum AS LONG
    DIM myStr AS STRING
Similarly, you can attach a suffix symbol which describes the variable type:
    myNum& = 234
    myStr$ = "abc"
Chapter 3 has a list of these suffixes, but are listed here again for your convenience:
    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
    String      $
A variant data type has no suffix, so you'll have to use DIM instead, or change the default DIM operation.
    $OPTION DIM VARIANT

    myVar = "hello!"
myVar is defined as a VARIANT since we've changed the default data type for DIM. Whenever Rapid-Q comes across an undefined symbol (with no suffix), it will choose the data type according to traditional BASIC. Traditionally, this has been choosen to be either SINGLE or DOUBLE. With Rapid-Q, you can choose any of the existing data types as the default one.

Variant data type
A Variant is a special kind of data type, since a Variant can mutate. Don't be afraid, it won't mutate to a virus or anything like that. It simply changes types on the fly, as needed. Even a simple operation like addition changes when you add 2 variants together. Take this for example:
   DIM V1 AS VARIANT, V2 AS VARIANT

   V1 = 101
   V2 = "99.5"

   PRINT V1+V2  '-- Output is 200.5
As you'll notice V2 is originally assigned a string, but V2 has changed its type to a floating point number when the addition takes place. Note that V2 is still a string, it just mutated itself for that one operation. Similarly,
   DIM V1 AS VARIANT, V2 AS VARIANT

   V1 = "101"
   V2 = 99.5

   PRINT V1+V2  '-- Output is 10199.5
In this case, V2 was originally a floating point number, but changed its type during the addition operation to a string. Notice how the order of operation defines the mutation. In the previous example, V1 was a number, so V1+V2 results in a numeric expression, while the above example produces a string.


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

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

    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. QObjects, Arrays, UDTs and Variants 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-2000 Appendix C: Internal Variables

Internal Variables

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

Variable | Support | Type | Description
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. This function is being deprecated.
MouseY | Windows | INTEGER | Returns Y Coordinate of Mouse Pointer relative to your active Form. This function is being deprecated.
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.Cursors | Windows | ARRAY of INTEGER | R/W array of cursor handles.
Screen.Height | Windows | INTEGER | Returns Windows screen Height (not to be confused with Form Height)
Screen.MouseX | Windows | INTEGER | Returns X Coordinate of Mouse Pointer relative to your screen.
Screen.MouseY | Windows | INTEGER | Returns Y Coordinate of Mouse Pointer relative to your screen.
Screen.Width | Windows | INTEGER | Returns Windows screen Width
Stack.Int() | Windows Unix | ARRAY | Returns most current stack integer parameter. First element starting at 0. This function is deprecated.
Stack.Str$() | Windows Unix | ARRAY | Returns most current stack string parameter. First element starting at 0. This function is deprecated.


Appendix C: Console keywords

Rapid-Q Documentation by William Yu (c)1999-2000 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
CONSOLE.INPUTHANDLE Windows hnd = CONSOLE.INPUTHANDLE
Returns the console input handle
CONSOLE.OUTPUTHANDLE Windows hnd = CONSOLE.OUTPUTHANDLE
Returns the console output handle
CSRLIN Windows Unix CurRow% = CSRLIN
Returns current row of cursor
INKEY$ Windows Unix A$ = INKEY$
Returns ASCII/Extended key character typed
INPUT Windows Unix INPUT A$
Reads a full line of input from user
LOCATE Windows Unix LOCATE [Y%][, X%][, cursor]
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.
SCREEN Windows A% = SCREEN(row, col [, colorflag])
Returns the chararacter or attribute value at (row,col)
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. The following keywords are all encapsulated in the CONSOLE object, so Console.PRINT is the same as PRINT.

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

CONSOLE.INPUTHANDLE | CONSOLE Statement | Windows
Returns the console input handle for use in API calls.

Syntax: CONSOLE.INPUTHANDLE
hnd = CONSOLE.INPUTHANDLE

CONSOLE.OUTPUTHANDLE | CONSOLE Statement | Windows
Returns the console output handle for use in API calls.

Syntax: CONSOLE.OUTPUTHANDLE
hnd = CONSOLE.OUTPUTHANDLE

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 start with CHR$(27) and are 2 bytes in length. Extended keys are arrow keys, page up/down, home, end, insert, delete, and F1-F12 keys. You can also trap the shift, ctrl, alt, caps/num/scroll lock keys under Windows.

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"{;|,}] 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 can be a string or numeric 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][,cursor]
LOCATE 10, 1
LOCATE ,10
LOCATE 5
LOCATE 1,,80

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). The cursor argument is optional, and can take a range of values from 0 to 100 indicating the percentage of the character cell that is filled by the cursor. ie. specifying a value of 0 completely hides the cursor. The default cursor value is 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.

SCREEN | CONSOLE Function | Windows
Returns the ASCII character or attribute at (row, col) on the current console screen.

Syntax: SCREEN(row, col [, colorflag])
A% = SCREEN(1, 1) '-- Get character located on the first row and column
A% = SCREEN(5, 3, 1) '-- Get attribute of character located at (5,3)

Details:
The SCREEN function is very similar to the PEEK function, except that it's much easier to use. If you supply the function with a colorflag parameter, the function returns the attribute (ie. color), otherwise it returns the ASCII character. The SCREEN function only works on the current console screen and not on any hidden pages.

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$
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
CALLBACK/CODEPTR Windows CODEPTR(MySUB)
Returns the absolute address of the SUB/FUNCTION
CALLFUNC Windows Unix CALLFUNC(Num, Param1, Param2, ...)
Call function pointer
CEIL Windows Unix CEIL(NumericExpression)
Rounds a numeric expression up towards positive infinity.
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
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.
FLOOR Windows Unix FLOOR(NumericExpression)
Rounds a numeric expression down towards negative infinity.
FORMAT$ Windows Unix 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
INITARRAY Windows Unix INITARRAY(Array, values, ...)
Initializes array with corresponding values
INP Windows Unix INP(Address)
Returns the byte value read from an I/O port 0..65535
INPW Windows Unix INPW(Address)
Returns the word 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
KILLMESSAGE Windows KILLMESSAGE hWnd, Message
Removes message from queue
LBOUND Windows Unix LBOUND(ArrayName[, Dimension])
Returns the lowerbound of an array (Dimension starts at 1)
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
LFLUSH Windows LFLUSH
Calling this will start printing your document. Make sure all your LPRINTs are executed before calling LFLUSH.
LIBRARYINST Windows LIBRARYINST(DLLName)
Returns the handle to a loaded DLL module
LOG Windows Unix LOG(NumericExpression)
Returns the natural logarithm of NumericExpression
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
MEMCMP Windows Unix MEMCMP(ptr1, ptr2, count)
Compares 2 memory addresses, returns 0 if not equal, non-zero otherwise.
MEMCPY Windows Unix MEMCPY(destination, source, count)
Copies count bytes of source memory address to destination memory address.
MEMSET Windows Unix MEMSET(source, char, n)
Initializes a source memory block with n bytes of char.
MESSAGEBOX Windows MESSAGEBOX(Msg$, Title$, MsgButtons%)
Displays a simple message box with prompts
MESSAGEDLG Windows MESSAGEDLG(Msg$, MsgType, MsgButtons, HelpContext)
Displays a message dialog 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
OUTW Windows Unix OUTW(Address, wordvalue)
Sends a word value to a machine I/O port 0..65535
PLAYWAV Windows PLAYWAV FileName$|Resource_Handle, 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
SOUND Windows SOUND freq, duration
Outputs sound through PC Speaker
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
STATIC Windows Unix STATIC Variable AS DataType
Creates variable of type DataType and preserves variable between procedure calls
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
UNLOADLIBRARY Windows UNLOADLIBRARY(DLLName)
Removes DLL from memory
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.
VARTYPE Windows Unix VARTYPE(variant)
Returns the type of a variant 0 - Integer, 1 - Float, 2 - String.


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")

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.

CALLBACK/CODEPTR | ADDRESS Function | Windows
CODEPTR (or CALLBACK) will return the absolute address of a SUB or FUNCTION.

Syntax: CODEPTR(MySUB)
SUB MySUB
END SUB
A& = CODEPTR(MySUB)

Details:
Use this function for CALLBACK routines. Not all cases are implemented, results may vary depending on the CALLBACK and the type of parameters it receives.

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.

CEIL | MATH Function | Windows/Unix
A math function that rounds a numeric expression up toward positive infinity.

Syntax: CEIL(numeric-expression)
A% = CEIL(66.2) '-- Returns 67

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) '-- equals 67

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 [ as Datatype ]= expression
CONST False = 0
CONST True AS LONG = NOT False
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 your program.

Syntax: END
END

Details:
Call END to terminate your application, but if there are any Windows still opened, you should close them first.

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)

FLOOR | MATH Function | Windows/Unix
A math function that rounds a numeric expression down toward negative infinity.

Syntax: FLOOR(numeric-expression)
A% = FLOOR(66.7) '-- Returns 66

FORMAT$ | STRING Function | Windows/Unix
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)

INITARRAY | ARRAY Statement | Windows/Unix
Initializes an array with the corresponding values.

Syntax: INITARRAY(Array, value [, ...])
DIM A(1 TO 100) AS INTEGER
INITARRAY(A, 55, 234, 45, 99)

Details:
Equivalently:
DEFINT A(1 TO 100) = {55, 234, 45, 99}

Initializing arrays as opposed to looping through each one saves a bit of time.

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. Return value is in the range 0 to 255.

INPW | I/O Function | Windows/Unix
A device I/O function that returns the word value read from an I/O port.

Syntax: INPW(port)
A = INPW(&H3C9)

Details:
Port is any word value between 0 and 65535. Return value is also in the range 0 to 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"

KILLMESSAGE | RAPID-Q Specific | Windows
A statement that removes a message from the queue.

Syntax: KILLMESSAGE hWnd, Message
KILLMESSAGE form.handle, WM_CHAR

Details:
Ideally, KillMessage should be used inside an event, such as OnKeyDown, to remove any messages you don't want processed further.

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.

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.

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.

LIBRARYINST | DLL Function | Windows
Returns the handle to the DLL module. If the DLL hasn't been loaded yet or is not found, this function returns 0.

Syntax: LIBRARYINST(DLLName)
DECLARE FUNCTION UpdateWindow LIB "USER32" ALIAS _
"UpdateWindow" (hWnd AS LONG) AS LONG
UpdateWindow(0) '-- Using function will load DLL
hInst& = LIBRARYINST("USER32")

Details:
Declaring a function as a DLL function does not automatically load the DLL. The DLL is loaded once the function is used. Please note that library names should match, so in your declaration for LIB "USER32" ... to find this library, you must match that same name. ie. LIBRARYINST("USER32.DLL") returns 0, it must be "USER32" in this particular case. See also UNLOADLIBRARY.

LOG | MATH Function | Windows/Unix
A math function that returns the natural logarithm of a numeric expression.

Syntax: LOG(numeric-expression)
A# = LOG(10)

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

MEMCMP | MEMORY Function | Windows/Unix
A memory function that compares 2 memory addresses and returns 0 if the memory contents do not match, or non-zero otherwise.

Syntax: MEMCMP(ptr1, ptr2, count)
DEFINT I=10, J=10
A% = MEMCMP(VARPTR(I), VARPTR(J), SIZEOF(INTEGER))

MEMCPY | MEMORY Function | Windows/Unix
A memory function that copies n bytes of memory from source to destination.

Syntax: MEMCPY(destination, source, n)
DEFINT I=90, J=10
'-- After MEMCPY, I should equal 10
MEMCPY(VARPTR(I), VARPTR(J), SIZEOF(INTEGER))

MEMSET | MEMORY Function | Windows/Unix
A memory function that initializes a memory blocks.

Syntax: MEMSET(ptr, char, size)
DIM IntArray(1 TO 10) AS INTEGER
MEMSET(VARPTR(I(1)), 0, 10*SIZEOF(INTEGER))

MESSAGEBOX | RAPID-Q Specific | Windows
Displays a simple message box with prompts. This implements Window's MessageBox API function.

Syntax: MESSAGEBOX(message, title, flags%)
IF MessageBox("Close this form?", "Close", 1) = 1 THEN
'-- Close form
END IF

Details:
See Windows API Help file for valid flags.

MESSAGEDLG | RAPID-Q Specific | Windows
Displays a message box with an icon and a user defined caption. This implements Window's MessageBoxEx API function.

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 substring with n chracters starting from i 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.

    • OUTW | I/O Statement | Windows/Unix
    A device I/O statement that sends a word value to a machine I/O port.

    Syntax: OUTW port, value
    OUTW &H378, 128

    Details:
  • Port is any word value between 0 and 65535.
  • Value is any byte value between 0 and 65535.

    • PLAYWAV | RAPID-Q Specific | Windows
    Plays a .WAV file or a .WAV resource.

    Syntax: PLAYWAV wavfilename|wavresource, sndOptions
    $RESOURCE Welcome_WAV AS "welcome.wav"
    PLAYWAV "welcome.wav", SND_ASYNC OR SND_LOOP
    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. You can stop the .WAV by passing an empty string as a filename.

    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 (except when dealing with components, in which case you'll receive a compiler error). 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(1 to 100) AS INTEGER
DIM B(1 to 100) AS INTEGER
REDIM A(1 to 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 101 to 200 is the data for B and 1 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. Note that this by-product does not apply to redimming Fixed Strings, Variants and Components.
    Redim table
      DIM Button(1 TO 2, 1 TO 2) AS QBUTTON
REDIM Button(1 TO 2, 1 TO 4) AS QBUTTON
    Note that when dealing with multiple dimensions the elements are shifted to fill each column. So element (2,2) is actually moved to position (1,4).

    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.49) '-- Returns 3
    A% = ROUND(3.50) '-- 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|variable)
    PRINT SIZEOF(MyUDT)
    PRINT SIZEOF(MyVar)
    PRINT SIZEOF(INTEGER)

    Details:
    To calculate the size of a UDT, you must first DIM it.
    ie. DIM MyUDT AS TMyUDT

    SOUND | I/O Statement | Windows
    A device I/O statement that generates sound through the PC Speaker.

    Syntax: SOUND frequency, duration
    SOUND 4000, 18

    Details:
  • Frequency is a numeric expression whose value is between 37 and 32,767. Frequency is measured in cycles/second, or hertz.
  • Duration is a numeric expression whose value is between 0 and 65,535. There are 18.2 clock ticks per second, so 18 is considered 1 second, etc...

    • 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

    STATIC | Statement | Windows/Unix
    Similar to DIM, this statement names one or more variables and allocates storage space for them. However, declaring STATIC variables means that variable values are preserved between procedure calls. Note that only simple types are affected.

    Syntax: STATIC variable[(subscripts)] AS type
    STATIC A AS INTEGER, B AS BYTE, S AS STRING

    Details:
    STATIC has no affect (ie. same as using DIM) when declared in the main module. Use STATIC only inside a SUB/I or FUNCTION/I.

    Examples:
        '-- Non static count
    SUB Count (N AS INTEGER)
       DIM B AS LONG

       B = N
       IF N = 10 THEN EXIT SUB
       Count(N+1)
       PRINT B
    END SUB

    Count(1)

    '-- Static count, B retains the same value
    SUB StaticCount (N AS INTEGER)
       STATIC B AS LONG

       B = N
       IF N = 10 THEN EXIT SUB
       StaticCount(N+1)
       PRINT B
    END SUB

    StaticCount(1)

    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$(count, byte)
    A$ = STRING$(9, 65) '-- Returns AAAAAAAAA
    Syntax: STRING$(count, string-expression)
    A$ = STRING$(9, "ABC") '-- Returns AAAAAAAAA

    Details:
    The first parameter indicates the number of times to repeat the character. The second parameter can either be a string expression, whose first character is used as the repeat character, or a byte number in the range from 0 to 255 representing the ASCII character code.

    SWAP | Statement | Windows/Unix
    An assignment statement that exchanges the values of 2 variables.

    Syntax: SWAP variable1, variable2
    SWAP A$, B$

    Details:
    Variable1 and variable2 should be of the same type, but Rapid-Q won't complain. Also, do not swap variants using the SWAP function if their types do not match.

    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

    UNLOADLIBRARY | DLL Statement | Windows
    Removes DLL from memory (only those declared in Rapid-Q). If DLL hasn't been loaded or is not found, this statement does nothing.

    Syntax: UNLOADLIBRARY(DLLName)
    DECLARE FUNCTION UpdateWindow LIB "USER32" ALIAS _
    "UpdateWindow" (hWnd AS LONG) AS LONG
    UNLOADLIBRARY("USER32") '-- Removes USER32.DLL from memory

    Details:
    It is not required that you unload a DLL, this is done for you when your Rapid-Q program ends. Unloading a DLL library from memory does not mean the function call that requires the DLL will fail. The DLL is again reloaded into memory before the function call, so you can UnLoad it again if you want. Please note that library names should match, so in your declaration for LIB "USER32" ... to unload this library, you must match that same name. UNLOADLIBRARY("USER32.DLL") does nothing, it must be "USER32" in this particular case. See also LIBRARYINST.

    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))

    VARPTR$ | ADDRESS Function | Windows/Unix
    A function that returns the string representation of a given address.

    Syntax: VARPTR$(address)
    S$ = VARPTR$(279027343)

    VARTYPE | VARIANT Function | Windows/Unix
    A function that returns the data type of the current value stored in the variant.

    Syntax: VARTYPE(variant)
    DIM myvariant(100) AS VARIANT
    myvariant(1) = "G"
    VType = VARTYPE(myvariant(1))

    Details:
    Valid return values are:
    0 - Number (includes Byte, Word, Dword, Short, Long/Integer)
1 - Float (includes Single, Double)
2 - String
    All undefined variants are initialized as Numbers.


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, Arrays, and Variants 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 Arrays, Variants, 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, Variants, 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


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