In a previous tutorial you have learned how to realize a composite widget (a class called MyFirstWidget) by using the Designer. That class was very simple with just three elementary widgets (editfield, button, and label) performing a minimalist interaction among them.

In this new tutorial instead you'll see how to realize a more complex application that put a new problem and how to solve it. In particular we focus on the callback. Here I assume you know what a callback is (see the documentation otherwise), while I'll try to show where a callback should be definite to achieve a given aim.
Our next application is a class containing two instances of the class MyFirstWidget. It is a very stupid application but it is useful to show the problem that commonly occur when we project a complex GUI. Here is the code of the application:
#include <CtrlLib/CtrlLib.h>
#define LAYOUTFILE <TutorialDesigner/mywidget.lay>
#include <CtrlCore/lay.h>/////////////////////////// Begin class MyFirstWidget /////////////
class MyFirstWidget : public WithMyFirstWidget<TopWindow> {
public:
void BtnPush()
{ String s= ~edit; // get the string in edit
lbl.SetLabel(s); // set the string in the label
edit <<= Null; // clear edit
}typedef MyFirstWidget CLASSNAME;
MyFirstWidget();
};MyFirstWidget::MyFirstWidget() // constructor
{ CtrlLayout(*this, "");
btn.WhenAction = THISBACK(BtnPush); // callback
}
/////////////////////////// end class MyFirstWidget //////////////////////////////////////// Begin class Application /////////////
class MyApp : public TopWindow {
MyFirstWidget myA, myB;
LabelBox dv;
public:
typedef MyApp CLASSNAME;MyApp();
};MyApp::MyApp() // constructor
{ Add(dv);
dv.SetLabel("MyApp").LeftPosZ(24, 420).TopPosZ(16, 444);
Add(myA);
myA.LeftPosZ(50, 372).TopPosZ(204, 100);
Add(myB);
myB.LeftPosZ(50, 372).TopPosZ(48, 100);
}
/////////////////////////// end class Application /////////////
GUI_APP_MAIN
{ MyApp app;
app.Sizeable().Run(); // run the application
}// mywidget.lay file
LAYOUT(MyFirstWidget, 372, 116)
ITEM(LabelBox, dv___0, SetLabel(t_("MyWidget")).LeftPosZ(32, 308).TopPosZ(12, 88))
ITEM(Label, lbl, SetFrame(ThinInsetFrame()).LeftPosZ(248, 72).TopPosZ(44, 22))
ITEM(Button, btn, SetLabel(t_("move string =>s")).LeftPosZ(136, 92).TopPosZ(44, 22))
ITEM(EditString, edit, LeftPosZ(52, 60).TopPosZ(44, 22))
END_LAYOUT
This is how the application looks

Each label box (the rectangular thin frame) delimit graphically each class. This help us to recognize the presence of the class with wich we deal. So in the previous picture we can see in action two instances of MyFistWidget, myA and myB, inside a MyApp instance. In each of the MyFirstWidget there is an edit field, a button and a label. Now it is important to recognise that, for example, the label of myA "cannot see" the label of myB. In general each instance is not aware of the presence of the other. In fact the methods of the instance of myA can only operate inside myA on its own objects without the possibility to operate on those of myB, and vice versa of course.
In the previous picture you can found an analogy with the mathematics concept of set and subset. The elements of myA do not belong to MyB and vice versa. However myA and myB are inside a wider class, MyApp. So what belong to myA and myB belong to MyApp too. In other words the methods of MyApp could look into MyA and MyB and use their methods and objects.
To make more clear the discussion let's try to resolve the following problem. I want that when I press the button of myA the string at its left should be set in the label of myB, and vice versa. This is not what the instance myA and myB does normally. How should be modified the code to achieve this aim?
If we think a bit, we realize that the callback of MyFirstwidget associate to the button
btn.WhenAction = THISBACK(BtnPush);
that run the method
void BtnPush()
{ String s= ~edit; // get the string in edit
lbl.SetLabel(s); // set the string in the label
edit <<= Null; // clear edit
}
cannot do the job we want. In fact BtnPush cannot see myB and has no access to its label. So this callback can read its own edit field ( String s= ~edit; ) but cannot put the its value in the label of the other widget.
Who can perform this task? Of course who can enter in both MyA and MyB: MyApp! This means that the callback associate to the button should be defined in MyApp that can see both widgets; in particular the callback should be defined in the constructor of MyApp as follow:
#include <CtrlLib/CtrlLib.h>
#define LAYOUTFILE <TutorialDesigner/mywidget.lay>
#include <CtrlCore/lay.h>
/////////////////////////// Begin class MyFirstWidget /////////////
class MyFirstWidget : public WithMyFirstWidget<TopWindow> {
public:
void BtnPush()
{ String s= ~edit; // get the string in edit
lbl.SetLabel(s); // set the string in the label
edit <<= Null; // clear edit
}
typedef MyFirstWidget CLASSNAME;
MyFirstWidget();
};
MyFirstWidget::MyFirstWidget()
{ CtrlLayout(*this, "");
// btn.WhenAction = THISBACK(BtnPush); // removed because
useless
}
/////////////////////////// end class MyFirstWidget /////////////
///////////////////////////
Begin class Application /////////////
class MyApp : public TopWindow {
MyFirstWidget myA, myB;
LabelBox dv;
public:
void ExchangeAtoB();
void ExchangeBtoA();
typedef MyApp CLASSNAME;
MyApp();
};
void MyApp::ExchangeAtoB()
{ String s= ~myA.edit; // get the string in edit of MyA
myB.lbl.SetLabel(s); // set the string in the label of myB
myA.edit <<= Null; // clear edit of myA
}
void MyApp::ExchangeBtoA()
{ String s= ~myB.edit; // get the string in edit of myB
myA.lbl.SetLabel(s); // set the string in the label of myA
myB.edit <<= Null; // clear edit of myB
}
MyApp::MyApp()
{ Add(dv);
dv.SetLabel("MyApp").LeftPosZ(24, 420).TopPosZ(16, 444);
Add(myA);
myA.LeftPosZ(50, 372).TopPosZ(204, 100);
Add(myB);
myB.LeftPosZ(50, 372).TopPosZ(48, 100);
// the buttons are activated at the extern of MyA and MyB
myA.btn.WhenAction = THISBACK(ExchangeAtoB);
myB.btn.WhenAction = THISBACK(ExchangeBtoA);
}
/////////////////////////// end class Application /////////////
GUI_APP_MAIN
{ MyApp app;
app.Sizeable().Run();
}
In the previous code you should pay attention at the new syntax that permits to "enter" in myA and myB from MyApp.