Using Gui*() functions in Real Time AB

Hello,

I'm trying to create a simple "Buy from the chart" mechanism, where the Buy/Short parameters are automatically filled in when the order is sent to IBC.

I have the following simple four buttons for Cancel, Buy, Short and Close
image
When I click on the Buy or Short buttons, I display three extra controls, an Edit Control to enter the number of contracts and two OK/Cancel buttons
image
The problem is that in real-time mode, the screen is constantly being refreshed, and the text box to enter the number of contracts is constantly being rewritten on the screen. This means I can't fill in the text box.

My AFL code is somerthing like this

GuiCreateButton(idButtonCancel, cancelCellStr, colorLightBlue);
GuiCreateButton(idButtonBuy, buyCellStr, colorBrightGreen);
GuiCreateButton(idButtonShort, shortCellStr, colorDarkRed);
GuiCreateButton(idButtonClose, closeCellStr, colorOrange);

TriggerCancel = GuiGetWaitingEvent(idButtonCancel);
TriggerBuy = GuiGetWaitingEvent(idButtonBuy);
TriggerShort = GuiGetWaitingEvent(idButtonShort);
TriggerClose = GuiGetWaitingEvent(idButtonClose);

if( TriggerBuy OR TriggerShort )
{
      // how to enter text into this text box?
      GuiCreateEdit(idEditPositionSize, colorYellow);
      GuiSetText("1", idEditPositionSize);
      TriggerQuantityChange = GuiGetWaitingEvent(idEditPositionSize);

      GuiCreateButton(idButtonOk, okCellStr, colorPink);
      TriggerOk = GuiGetWaitingEvent(idButtonOk);

      GuiCreateButton(idButtonNok, nokCellStr, colorPink);
      TriggerNok = GuiGetWaitingEvent(idButtonNok);
}

GuiCreateButton() and GuiCreateEdit() are wrappers to call GuiButton() and GuiEdit().

I've simplified the processing of the TriggerBuy and TriggerShort above, because these events are not persisted across successive refreshes of the AFL. I've used static variables to store their states until the user clicks on Confirm or Cancel.

Can anyone help?

Just adding a note here for anyone else with the same problem.
Fixed as follows:

// how to enter text into this text box?
rc = GuiCreateEdit(idEditPositionSize, colorYellow);
if( rc == guiNew )
{
          // Only fill the text box when control is created
          GuiSetText("1", idEditPositionSize);
}

It is happening because your code procures so...

The problem is not because the chart gets refreshed, but upon every refresh (after Buy or Short Toggle Button is SetCheck to True) a new GuiEdit gets created destroying the previous one. That's why it gets constantly rewritten on the screen.

Instead create all GUIs once and then programmatically toggle between its visibility as and when required - much safer approach! Usage of Staticvars are more than enough for this case.

Try this:

global ChartId, id, event;
ChartId = Name() + GetChartID();
id = GuiGetEvent( 0, 0 );				event = GuiGetEvent( 0, 1 );

function IndpndntBtnState( BtnId ) {
	 local GuiSel; // Selected GUI
	 GuiSel = Nz( StaticVarGet( ChartId + BtnId ) );
	 if( id == BtnId && event ) {
	 	 if( GuiSel ) StaticVarRemove( ChartId + BtnId );
		 else StaticVarSet( ChartId + BtnId, GuiSel = 1, False );
	 }
	 return GuiSel;
}

procedure CreateGuiBtn( BtnTxt, BtnId, BtnX, BtnY, BtnWdth, BtnHght, BtnFlag ) {
	 switch( BtnId ) { // Otherwise use a for-loop if GuiSetColors() is common for all GUIs
		 case 1: // "Buy" Button
			 GuiToggle( BtnTxt, BtnId, BtnX, BtnY, BtnWdth, BtnHght, BtnFlag );
			 GuiSetColors( BtnId, BtnId, 1,
				 clrText 	= colorWhite, 		clrBk    = colorGrey50,			clrBor 		= colorBlack,
				 clrSelText = colorWhite,		clrSelBk = colorGreen,			clrSelBor	= colorBrightGreen,
				 clrHovText = colorBlack,		clrHovBk = colorBrightGreen,	clrHovBor	= colorBrightGreen );
			 break;
		 case 2: // "Short" Button
			 GuiToggle( BtnTxt, BtnId, BtnX, BtnY, BtnWdth, BtnHght, BtnFlag );
			 GuiSetColors( BtnId, BtnId, 1,
				 clrText 	= colorWhite, 		clrBk    = colorGrey50,			clrBor 		= colorBlack,
				 clrSelText = colorWhite,		clrSelBk = colorBrown,			clrSelBor	= colorRed,
				 clrHovText = colorBlack,		clrHovBk = colorRed,			clrHovBor	= colorRed );
			 break;
		 case 3: // "Ok" Button
			 GuiButton( BtnTxt, BtnId, BtnX, BtnY, BtnWdth, BtnHght, BtnFlag );
			 GuiSetColors( BtnId, BtnId, 1,
				 clrText 	= colorWhite, 		clrBk    = colorGrey50,			clrBor 	= colorBlack,
				 clrSelText = colorGrey40,		clrSelBk = -1,					clrSelBor	= colorGrey40,
				 clrHovText = colorGrey40,		clrHovBk = -1,					clrHovBor	= colorGrey40 );
			 break;
		 case 4: // "No" Button
			 GuiButton( BtnTxt, BtnId, BtnX, BtnY, BtnWdth, BtnHght, BtnFlag );
			 GuiSetColors( BtnId, BtnId, 1,
				 clrText 	= colorWhite, 		clrBk    = colorGrey50,			clrBor 	= colorBlack,
				 clrSelText = colorGrey40,		clrSelBk = -1,					clrSelBor	= colorGrey40,
				 clrHovText = colorGrey40,		clrHovBk = -1,					clrHovBor	= colorGrey40 );
			 break; 
	 }
}

procedure CreateGuiEdit( EditId, EditX, EditY, EditWdth, EditHght, EditFlag ) {
	 GuiEdit( EditId, EditX, EditY, EditWdth, EditHght, EditFlag ); // Qty Edit Box
	 GuiSetColors( EditId, EditId, 1,
		 clrText 	= colorWhite, 		clrBk     = colorDefault,    	clrBor = colorWhite,
		 clrSelText = colorYellow, 		clrSelBk = colorDefault, 		clrSelBor = colorYellow,
		 clrHovText = colorYellow, 		clrHovBk = colorDefault, 		clrHovBor = colorYellow );
}

_SECTION_BEGIN( "Order Interface" );
	 // Setting GUI Ids
	 BuyBtnId = 1;
	 ShortBtnId = BuyBtnId + 1;
	 OkBtnId = ShortBtnId + 1;
	 NoBtnId = OkBtnId + 1;
	 QtyEditId = NoBtnId + 1; // 5
	 
	 // Common Witdth and Height for all GUIs
	 GuiWdth = 40;					GuiHght = 20;
	 BuyBtnX = 5;							BuyBtnY = Status( "PxChartHeight" ) - GuiHght;
	 CreateGuiBtn( "Buy", BuyBtnId, BuyBtnX, BuyBtnY, GuiWdth, GuiHght, notifyClicked );
	 ShortBtnX = BuyBtnX + GuiWdth;			ShortBtnY = BuyBtnY;
	 CreateGuiBtn( "Short", ShortBtnId, ShortBtnX, ShortBtnY, GuiWdth, GuiHght, notifyClicked );
	 QtyEditX = ShortBtnX + GuiWdth + 5;	QtyEditY = ShortBtnY;
	 CreateGuiEdit( QtyEditId, QtyEditX, QtyEditY, GuiWdth, GuiHght, notifyClicked | notifyEditChange );
	 OkBtnX = QtyEditX + GuiWdth + 5;		OkBtnY = QtyEditY;
	 CreateGuiBtn( "Ok", OkBtnId, OkBtnX, OkBtnY, GuiWdth, GuiHght, notifyClicked );	 
	 NoBtnX = OkBtnX + GuiWdth;				NoBtnY = OkBtnY;
	 CreateGuiBtn( "No", NoBtnId, NoBtnX, NoBtnY, GuiWdth, GuiHght, notifyClicked );
	 
	 // Setting GUI states
	 if( IndpndntBtnState( BuyBtnId ) ) {
		 GuiSetCheck( BuyBtnId, 1 );
		 StaticVarRemove( ChartId + ShortBtnId );
	 }
	 else GuiSetCheck( BuyBtnId, 0 );
	 
	 if( IndpndntBtnState( ShortBtnId ) ) {
		 GuiSetCheck( ShortBtnId, 1 );
		 StaticVarRemove( ChartId + BuyBtnId );
	 }
	 else GuiSetCheck( ShortBtnId, 0 );	 
	 
	 // GUI Button Events
	 if( GuiGetCheck( BuyBtnId ) || GuiGetCheck( ShortBtnId ) ) {
		 for( i = OkBtnId; i <= QtyEditId; i++ ) GuiSetVisible( i, 1 );
		 
		 Qty = Nz( StrToNum( GuiGetText( QtyEditId ) ) );
		 
		 TradeType = GuiGetCheck( BuyBtnId ) + 2 * GuiGetCheck( ShortBtnId );
		 if( Qty && ( id == OkBtnId && event ) ) {  // On "Ok" Button clicked
			 PopupWindow( "Qty taken from GUIEdit is " + Qty + ",\nwhich now can be passed as an argument\nto your script.", "Ready to ShellExecute" );
			 
			 switch( TradeType ) {
				 case 1:
					 // ShellExecute( Buy.exe, use_Qty_as_argument );
					 // Do other things					 
					 StaticVarRemove( ChartId + BuyBtnId );
					 break;
				 case 2:
					 // ShellExecute( Short.exe, use_Qty_as_argument );
					 // Do other things
					 StaticVarRemove( ChartId + ShortBtnId );
					 break;
			 }
		 }
		 
		 if( id == NoBtnId && event ) { // On "No" Button clicked
			 switch( TradeType ) {
				 case 1:
					 // Do something else
					 StaticVarRemove( ChartId + BuyBtnId );
					 break;
				 case 2:
					 // Do something else
					 StaticVarRemove( ChartId + ShortBtnId );
					 break;
			 }
		 }
	 }
	 else
		 for( i = OkBtnId; i <= QtyEditId; i++ ) GuiSetVisible( i, 0 ); 

	 RequestMouseMoveRefresh();
_SECTION_END();

1

6 Likes

Hello Cougar,

Many thanks for the detailed reply.
You have given me some ideas to think about with regard to improving my implementatiion.

However, I think that the Gui*() functions were designed with screen refreshes in mind.
This is why they return guiNew or guiExisting

rc = GuiEdit(controlId, cellX, cellY, cellWidth, cellHeight, notifyEditChange); 
if( rc == guiNew ) {
  // do one-time processing
}
1 Like

@Cougar, @polomora and others - you really need to read the manual. Possibly multiple times.

For GUI: http://www.amibroker.com/guide/h_gui.html

Every single question is covered there. The Manual is the definitive and final and right answer. @polomora final post about using guiNew was correct. The manual instructs you should use guiNew return value to detect when you need to initialize controls (including Edit text). I won't discuss it more here because I wrote already tons of perfect documentation http://www.amibroker.com/guide/h_gui.html
You are just supposed to read that carefully and use as instructed.

Following manual to the letter, makes sure that everything works ALWAYS, regardless if it is RT or not RT.

1 Like

No harm using guiNew if it is the first (and single) invocation of that GUI but I am against the idea of creating new GUIs upon Event getting triggered from other GUI(s). This makes responses slower while handling many GUIs at noose of one trigger.

OP is mixing two things. In one hand he writes:

Then proceeding to check for guiNew:

This means GuiEdit gets created each time when TriggerBuy or TriggerShort occurs and then upon checking whether the GUI got newly created the text of the GuiEdit is set. New text change on the GuiEdit from the chart is not addressed and hence it does not get updated. If that is the case, when why create doldrums of GuiEdit, simply use a constant!

Within context of this discussion, what if the GuiEdit is no longer new - whilst CPU is no longer idle, GUIs would get anyways refreshed - then need to handle guiExisting again?

A StaticVar can simply resolve all what OP wants much faster.

My findings (based on performance check while handling multiple - not few - GUIs) shows setting GUI visibility is effective than creating it afresh upon an event trigger.

May I request you to review my code (shared above) and let me know what I've written incorrectly. Surely that'll help learn, more!


P.S. Handling about 100 GUIs dynamically for personal use (everyday) without any delay, lag or issue - thanks to your software!

image