Naming GuiButtons

Hello,

When we have many buttons it is difficult to keep track of the ButtonIDs, is there a way to wrap the Gui functions so that we can assign a meaningful button name instead of a number to the functions? For example, here is the normal function:

GuiButton( “Text”, id, x, y, width , height , notifyflags ) ;

It would be nice if we could wrap the function like this:

xGuiButton( “Text”, “ButtonName”, x, y, width, height, notifyflags );

Here the xGuiButton would automatically translate the ButtonName to sequential ButtonIDs so that later in the code we can refer to the button by name.

Thanks for any ideas you may have!
Herman

Not tested but may give you ideas

GuiButtonId = 1;

procedure xGuiButton( Text, ButtonName, x, y, width, height, notifyflags )
{
	global GuiButtonId;
	
	GuiButton( Text, GuiButtonId, x, y, width , height , notifyflags ) ;
	VarSet(ButtonName, GuiButtonId);
	GuiButtonId++;
}

xGuiButton( "Text", "ButtonName", x, y, width, height, notifyflags );

1 Like

Thank you awilson,

That helped me solve my problem as shown below. Works nicely so far :slightly_smiling_face:

procedure xGuiButton( Text, ButtonName, x, y, width, height, notifyflags )
{
	global GuiButtonId;
	if( typeof( GuiButtonId ) == "undefined" ) GuiButtonId = 1;
	GuiButton( Text, GuiButtonId, x, y, width , height , notifyflags ) ;
	VarSet( ButtonName, GuiButtonId);
	GuiButtonId++;
}

// The following four lines are program specific - adjust to your own code environment.
    xGuiButton( "MKT", "BuyOrderType", x1, 0, P_ColumnWidth, ButtonHeight, 7 );
    xGuiButton( "LMT", "SellOrderType", x2, 0, P_ColumnWidth, ButtonHeight, 7 );   
    xGuiButton( "CANCEL", "BuyCancel", x1, pxchartbottom-ButtonHeight, P_ColumnWidth, ButtonHeight, 7 );
    xGuiButton( "CANCEL", "SellCancel", x2, pxchartbottom-ButtonHeight, P_ColumnWidth, ButtonHeight, 7 );   

// Button Handler
if( GuiGetEvent( 0, 1 ) == 1 )
{
    str = GuiGetEvent( 0, 2 );
    id = GuiGetEvent( 0, 0 );

    for( i = 1; i <= 10; i++ )
    {
        if( id == i )
        {
            switch( id )
            {
                case BuyOrderType:
                    Say( "1" );
                    break;

                case SellOrderType:
                    Say( "2" );
                    break;

                case BuyCancel:
                    Say( "3" );
                    break;

                case SellCancel:
                    Say( "4" );
                    break;
            }
        }
    }
}

Actually it is far better to rely on IDs than on names. Using IDs you can change button names freely without changing other parts of code. For example if you ever thought about localization. The IDs will remain constant even if text change. The IDs should be defined as names

Such as

// define symbolic IDs
idBuyMarket = 1;
idBuyLimit = 2;
idCancel = 3;

and you should use those symbolic IDs throughout the code.

// use symbolic IDs 
GuiButton( "My Buy Market", idBuyMarket, x, y, width , height , notifyflags ) ;

Also note that IDs are used to group controls like radio buttons that work together as a group. These assume consecutive IDs in the group. Control IDs are used by Windows OS itself

1 Like

Thank you Tomasz,

When using many buttons in different parts of a large program, and perhaps in include files, and/or in conditional code segments, or modules that get patched in, it gets hard to know which IDs are used, where they are defined, and to keep them sequential. Especially when code is under development and changes drastically all the time (I do a lot of cut-n-pasting). How would I maintain a sequential ID sequence when patching code modules together?

It seems to me that automatic ID assignment would be much easier. I do not understand your last sentence, does this mean that automatic ID assignments could prevent my code from running properly?

Surely I must be missing the bigger picture…

Herman

Believe me. I know what I am talking about. AmiBroker has thousands of controls. And each and every one has the ID. This is how EVERY windows program is build, including MS Word, Excel, Photoshop. Each and every one uses the IDs. And trust me I am speaking about programs that have MILLIONS of lines of source code and thousands of files and are infinitely more complex than your formulas. IDs make things easier, not harder.

IDs don’t need to be sequential but they need to be unique WITHIN ONE parent window. Each module can have different “range” of IDs. So for example you got 10xx in one module, 20xx in another 30xx in yet another and so on.

So in one module you can define those like this:

idBase = 1000; // you can modify the base and quickly renumber all relative IDs
idMyButton = idBase + 1; // relative to base ID
idMyOtherButton = idBase + 2; // relative to base ID
4 Likes

These are helpful comments, thank you Tomasz.

Herman

Hard coding is probably Ok if you need to test something out, quick and dirty, going to throw it way, but, from hard personal experience, hard-coding a unique value, literal or constant, is only asking for trouble, especially if you have to maintain the code.

For example, a lot of older AB code, from the Yahoo days, and in the KnowledgeBase, use numeric values for the color parameter of the Plot() function, eg. Plot(Close, "Close", 1), where the "1" might represent the color blue.

There are a couple of issues with using literal values rather than named constants:

  1. the code is less readable/ maintainable.
  2. the value may have a certain meaning in one version of AB, but may change over time, eg. the literal for color blue has changed to "2", and "1" is now used to produce black.
  3. your code may have the value "1.1235" in a number of places, which may change over time.

A better way, is to use a named constant, like @Tomasz has suggested, that way the code is easier to read & understand, you reduce the possibility of copy/paste/replace errors, and any change to the literal value automatically "ripples" through the code. For example:

// Literal/ hard-coded values, that may not work the same in the future
SetBarsRequired(-2, -2)
// Easier to read and maintain, and independent of any changes in the underlying software
SetBarsRequired(sbrAll, sbrAll)