Help with Callbacks

Started by Xerum, 09 November 2016, 00:53:17

Xerum

I'm sure this may seem like a relatively "dumb" or easy to answer question, but I'm having the hardest time understanding the documentation on callbacks for .07. For example your menu example of .06 is:
tgui::MenuBar::Ptr menu(gui);
    menu->load(THEME_CONFIG_FILE);
    menu->setSize(window.getSize().x, 20);
    menu->addMenu("File");
    menu->addMenuItem("File", "Load");
    menu->addMenuItem("File", "Save");
    menu->addMenuItem("File", "Exit");
    menu->bindCallback(tgui::MenuBar::MenuItemClicked);
    menu->setCallbackId(2);


In version .07 how do I add callback to a widget?

texus

You can find a tutorial about it here: https://tgui.eu/tutorials/v0.7/signals-introduction/

You basically no longer have a callback loop where you poll for callbacks but instead you call a certain function when something happens. You bind this function by calling the connect function.

Example:
Code (cpp) Select
void f() { std::cout << "clicked on some menu item" << std::endl; }
menu->connect("MenuItemClicked", f);


In this case you probably want to know on which menu item you clicked, so you can use the following code (unless you use VS2013 in which case you need an alternative way involving the connectEx function)
Code (cpp) Select
void f(std::string item) { std::cout << item << std::endl; } // will print e.g. "Exit"
menu->connect("MenuItemClicked", f);


or using a lambda function:
Code (cpp) Select
menu->connect("MenuItemClicked", [](std::string item){ std::cout << item << std::endl; });

Xerum

#2
Thank you for the help!

texus

There are a few ways to do this depending on the situation. Since you are talking about the main function I doubt you are using classes so I'll show an example with just a normal callback function. But for more complex situations it might be worth having the callback function in the same class as the code that needs it so that you can just access member variables instead of having to pass everything you need as parameters to the function. But here I will just pass the gui and the panel as parameters:
Code (cpp) Select
void func(tgui::Gui& gui, tgui::Panel::Ptr panel, const std::string& item)
{
    if (item == "Debug")
        gui.add(panel);
}

menuBar->connect("MenuItemClicked", func, std::ref(gui), debugWindow);


Note that you pass 2 parameters to the connect function that are intended for the func callback function. When a menu item gets clicked, these parameters (a reference to the gui and the debug panel) will be passed as the first 2 parameters to func, while the remaining parameter (the string) will be provided by the gui and for menu bars will contain the item that you clicked on. Note that in order to pass a reference, you have to both use std::ref at the connect call and have the "&" when declaring func. If either is missing then it will still compile but you will copy the parameter instead of passing a reference. In this example a copy of debugWindow is made at the moment you call the connect function, this shouldn't be a problem since it is a pointer but if it would be a nullptr at the moment that you call the connect function and only assign a value later then the func still gets nullptr as parameter. So depending on where you initialize debugWindow you might also need to pass the panel pointer as a reference. I hope that the explanation makes some sense to you.

edit: I only saw that you removed your question after I finished writing my reply :)

Normand Blais

Using:

   mMenuBar->addMenu("File");
   mMenuBar->addMenuItem("File", "Load");
   mMenuBar->addMenuItem("File", "Save");
   mMenuBar->addMenuItem("File", "Exit");
   mMenuBar->connect("MenuItemClicked", [&]() { mWindow.close(); });

Any selection closes the application. How can I restrict the action to only one item ("Exit" for instance). I use TGUI 0.7.2 and SFML 2.4.1. My compiler is Visual Studio 2015.

Thanks,

Norm

texus

The function is called on any action, so you have to check it inside the callback function itself.
Which item you clicked is passed as optional argument to the function, so the callback function has to look like this:
Code (cpp) Select
[&](const sf::String& item) {
    if (item == "Exit")
        mWindow.close();
}

Normand Blais

>> [&](const sf::String& item) {
>>     if (item == "Exit")
>>        mWindow.close();
>> }

I did try that but I could not get the code to compile.

1>  Game.cpp
1>d:\programs\visual studio\vc\include\type_traits(1441): error C2672: 'std::invoke': no matching overloaded function found
1>  d:\programs\visual studio\vc\include\functional(792): note: see reference to function template instantiation '_Rx std::_Invoke_ret<std::_Unforced,_Cv_FD&>(std::_Forced<_Rx,false>,_Cv_FD &)' being compiled
1>          with
1>          [
1>              _Rx=std::_Unforced,
1>              _Cv_FD=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\programs\visual studio\vc\include\functional(847): note: see reference to function template instantiation '_Rx std::_Call_binder<std::_Unforced,,_Ty1,_Ty2,std::tuple<>>(std::_Forced<_Rx,false>,std::integer_sequence<_Ty>,_Cv_FD &,_Cv_tuple_TiD &,_Untuple &&)' being compiled
1>          with
1>          [
1>              _Rx=std::_Unforced,
1>              _Ty1=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>,
1>              _Ty2=std::tuple<>,
1>              _Ty=size_t,
1>              _Cv_FD=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>,
1>              _Cv_tuple_TiD=std::tuple<>,
1>              _Untuple=std::tuple<>
1>          ]
1>  d:\programs\visual studio\vc\include\type_traits(1349): note: see reference to function template instantiation '_Rx std::_Binder<std::_Unforced,Func &>::operator ()<>(void)' being compiled
1>          with
1>          [
1>              _Rx=std::_Unforced,
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\programs\visual studio\vc\include\type_traits(1348): note: see reference to function template instantiation '_Rx std::_Binder<std::_Unforced,Func &>::operator ()<>(void)' being compiled
1>          with
1>          [
1>              _Rx=std::_Unforced,
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\programs\visual studio\vc\include\type_traits(1417): note: see reference to function template instantiation '_Rx std::_Invoker_functor::_Call<_Callable&,>(std::_Binder<std::_Unforced,Func &>)' being compiled
1>          with
1>          [
1>              _Rx=std::_Unforced,
1>              _Callable=_Decayed,
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\programs\visual studio\vc\include\type_traits(1434): note: see reference to function template instantiation '_Rx std::invoke<_Callable&,>(std::_Binder<std::_Unforced,Func &>)' being compiled
1>          with
1>          [
1>              _Rx=std::_Unforced,
1>              _Callable=_Decayed,
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\programs\visual studio\vc\include\functional(208): note: see reference to function template instantiation 'void std::_Invoke_ret<_Rx,_Callable&>(std::_Forced<_Rx,true>,_Callable &)' being compiled
1>          with
1>          [
1>              _Rx=void,
1>              _Callable=_Decayed
1>          ]
1>  d:\programs\visual studio\vc\include\functional(206): note: while compiling class template member function 'void std::_Func_impl<_Decayed,_Alloc,_Ret>::_Do_call(void)'
1>          with
1>          [
1>              _Alloc=std::allocator<int>,
1>              _Ret=void
1>          ]
1>  d:\programs\visual studio\vc\include\functional(134): note: see reference to class template instantiation 'std::_Func_impl<_Decayed,_Alloc,_Ret>' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<int>,
1>              _Ret=void
1>          ]
1>  d:\programs\visual studio\vc\include\functional(337): note: see reference to class template instantiation 'std::_Is_large<_Myimpl>' being compiled
1>  d:\programs\visual studio\vc\include\functional(316): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset_alloc<_Ty,std::allocator<int>>(_Fx &&,const _Alloc &)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              _Ty=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>,
1>              _Fx=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>,
1>              _Alloc=std::allocator<int>
1>          ]
1>  d:\programs\visual studio\vc\include\functional(316): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset_alloc<_Ty,std::allocator<int>>(_Fx &&,const _Alloc &)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              _Ty=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>,
1>              _Fx=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>,
1>              _Alloc=std::allocator<int>
1>          ]
1>  d:\programs\visual studio\vc\include\functional(482): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset<std::_Binder<std::_Unforced,Func &>>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>,
1>              _Fx=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>
1>          ]
1>  d:\programs\visual studio\vc\include\functional(482): note: see reference to function template instantiation 'void std::_Func_class<_Ret>::_Reset<std::_Binder<std::_Unforced,Func &>>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Ret=void,
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>,
1>              _Fx=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>
1>          ]
1>  d:\tgui\tgui-0.7.2-vc14-32bit-for-sfml-2.4.1\tgui-0.7\include\tgui\signal.hpp(160): note: see reference to function template instantiation 'std::function<void (void)>::function<std::_Binder<std::_Unforced,Func &>>(_Fx)' being compiled
1>          with
1>          [
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>,
1>              _Fx=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>
1>          ]
1>  d:\tgui\tgui-0.7.2-vc14-32bit-for-sfml-2.4.1\tgui-0.7\include\tgui\signal.hpp(160): note: see reference to function template instantiation 'std::function<void (void)>::function<std::_Binder<std::_Unforced,Func &>>(_Fx)' being compiled
1>          with
1>          [
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>,
1>              _Fx=std::_Binder<std::_Unforced,Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &>
1>          ]
1>  d:\tgui\tgui-0.7.2-vc14-32bit-for-sfml-2.4.1\tgui-0.7\include\tgui\signal.hpp(159): note: while compiling class template member function 'std::function<void (void)> tgui::priv::connector<type,Func>::connect(Func,size_t)'
1>          with
1>          [
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\tgui\tgui-0.7.2-vc14-32bit-for-sfml-2.4.1\tgui-0.7\include\tgui\signal.hpp(251): note: see reference to function template instantiation 'std::function<void (void)> tgui::priv::connector<type,Func>::connect(Func,size_t)' being compiled
1>          with
1>          [
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\tgui\tgui-0.7.2-vc14-32bit-for-sfml-2.4.1\tgui-0.7\include\tgui\signal.hpp(251): note: see reference to class template instantiation 'tgui::priv::connector<type,Func>' being compiled
1>          with
1>          [
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\tgui\tgui-0.7.2-vc14-32bit-for-sfml-2.4.1\tgui-0.7\include\tgui\signal.hpp(365): note: see reference to function template instantiation 'void tgui::Signal::connect<Func,>(unsigned int,Func)' being compiled
1>          with
1>          [
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>  d:\slip\projects\slipboard\game.cpp(99): note: see reference to function template instantiation 'unsigned int tgui::SignalWidgetBase::connect<Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>,>(const std::string &,Func)' being compiled
1>          with
1>          [
1>              Func=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683>
1>          ]
1>d:\programs\visual studio\vc\include\type_traits(1441): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
1>  d:\programs\visual studio\vc\include\type_traits(1441): note: With the following template arguments:
1>  d:\programs\visual studio\vc\include\type_traits(1441): note: '_Callable=Game::{ctor}::<lambda_8d0a58af01f3e7092cc3ce1902335683> &'
1>  d:\programs\visual studio\vc\include\type_traits(1441): note: '_Types={}'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

texus

#7
I'll have to look into that. Perhaps in the meantime you can use code like this and check if that works:
Code (cpp) Select
void function(sf::RenderWindow& window, const sf::String& item)
{
    if (item == "Exit")
        mWindow.close();
}

mMenuBar->connect("MenuItemClicked", function, std::ref(mWindow));


Unfortunately my windows drive got corrupted a few days ago so it will take a few hours/days before I have everything up and running again to test that code and find out why it doesn't compile.

EDIT: Are you using the latest update of VS2015? You need at least update 2 to have full support for the connect function.

Normand Blais

OK. I have upgraded Visual Studio 2015 to the latest version (Update 3). It's now working. Thanks for your help and thank you for TGUI. SFML and TGUI make my day.

Norm