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.

  Prev Chapter | Contents | Next Chapter