GuiButtons for everyone

Unless you are familiar with some of the underlying programming principles and terminology, which I presume 99% of Amibroker users are not, creating a full-fledged GuiButton panel is a nightmare. While it may well be that I have discovered another personal handicap I find it hard to believe I am the only one struggling with this. So, perhaps we can share some knowledge and popularize GuiButtons?

If you have completed the GuiButton learning curve and are now able to layout a button parameter panel as easily and quickly as you would using Param() then you are where I would like to get with this thread.

The objective is to duplicate the most common Parameter function with equivalent GuiButtons, for example:

ParamTrigger() > ButtonTrigger(), ParamToggle() > ButtonToggle(), ParamStr() > ButtonStr(), etc.

This would allow us to substitute button functions for parameter functions, without major edits or risk, in mature code.

The problem is that buttons interface differently to the Windows environment - for example they cannot be used together with RequestMouseMoveRefresh() and events are queued. It will require some to work around and deal with these technical issues. If we cannot solve these problems GuiButton functions will find very limited use.

Below is my failure at coding a general purpose ButtonTrigger(). The problem is that I do not get separate return values, they all toggle at once. Anyone know where I went wrong?

Happy coding,
Herman

RequestTimedRefresh( 1 );
GuiSetFont( "Lucida Console", 10 );

function ButtonTrigger( ButtonName, x, y, width, Height )
{
	global ID;
	if( typeof( ID ) == "undefined" ) ID = 0; 
	
	GuiButton( ButtonName, ++ID, x, y, width, height, 7 ); 
	LastEvent = GuiGetEvent( 0, 0 ); 
	return LastEvent;
}

ButtonTrigger1 = ButtonTrigger( "ButtonTrigger1", 0, 50, 200, 30 );
ButtonTrigger2 = ButtonTrigger( "ButtonTrigger2", 200, 50, 200, 30 );
ButtonTrigger3 = ButtonTrigger( "ButtonTrigger3", 400, 50, 200, 30 );
GuiSetColors( 1, 3, 2, colorRed, colorBlack, colorRed, colorWhite, colorBlue, colorYellow, colorRed, colorBlack, colorYellow ); 

Title = 
"ButtonTrigger1: " + ButtonTrigger1+"\n"+
"ButtonTrigger1: " + ButtonTrigger2+"\n"+
"ButtonTrigger2: "+ButtonTrigger3;

Not sure I understood what you want but maybe this help

RequestTimedRefresh( 1 );
GuiSetFont( "Lucida Console", 10 );

function ButtonTrigger( ButtonName, x, y, width, Height )
{
	global ID;
	if( typeof( ID ) == "undefined" ) ID = 0; 
	
	GuiButton( ButtonName, ++ID, x, y, width, height, 7 ); 
	LastEvent = GuiGetEvent( 0, 0 ); 
	return LastEvent;
}

ButtonTrigger1 = ButtonTrigger( "ButtonTrigger1", 0, 50, 200, 30 );
ButtonTrigger2 = ButtonTrigger( "ButtonTrigger2", 200, 50, 200, 30 );
ButtonTrigger3 = ButtonTrigger( "ButtonTrigger3", 400, 50, 200, 30 );
GuiSetColors( 1, 3, 2, colorRed, colorBlack, colorRed, colorWhite, colorBlue, colorYellow, colorRed, colorBlack, colorYellow ); 

txt = StaticVarGetText("GuiButtonText");
// read all pending events
for( i = 0; id = GuiGetEvent( i, 0 ); i++ )
{
	code = GuiGetEvent( i, 1 );
	text = GuiGetEvent( i, 2 );
	txt += NumToStr(i, 1.0, false)  + " | " + NumToStr(Code, 1.0, false) + " | " + text; 
}
if( i > 0 ) {
	txt += "\n";
	StaticVarSetText("GuiButtonText", txt);
}
Title = txt;

1 Like

Forgot to remove/comment the GuiGetEvent( 0, 0 ); inside the function

Here is possible solution. Works for me.
But why no simply setting IDset as function argument?

RequestTimedRefresh( 1 );
GuiSetFont( "Lucida Console", 10 );

function GuiButtonTrigger( ButtonName, x, y, width, Height ) {
	/// @link http://forum.amibroker.com/t/guibuttons-for-everyone/1716/4
	/// by beaver & fxshrat
	/// version 1.1
	global IDset;
	local id, event, clickeven;
	
	if( typeof( IDset ) == "undefined" ) IDset = 0; 

	//_TRACEF( "IDset before: %g", IDset );	
	GuiButton( ButtonName, ++IDset, x, y, width, height, 7 ); 
	//_TRACEF( "IDset after: %g", IDset );
	
	id = GuiGetEvent( 0, 0 );// receiving button id
	event = GuiGetEvent( 0, 1 );// receiving notifyflag
	clickevent = event == 1;
	
	return id == IDset && clickevent;
}

ButtonTrigger1 = GuiButtonTrigger( "ButtonTrigger1", 0, 50, 200, 30 );
ButtonTrigger2 = GuiButtonTrigger( "ButtonTrigger2", 200, 50, 200, 30 );
ButtonTrigger3 = GuiButtonTrigger( "ButtonTrigger3", 400, 50, 200, 30 );
GuiSetColors( 1, 3, 2, colorRed, colorBlack, colorRed, colorWhite, colorBlue, colorYellow, colorRed, colorBlack, colorYellow ); 

Title = "ButtonTrigger1: " + ButtonTrigger1 + "\n" +
        "ButtonTrigger2: " + ButtonTrigger2 + "\n" +
        "ButtonTrigger3: " + ButtonTrigger3;
2 Likes

My (shorter and simpler) solution without any function:

RequestTimedRefresh( 2 );
GuiSetFont( "Lucida Console", 10 );

GuiButton( "ButtonTrigger1", 1, 0, 50, 200, 30, 7 );
GuiButton( "ButtonTrigger2", 2, 200, 50, 200, 30, 7 );
GuiButton( "ButtonTrigger3", 3, 400, 50, 200, 30, 7 );
GuiSetColors( 1, 3, 2, colorRed, colorBlack, colorRed, colorWhite, colorBlue, colorYellow, colorRed, colorBlack, colorYellow );

id = GuiGetEvent( 0, 0 );
event = GuiGetEvent( 0, 1 );

for( i = 1; i <= 3; i++ )
{
    if( id == i && event == 1 )
    {
        Say( "Button " + i + " clicked" );
        GuiSetText( "Button " + i + " clicked", i );
    }
}

Regards

1 Like

Thank you for your contributions!

A quick answer before I test your codes:

  1. Single-line button calls, i.e., no external code to maintain the buttons, makes replacing param()s easier. Getting all the return values in a loop makes it very inconvenient when calls are located in different sections of a large program.

  2. Auto IDs are preferable as it allows you to move the button functions around. I found hard-coded IDs difficult to work with as you have to keep track of the IDs.

They should be as similar as possible to Param() calls to make it easy to upgrade existing programs.

If you have only a few calls these qualities are not important but when you have dozens of param() calls, and the are placed in different parts of a large, they make life a lot simpler.

Herman

1 Like

with respect to the general mouse functions not working once the mouse is in the GuiButton area the only problem for me (as of yet) was that I wanted to drag the GUI buttons with the mouse. I solved it pretty satisfactory using GFX functions.

see video: https://goo.gl/HmG1pN

if you like this test code I can post it. It works even with just a small 5 pixel border around the buttons.

1 Like

You made my day with so many “working” solutions :wink: Thanks everyone!

While each solution is useful and educational I personally prefer fxshrat’s solution because the single-line calls can easily be substituted for paramtrigger() functions, and it is easy to create a column/row of buttons. I tested it best I can and could not find any problems. I did however add a click-sound as I find it always reassuring the ‘hear’ code is working. Right Milosz?

To complete this thread I’ll repeat the slightly modified code below. Sorry, I can’t seem to be able to attach the sound file… but you can google for that. This gives me an excellent start for the ButtonToggle().

RequestTimedRefresh( 1 );
GuiSetFont( "Lucida Console", 10 );

function SoundButtonClick()
{
    playsound( "C:\\Program Files\\Amibroker\\Sounds\\Button.wav" );
}

function GuiButtonTrigger( ButtonName, x, y, width, Height ) {
	/// @link http://forum.amibroker.com/t/guibuttons-for-everyone/1716/4
	/// by beaver & fxshrat
	/// version 1.1
	global IDset;
	local id, event, clickeven;
	
	if( typeof( IDset ) == "undefined" ) IDset = 0; 

	//_TRACEF( "IDset before: %g", IDset );	
	GuiButton( ButtonName, ++IDset, x, y, width, height, 7 ); 
	//_TRACEF( "IDset after: %g", IDset );
	
	id = GuiGetEvent( 0, 0 );// receiving button id
	event = GuiGetEvent( 0, 1 );// receiving notifyflag
	clickevent = event == 1;
	ButtonClicked = id == IDset && clickevent;
	if( ButtonClicked ) SoundButtonClick();
	return ButtonClicked;
}

ButtonTrigger1 = GuiButtonTrigger( "ButtonTrigger1", 0, 50, 200, 30 );
ButtonTrigger2 = GuiButtonTrigger( "ButtonTrigger2", 200, 50, 200, 30 );
ButtonTrigger3 = GuiButtonTrigger( "ButtonTrigger3", 400, 50, 200, 30 );
GuiSetColors( 1, 3, 2, colorRed, colorBlack, colorRed, colorWhite, colorBlue, colorYellow, colorRed, colorBlack, colorYellow ); 

Title = "ButtonTrigger1: " + ButtonTrigger1 + "\n" +
        "ButtonTrigger2: " + ButtonTrigger2 + "\n" +
        "ButtonTrigger3: " + ButtonTrigger3;
1 Like

Param* and Gui* functions serve completely different purposes and have different audience. As old saying goes “you can’t please everyone” and that is perfect example.
Gui functions are for people familiar with Windows GUI event-driven programming.

All forced time refreshes they should be AVOIDED with Gui. The general principle of Gui* functions is that they DO NOT NEED refreshes AT ALL as the DESIGN principle is that Gui create EVENTS that need to be handled.

Gui* uses EVENT driven design as opposed to timed polling that people where using with their own Gfx* based buttons. These two do not mix. Bottom line - if you are using Gui* functions you should not use forced refreshes because it is counterproductive.

The purpose of GUI functions is to LOWER the CPU usage but NOT requiring ANY forced refreshes. Gui* send EVENTS and you should not do any “polling” at all.

As in Windows API programming you should have single message sink that gets events (GuiGetEvent like PeekMessage/GetMessage in Windows) and dispatch processing via switch. Putting GuiGetEvent into some functions and spreading it along many places is a mistake.

All example codes presented in this topic are flawed as they don’t follow event-driven programming paradigm. You are applying “old thinking” all the time. People without Windows GUI programming background first need a course in programming to understand.

If you don’t know how to program that way, wait for OFFICIAL VERSION (6.30) that will come with instructions and examples of proper coding

3 Likes

Of course I agree with you Herman, but there are also some situations in which a simple loop is probably a better solution to maintain even lots of buttons. Take a look at the example below:


id = GuiGetEvent( 0, 0 );
event = GuiGetEvent( 0, 1 );
nRows = 30;  // number of rows and buttons to be displayed
for( i = 1; i < nRows + 1; i++ )
{
    GuiButton( StaticVarGetText( "Symbol" + i ), i, x, y, width, height, 1 );
    if( id == i && event == 1 ) ShellExecute( StaticVarGetText( "Link" + i ), "", "" );
}

In this case everything that has something to do with all those Buttons is presented in the code above. Only 2 lines of code allow to import all the necessary string variables from another code (an Exploration which extracts information from a web page) to display a selected button, check its state and if this button is clicked, open a new tab in my default web browser with the coressponding content. This repeats n-times to display the rest of the buttons. Only these two lines of "Gui" code are inside a loop. The whole code is very light and really easy to maintain. Of course it is only a very well selected example, but worth taking into account :slight_smile:

Regards

1 Like

Well Herman, I prefer to hear which exactly button is clicked out of many (and in what situation) and for that reason I prefer the Say() function to PlaySound() :wink:

Tomasz, thank you for additional information. I avoid using RequestTimedRefresh() in my codes at all costs. I used it here just because Herman wanted a Trigger Button and after using:

GuiSetText( "Button " + i + " clicked", i );

… the button after being clicked, changes it’s text to “Button x clicked”, but if the chart is not refreshed, the button’s text, doesn’t return to it’s default. So it was just for presentation purpose.

But I have just come up with this solution which doesn’t force any regular refreshes, just one after clicking the button - what after displaying a custom text, allow the button to display it’s default text again (without any regular refreshes at all):

GuiSetFont( "Lucida Console", 10 );

GuiButton( "ButtonTrigger1", 1, 0, 50, 200, 30, 7 );
GuiButton( "ButtonTrigger2", 2, 200, 50, 200, 30, 7 );
GuiButton( "ButtonTrigger3", 3, 400, 50, 200, 30, 7 );
GuiSetColors( 1, 3, 2, colorRed, colorBlack, colorRed, colorWhite, colorBlue, colorYellow, colorRed, colorBlack, colorYellow );

id = GuiGetEvent( 0, 0 );
event = GuiGetEvent( 0, 1 );

for( i = 1; i <= 3; i++ )
{
    if( id == i && event == 1 )
    {
        Say( "Button " + i + " clicked" );
        GuiSetText( "Button " + i + " clicked", i );
        RequestTimedRefresh(1);
    }
}

… and it works :slight_smile:

3 Likes

Very nice Milosz! Looks impressive. I use nested loops to create columns and rows of gfx buttons, so yes, I know the benefit of loops.

Thanks you Tomasz, I look forward to the next release.

Herman

1 Like

Thanks you for your offer!

Yes, I’d like to run your code. I’d love to try it.

Herman

1 Like

hi Herman,

test code is below. It enables dragging of a GUI button pack. You can change the thickness of the “dragging border rim” in the param window. For me it works good enough but if anyone can make it better please go ahead :smiley:

// Test Code: Drag GUI Button-Pack using mouse, E.M.Pottasch, 8/10/2017
// Button pack can be dragged smoothly with the left mouse button pushed
// down in the border area, but will finally settle in nearest Row and
// Column once the left mouse button is lifted

Version( 6.25 );
GfxSetCoordsMode( 0 );
RequestMouseMoveRefresh();
GfxSetZOrder( 2 );
reset = ParamTrigger( "Reset Button Pack Position", "Press Here" );
//DragLock = ParamToggle( "Lock Dragging of Buttons", "On|Off", 1 );
CellHeight = Param( "Cell Height (Pixels)", 20, 5, 200, 1 );
CellWidth = Param( "Cell Width (Pixels)", 95, 5, 200, 1 );
CellXSpace = Param( "Space Between Buttons X Direction (Pixels)", 0, 0, 50, 1 );
CellYSpace = Param( "Space Between Buttons Y Direction (Pixels)", 0, 0, 50, 1 );
transx = Param( "Small Move Button Pack along X-Axis (Pixels)", 0, 0, 2000, 1 );
transy = Param( "Small Move Button Pack along Y-Axis (Pixels)", 0, 0, 2000, 1 );
DragBorderWidth = Param( "Drag Border Width (Pixels)", 10, 0, 500, 1 );
rm = RadioButtonLeftMargin = Param( "Radion Button Left Margin (Pixels)", 2, 0, 10, 1 );
FontPointsize = Param( "Font Pointsize", 10, 1, 50, 1 );
FontType = ParamList( "Font Type", "Segoe UI|Tahoma|Arial|Arial Black|Verdana|Courier New|Times New Roman|Lucida Sans Unicode|Trebuchet MS|Lucida Console", 3 );
ButtonclrBack = ParamColor( "Button Back Color", ColorRGB( 254, 254, 0 ) );
per1 = Param( "Period 1", 20, 1, 500, 1 );
per2 = Param( "Period 2", 80, 1, 500, 1 );
per3 = Param( "Period 3", 110, 1, 500, 1 );
per4 = Param( "Period 4", 150, 1, 500, 1 );
per5 = Param( "Period 5", 210, 1, 500, 1 );

cid = NumToStr( GetChartID() ) + "ProgramName";

id_1 = 40;
id_2 = 41;
id_3 = 42;
id_4 = 43;
id_5 = 44;
GuiSetFont( FontType, FontPointsize );

id0 = GuiGetEvent( 0, 0 );
id1 = GuiGetEvent( 0, 1 ); // returns notify flag (1 ==> click event)
clickevent = id1 == 1;

x0 = transx;
y0 = transy;
GfxSelectSolidBrush( ButtonclrBack );
pp = 0;
nn = 1;

for( i = id_1; i <= id_5; i++ )
{
    GuiRadio( "Radio " + i, i, x0 + ( CellWidth + CellXSpace ) * ( Nz( StaticVarGet( "Column" + cid ) ) + 0 ), y0 + ( CellHeight + CellYSpace ) * ( Nz( StaticVarGet( "Row" + cid ) ) + nn ), CellWidth, CellHeight, 1 );
    x1 = x0 + ( CellWidth + CellXSpace ) * ( Nz( StaticVarGet( "Column" + cid ) ) + 0 ) - rm;
    y1 = y0 + ( CellHeight + CellYSpace ) * ( Nz( StaticVarGet( "Row" + cid ) ) + nn ) - ( CellYSpace + 0 );
    x2 = x1 + CellWidth + rm;
    y2 = y1 + CellHeight + ( CellYSpace + 0 );
    x3 = 0;
    y3 = 0;
    GfxRoundRect( x1, y1, x2, y2, x3, y3 );

    if( i == id_1 )
    {
        xmin = x1 - DragBorderWidth;
        ymin = y1 - DragBorderWidth;
    }

    if( i == id_5 )
    {
        xmax = x2 + DragBorderWidth;
        ymax = y2 + DragBorderWidth;
    }

    nn++;
}

// at startup
if( Nz( StaticVarGet( "startval" ) ) == 0 )
{
    prevcheck = 0;

    for( i = id_1; i <= id_5; i++ )
    {
        if( Nz( StaticVarGet( "StaticGuiGetCheck" + cid + i ) ) == 1 )
        {
            GuiSetCheck( i, 1 );
            prevcheck = 1;
        }
        else
        {
            GuiSetCheck( i, 1 );
        }
    }

    if( prevcheck == 0 )
    {
        GuiSetCheck( id_1, 1 );
        StaticVarSet( "StaticGuiGetCheck" + cid + id_1, 1, 1 );
    }

    Say( "startup" );

    StaticVarSet( "startval", 1 );

    StaticVarSet( "DragToggle" + cid, 0 );

    // if column and row not already set at startup then set both to 0
    if( Nz( StaticVarGet( "Column" + cid ) ) == 0 )
    {
        StaticVarSet( "Column" + cid, 0, 1 );
    }

    if( Nz( StaticVarGet( "Row" + cid ) ) == 0 )
    {
        StaticVarSet( "Row" + cid, 0, 1 );
    }
}

DragToggle = StaticVarGet( "DragToggle" + cid );

if( Nz( StaticVarGet( "DragClicked" + cid ) ) )
{
    if( Nz( StaticVarGet( "DragToggle" + cid ) ) )
    {
        StaticVarSet( "DragToggle" + cid, 0 );
        StaticVarSet( "DragClicked" + cid, 0 );
    }
    else
    {
        StaticVarSet( "DragToggle" + cid, 1 );
        StaticVarSet( "DragClicked" + cid, 0 );

    }
}

if( reset == 1 )
{
    StaticVarSet( "Column" + cid, 0, 1 );
    StaticVarSet( "Row" + cid, 0, 1 );

    Say( "Reset Button Pack Position" );
    RequestTimedRefresh( 0.1 ); // force chart refresh
}

// radio button toggle
if( clickevent )
{
    for( i = id_1; i <= id_5; i++ )
    {
        if( i == id0 )
        {
            GuiSetCheck( i, 1 );
            StaticVarSet( "StaticGuiGetCheck" + cid + i, 1, 1 );
            Say( "set radio button number" + i );
        }
        else
        {
            GuiSetCheck( i, 0 );
            StaticVarSet( "StaticGuiGetCheck" + cid + i, 0, 1 );
        }
    }
}

// set radio button at each refresh (possibly no longer needed in next beta)
for( i = id_1; i <= id_5; i++ )
{
    GuiSetCheck( i, Nz( StaticVarGet( "StaticGuiGetCheck" + cid + i ) ) );
}

function OnLMouseButton( px, py )
{
    StaticVarSet( "startpx" + cid, px );
    StaticVarSet( "startpy" + cid, py );

    if( px > xmin AND px < xmax AND py > ymin AND py < ymax )
    {
        StaticVarSet( "DragClicked" + cid, 1 );
    }
}

function OnLButtonIsDown( px, py )
{
    Col0 = StaticVarGet( "Column" + cid );
    Row0 = StaticVarGet( "Row" + cid );

    spx = StaticVarGet( "startpx" + cid );
    spy = StaticVarGet( "startpy" + cid );

    dpx = ( px - spx );
    dpy = ( py - spy );

    dCol = ( dpx / CellWidth );
    dRow = ( dpy / CellHeight );

    StaticVarSet( "Column" + cid,  Max( 0, ( dCol + Col0 ) ), 1 );
    StaticVarSet( "Row" + cid, Max( 0, ( dRow + Row0 ) ), 1 );

    StaticVarSet( "startpx" + cid, px );
    StaticVarSet( "startpy" + cid, py );
}

if( DragToggle )
{
    GfxSetZOrder( 1 );
    GfxSelectSolidBrush( ColorRGB( 0, 0, 254 ) );
    GfxRoundRect( xmin, ymin, xmax, ymax, 0, 0 );
    GfxSetZOrder( 0 );
}

function OnHoverMouse( px, py )
{
    GfxSetZOrder( 1 );
    GfxSelectSolidBrush( ColorRGB( 0, 254, 0 ) );
    GfxRoundRect( xmin, ymin, xmax, ymax, 0, 0 );
    GfxSetZOrder( 0 );
}

function EventHandler()
{
    b = GetCursorMouseButtons();
    px = GetCursorXPosition( 1 );
    py = GetCursorYPosition( 1 );

    if( b & 8 )
    {
        if( b & 1 ) OnLMouseButton( px, py );
    }
    else
    {
        if( b == 0 )
        {
            if( px > xmin AND px < xmax AND py > ymin AND py < ymax )
            {
                OnHoverMouse( px, py );
            }

            // settle button pack to the nearest Row and Column
            StaticVarSet( "Column" + cid, round( Nz( StaticVarGet( "Column" + cid ) ) ), 1 );
            StaticVarSet( "Row" + cid, round( Nz( StaticVarGet( "Row" + cid ) ) ), 1 );
            StaticVarSet( "DragToggle" + cid, 0 );
            //_TRACE("px: " + px + " py: " + py );
        }

        if( b == 1 AND DragToggle ) OnLButtonIsDown( px, py );
    }
}

EventHandler();

GraphXSpace = 5;
SetChartBkColor( ColorBlack );
SetChartOptions( 0, chartShowDates );
SetBarFillColor( IIf( C > O, ColorRGB( 0, 75, 0 ), IIf( C <= O, ColorRGB( 75, 0, 0 ), colorLightGrey ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 250, 0 ), IIf( C <= O, ColorRGB( 250, 0, 0 ), colorLightGrey ) ), 64, Null, Null, 0, 0, 1 );

for( i = id_1; i <= id_5; i++ )
{
    gc = GuiGetCheck( i );

    if( gc == 1 AND i == 40 )
    {
        pp = per1;
    }

    if( gc == 1 AND i == 41 )
    {
        pp = per2;
    }

    if( gc == 1 AND i == 42 )
    {
        pp = per3;
    }

    if( gc == 1 AND i == 43 )
    {
        pp = per4;
    }

    if( gc == 1 AND i == 44 )
    {
        pp = per5;
    }
}

if( pp > 0 )
    Plot( MA( C, pp ), "", colorYellow, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );

Title = "Test Code [ Move Button Pack ]";
5 Likes

Thank you very much Ed, your code works very smooth. Never thought of adding a popup-grab-border to my gfx objects, this might be an idea I might use in some applications.

I replaced your RequestMouseMoveRefresh() with RequestTimedRefresh(0.1) in my copy because the RequestMouseMoveRefresh() locks up my GUI functions. Please note that GUIButtons are not compatible with fast timed refreshes, see TJs earlier post.

Right now I am lost wrt GUIButtons. Without timed refreshes my gfx doesn’t work and with it my GUI functions lock up, but perhaps all this will become clear later.

Thanks again for sharing your code,
Happy coding,
Herman

hi Herman,

I didn’t notice this lockup problem. I will look up TJ’s post on this but the way I understand it is that once the mouse is in the area of the new GUI buttons requestmousemoverefresh() does not refresh, or the function does not generate chart refreshes.

so if you add

_TRACE("refresh");

at the bottom of my test code and then hover over the button pack you will see no refreshes but the GUI buttons work normally. Only when the mouse leaves the GUI button pack area then the requestmousemoverefresh() function starts generation chart refreshes again.

I understand, that the code above is exerimental and presented mainly for educational purposes :wink: but I think, that using RequestTimedRefresh(0.1) or RequestMouseMoveRefresh() and forcing AmiBroker to refresh chart 10 times per second (in the first case) and even many times more whenever mouse is in the chart area (in the second case) just to be able to drag GuiButtons is an overkill. This option will be used very rarely (and can be achieved using Param sliders or even Gui Butons) but will make the code (constantly) even dozens of times more demanding for the CPU. It is an interesting exercise - I like it, but its practical application is very controversial :wink:

I have made a couple of different codes using GuiButtons, and I don’t use any extra refreshes at all. The only exception is in one of my posts above and concerns the Trigger Button which after being clicked should display some custom text and after a while display back it’s default text. At first I couldn’t find a way how to make it possible “in just one run” without any other regular refreshes being present (in a situation when refreshes occur only as a result of user interaction). But I managed to accomplish this using RequestTimedRefresh(n seconds) conditionally only once - when the button is clicked. As in the example above. It does its job and leaves the code without any extra refreshes at all. For example try using conditionally RequestTimedRefresh(5) and the button will display back it’s default text after a couple of seconds. Maybe there’s another (better) way how to accomplish it - I don’t know. If yes, I am very keen to learn how.

Let’s wait for some more examples and tips provided by Tomasz…

1 Like

yes true, I also made a version using GUI buttons but when dragging the pack you will need to use at least RequestMouseMoveRefresh() together with the other mouse functions to get the location of the mouse.

Dragging buttons seems a little over the top but I am making plugins that can be dragged on top of a chart and each plugin will have its own button pack. Not sure exactly yet how I will handle this :slight_smile: but then dragging of buttons will be handy to get buttons packs out of the way.

In any case to use the GUI radio buttons now we need RequestMouseMoveRefresh() because GuiSetCheck has to be set at each refresh (but this will go in the next beta if I understood correctly).

But yes, will wait for the example code that comes with v6.3. However, I do not see how dragging of buttons can be done without knowing the location of the mouse and therefor the mouse functions are needed, and they need RequestMouseMoveRefresh() to work correctly.

@Milosz coding shows correct approach (avoiding refreshes).

@empottasch - Buttons in Windows OS are not draggable

1 Like