March 29, 2024, 09:06:18 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


6. Constants

Started by LarryMc, October 15, 2014, 09:50:34 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

LarryMc

Since our next step will be to add controls to our window (w1) and dialog (dlg1) this is a good time to discuss constant variables.

A constant variable can be created several different ways:

  • With the CONST command
  • With the SETID command
  • With ENUM / ENDENUM
What all three have in common is that their values are determined at compile time and therefore can not be set to values of variables that are determined at run time.

SETID differs from the other two in two ways:

  • No math operators can be used in the determination of the constant value.
  • When used in an application the constant name is preceded by an "@"

With CONST and ENUM/ENDENUM you can

  • Use math operators to compute the value of the constant
  • Use other, previously defined constants in the calculation of the value.

When I think of constants I place them in one of two arbitrary groups.

  • Language constants-
    These are the constants that are created with SETID or CONST.  They are defined in one of the IWBasic include files or maybe in Sapero's windowssdk.inc file.  They are used for style flags, message ids, and such,
  • User defined constants-
    Although these are used in some cases for user defined flags and message ids, their primary use is for defining control and menu option ids.

Having said the above I have to mention that some people never create their controls using constants. Instead they just create them with numeric ids like this:
CONTROL w1,@EDIT,"Hello World",10,10,70,20,0,1
There is nothing wrong with this
It works fine in small, Single File applications that tend to not have many controls.

But let's say your Single File application has 100+ controls of various types and you want to set the color of one of them with
SETCONTROLCOLOR w1, x, 0xff0000, 0x0000ff
I defy just about anyone from knowing the correct number for "x" without going back and looking at the original CONTROL statements to determine which number to use.

The point is that just using raw numbers for IDs is not very descriptive.
In some of my Single File applications I have used

CONST Static1 = 10
CONST Edit1    = 11
CONST Static2 =  12
CONST Edit2     = 13
CONST Button1 = 14
CONST Button2 = 15

CONTROL w1,@STATIC,"FName",10,30,70,20,0,Static1
CONTROL w1,@EDIT,"",90,30,70,20,0,Edit1
CONTROL w1,@STATIC,"LName",10,60,70,20,0,Static2
CONTROL w1,@EDIT,"",90,60,70,20,0,Edit2
CONTROL w1,@BUTTON,"",10,90,70,20,0,Button1
CONTROL w1,@BUTTON,"",90,90,70,20,0,Button2


Although the IDs are a little more descriptive I'll still have to look at the CONTROL statement to know which button, edit, or static control I'm going to address is the correct one.

However, we have introduced 2 new problems:

  • By not grouping our controls by type we are preventing ourselves from being able to set up loops for using SETCONTROLCOLOR and SETFONT.
    This problem can be resolved by rearranging our declarations to look like this:
CONST Static1 = 10
CONST Static2 =  11
CONST Edit1    = 12
CONST Edit2     = 13
CONST Button1 = 14
CONST Button2 = 15
    [/li]
  • The second problem this introduces is encountered when we need to add a control.
    If we wanted to modify the above to include a line so we are able to add "Jr" to a name that would mean having to add a new @STATIC control and a new @EDIT control.  In order to maintain our ability to use our loops mentioned above, we'd have to renumber all the constants after the first two.
The latter problem can easily be addressed when we rearrange the order of our constants.  If we do this then there is room for expansion:
CONST Static1 = 10
CONST Static2 =  11
CONST Edit1    = 20
CONST Edit2     = 21
CONST Button1 = 30
CONST Button2 = 31

Doing the above gives us room for eight more of each type control.  Instead of incrementing by 10 for each type we could have just as easily incremented by a 100 or a 1000 which makes numbering a non issue.

So, this just leaves us with the constants being more descriptive.  Remember, our goal with a Project is to break things up in smaller pieces so that once we finish with a portion we don't have to continue to see that code.  Therefore, we need to make these control constants a descriptive as we can(within reason).

Lets change our block of constants, including the two new entries, to look like this:
CONST FName_prmpt = 10
CONST LName_prmpt    = 11
CONST Suffix_prmpt    = 12
CONST FName_text  =  20
CONST LName_text    = 21
CONST Suffix_text    = 22
CONST Save_but = 30
CONST Cancel_but = 31

and our CONTROL statements now look like this:
CONTROL w1,@STATIC,"FName",10,30,70,20,0,FName_prmpt
CONTROL w1,@EDIT,"",90,30,70,20,0,FName_text  
CONTROL w1,@STATIC,"LName",10,60,70,20,0, LName_prmpt    
CONTROL w1,@EDIT,"",90,60,70,20,0,LName_text    
CONTROL w1,@STATIC,"LName",10,60,70,20,0,Suffix_prmpt    
CONTROL w1,@EDIT,"",90,60,70,20,0,Suffix_text    
CONTROL w1,@BUTTON,"",10,90,70,20,0,Save_but
CONTROL w1,@BUTTON,"",90,90,70,20,0,Cancel_but


Now, instead of having a message handler that looks like this:
case @idcontrol
SELECT @controlid
CASE 20
'.....
CASE 21
'.....
CASE 22
'.....
CASE 30
'.....
CASE 31
'.....
ENDSELECT

or one that looks like this
case @idcontrol
SELECT @controlid
CASE Edit1
'.....
CASE Edit2
'.....
CASE Edit3
'.....
CASE Button1
'.....
CASE Button2
'.....
ENDSELECT

which is a little better, we now have this:
case @idcontrol
SELECT @controlid
CASE FName_text  
'.....
CASE LName_text  
'.....
CASE Suffix_text
'.....
CASE Save_but
'.....
CASE Cancel_but
'.....
ENDSELECT

Pretty  descriptive if I say so myself.

But this tutorial is about PROJECTS.
In the IWBasic2.5 beta Project there are 5 windows and 22 dialogs.  There are a lot of controls that have the same name and basic functionality.  And since, in a Project, you can have a dialog load a windows control there is a need to insure there are no duplicate ids when that is done AND that the user knows they are using the correct id.

That is why in my projects, including those created with the IWB+ visual designer (where I generate the source code ) I prefix all control ids with their parent window or dialog's id.

Doing so result's in the above becoming:
CONST w1_FName_prmpt = 10
CONST w1_LName_prmpt    = 11
CONST w1_Suffix_prmpt    = 12
CONST w1_FName_text  =  20
CONST w1_LName_text    = 21
CONST w1_Suffix_text    = 22
CONST w1_Save_but = 30
CONST w1_Cancel_but = 31
CONTROL w1,@STATIC,"FName",10,30,70,20,0, w1_FName_prmpt
CONTROL w1,@EDIT,"",90,30,70,20,0, w1_FName_text  
CONTROL w1,@STATIC,"LName",10,60,70,20,0, w1_LName_prmpt    
CONTROL w1,@EDIT,"",90,60,70,20,0, w1_LName_text    
CONTROL w1,@STATIC,"LName",10,60,70,20,0, w1_Suffix_prmpt    
CONTROL w1,@EDIT,"",90,60,70,20,0, w1_Suffix_text    
CONTROL w1,@BUTTON,"",10,90,70,20,0, w1_Save_but
CONTROL w1,@BUTTON,"",90,90,70,20,0, w1_Cancel_but

and the associated message handler looks like this:
case @idcontrol
SELECT @controlid
CASE w1_FName_text  
'.....
CASE w1_LName_text  
'.....
CASE w1_Suffix_text
'.....
CASE w1_Save_but
'.....
CASE w1_Cancel_but
'.....
ENDSELECT

I could end this section at this point just by saying put all your constants in the constants section of our globals.iwb file. After the entries of our constants from above, that section would look like this:
/******* constants definitions ******************************************/
'$INCLUDE "const.inc"
CONST w1_FName_prmpt = 10
CONST w1_LName_prmpt    = 11
CONST w1_Suffix_prmpt    = 12
CONST w1_FName_text  =  20
CONST w1_LName_text    = 21
CONST w1_Suffix_text    = 22
CONST w1_Save_but = 30
CONST w1_Cancel_but = 31

/******* end of constants definitions ***********************************/


Still not through.
Looking at our list of constants above notice that we had to type the word CONST 8 times, the '='sign 8 times and 8 numbers.

Remember at the very beginning of this section we mentioned ENUM/ENDENUM.  It can do exactly what we need with a lot less typing.

First we have to create an instance of our enumeration and give it a name. Setting that up with the arbitrary name of 'crtls' and adding our constant names would result in this:

ENUM ctrls
w1_FName_prmpt
w1_LName_prmpt
w1_Suffix_prmpt
w1_FName_text
w1_LName_text
w1_Suffix_text
w1_Save_but
w1_Cancel_but
ENDENUM

With the above the controls would be numbered 1 to 8.  All we have to do to duplicate our earlier number assignments is change the above to this:
ENUM ctrls
w1_FName_prmpt =10
w1_LName_prmpt
w1_Suffix_prmpt
w1_FName_text =20
w1_LName_text
w1_Suffix_text
w1_Save_but =30
w1_Cancel_but
ENDENUM

This will result in the controls being numbered 10,11,12,20,21,22,30,31
This is exactly the same as the values when we used the CONST commands.
And to enter a new constant we simply insert it at the proper location and the number is automatically assigned.

Everything that has been said so far about control ids also applies to menu item ids, of which the IWBasic2.5 beta contains over 50 just in the main window. That is not to mention the menu options in the 22 dialogs.

Also, the 2.5 beta main window and several of the dialogs have numerous toolbar buttons which require ids.
The same technique can be applied to them.

So, as I go through the rest of the tutorial I will be following this technique of using the ENUM/ENDENUM format.

This ends 6. Constants
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library