Add a "signals and callbacks" chapter into the first steps document
This commit is contained in:
parent
831e9fe05e
commit
17540c9581
|
@ -1,3 +1,8 @@
|
||||||
|
2018-12-28 Markus Gans <guru.mail@muenster.de>
|
||||||
|
* Add the assignment operator (=) for FButton to set the button text
|
||||||
|
* Corrected shortening of overlong texts in the title bar of FDialog
|
||||||
|
* Add a "signals and callbacks" chapter into the first steps document
|
||||||
|
|
||||||
2018-12-25 Markus Gans <guru.mail@muenster.de>
|
2018-12-25 Markus Gans <guru.mail@muenster.de>
|
||||||
* Add a "event processing" chapter into the first steps document
|
* Add a "event processing" chapter into the first steps document
|
||||||
|
|
||||||
|
|
|
@ -302,3 +302,302 @@ the above program with gcc:
|
||||||
```cpp
|
```cpp
|
||||||
g++ -O2 -std=c++11 -lfinal timer.cpp -o timer
|
g++ -O2 -std=c++11 -lfinal timer.cpp -o timer
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Signals and Callbacks
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The callback mechanism is essential for developing applications with
|
||||||
|
FINAL CUT. Callback routines allow the programmer to connect different
|
||||||
|
objects (which do not need to know each other). Connected objects notify
|
||||||
|
each other when an action occurs in a widget. To uniquely identify a widget
|
||||||
|
action, it uses signal strings. For example, if an `FButton` object gets
|
||||||
|
clicked by a keyboard or mouse, it sends the string "clicked". A signal
|
||||||
|
handler explicitly provided by Widget, in the form of a callback function
|
||||||
|
or a callback method, can react to such a signal.
|
||||||
|
|
||||||
|
A callback function is always structured as follows:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void cb_function (FWidget* w, FDataPtr data)
|
||||||
|
{...}
|
||||||
|
```
|
||||||
|
|
||||||
|
The structure of a callback method is the same:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void classname::cb_methode (FWidget* w, FDataPtr data)
|
||||||
|
{...}
|
||||||
|
```
|
||||||
|
|
||||||
|
We use the `addCallback()` method of the `FWidget` class to connect
|
||||||
|
to other widget objects.
|
||||||
|
|
||||||
|
For calling functions and static methods:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void FWidget::addCallback ( const FString& cb_signal
|
||||||
|
, FCallback cb_handler
|
||||||
|
, FDataPtr data )
|
||||||
|
{...}
|
||||||
|
```
|
||||||
|
|
||||||
|
For calling a member method of a specific instance:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void FWidget::addCallback ( const FString& cb_signal
|
||||||
|
, FWidget* cb_instance
|
||||||
|
, FMemberCallback cb_handler
|
||||||
|
, FDataPtr data )
|
||||||
|
{...}
|
||||||
|
```
|
||||||
|
|
||||||
|
There are two macros `F_FUNCTION_CALLBACK` and `F_METHOD_CALLBACK` to avoid
|
||||||
|
having to deal with necessary type conversions. With `delCallback()` you can
|
||||||
|
remove a connection to a signal handler or a widget. Alternatively, you can
|
||||||
|
use `delCallbacks()` to remove all existing callbacks from an object.
|
||||||
|
|
||||||
|
|
||||||
|
### Example of a callback function: ###
|
||||||
|
|
||||||
|
**File:** *callback-function.cpp*
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <final/final.h>
|
||||||
|
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
void cb_changeText (FWidget* w, FDataPtr data)
|
||||||
|
{
|
||||||
|
FButton& button = *(static_cast<FButton*>(w));
|
||||||
|
FLabel& label = *(static_cast<FLabel*>(data));
|
||||||
|
label.clear();
|
||||||
|
label << "The " << button.getClassName() << " was pressed";
|
||||||
|
label.redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char* argv[])
|
||||||
|
{
|
||||||
|
FApplication app(argc, argv);
|
||||||
|
FDialog dialog(&app);
|
||||||
|
dialog.setText ("A dialog with callback function");
|
||||||
|
dialog.setGeometry (25, 5, 45, 9);
|
||||||
|
FLabel label (&dialog);
|
||||||
|
label = "The button has never been pressed before";
|
||||||
|
label.setGeometry (2, 2, 41, 1);
|
||||||
|
FButton button (&dialog);
|
||||||
|
// Character follows '&' will be used as the accelerator key
|
||||||
|
button = "&Click me";
|
||||||
|
button.setGeometry (15, 5, 14, 1);
|
||||||
|
|
||||||
|
// Connect the button signal "clicked" with the callback function
|
||||||
|
button.addCallback
|
||||||
|
(
|
||||||
|
"clicked",
|
||||||
|
F_FUNCTION_CALLBACK (&cb_changeText),
|
||||||
|
&label
|
||||||
|
);
|
||||||
|
|
||||||
|
app.setMainWidget(&dialog);
|
||||||
|
dialog.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*(Note: You can close the dialog with the mouse,
|
||||||
|
<kbd>Shift</kbd>+<kbd>F10</kbd> or <kbd>Ctrl</kbd>+<kbd>^</kbd>)*
|
||||||
|
|
||||||
|
|
||||||
|
After entering the source code in *callback-function.cpp* you can compile
|
||||||
|
the above program with gcc:
|
||||||
|
```cpp
|
||||||
|
g++ -O2 -lfinal callback-function.cpp -o callback-function
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Example of a callback method: ###
|
||||||
|
|
||||||
|
**File:** *callback-method.cpp*
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <final/final.h>
|
||||||
|
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
class dialogWidget : public FDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit dialogWidget (FWidget* parent = nullptr)
|
||||||
|
: FDialog(parent)
|
||||||
|
{
|
||||||
|
setText ("Callback method");
|
||||||
|
setGeometry (25, 5, 25, 7);
|
||||||
|
button.setGeometry (7, 3, 10, 1);
|
||||||
|
|
||||||
|
// Connect the button signal "clicked" with the callback method
|
||||||
|
button.addCallback
|
||||||
|
(
|
||||||
|
"clicked",
|
||||||
|
F_METHOD_CALLBACK (this, &FApplication::cb_exitApp),
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FButton button{"&Quit", this};
|
||||||
|
};
|
||||||
|
|
||||||
|
int main (int argc, char* argv[])
|
||||||
|
{
|
||||||
|
FApplication app(argc, argv);
|
||||||
|
dialogWidget dialog(&app);
|
||||||
|
app.setMainWidget(&dialog);
|
||||||
|
dialog.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*(Note: You can close the window with the mouse,
|
||||||
|
<kbd>Shift</kbd>+<kbd>F10</kbd> or <kbd>Ctrl</kbd>+<kbd>^</kbd>)*
|
||||||
|
|
||||||
|
|
||||||
|
After entering the source code in *callback-method.cpp* you can compile
|
||||||
|
the above program with gcc:
|
||||||
|
```cpp
|
||||||
|
g++ -O2 -std=c++11 -lfinal callback-method.cpp -o callback-method
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Send custom signals ###
|
||||||
|
|
||||||
|
You can use the `emitCallback()` method to generate a user-defined signal.
|
||||||
|
You can connect this signal later with the method `addCallback()` to a
|
||||||
|
self-defined routine.
|
||||||
|
|
||||||
|
**File:** *emit-signal.cpp*
|
||||||
|
```cpp
|
||||||
|
#include <final/final.h>
|
||||||
|
|
||||||
|
using namespace finalcut;
|
||||||
|
|
||||||
|
class dialogWidget : public FDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit dialogWidget (FWidget* parent = nullptr)
|
||||||
|
: FDialog(parent)
|
||||||
|
{
|
||||||
|
setGeometry (25, 5, 22, 7);
|
||||||
|
setText ("Emit signal");
|
||||||
|
label.setGeometry (8, 1, 5, 1);
|
||||||
|
label.setAlignment (fc::alignRight);
|
||||||
|
label.setForegroundColor (fc::Black);
|
||||||
|
plus.setGeometry (3, 3, 5, 1);
|
||||||
|
minus.setGeometry (13, 3, 5, 1);
|
||||||
|
plus.setNoUnderline();
|
||||||
|
minus.setNoUnderline();
|
||||||
|
|
||||||
|
// Connect the button signal "clicked" with the callback method
|
||||||
|
plus.addCallback
|
||||||
|
(
|
||||||
|
"clicked",
|
||||||
|
F_METHOD_CALLBACK (this, &dialogWidget::cb_plus)
|
||||||
|
);
|
||||||
|
|
||||||
|
minus.addCallback
|
||||||
|
(
|
||||||
|
"clicked",
|
||||||
|
F_METHOD_CALLBACK (this, &dialogWidget::cb_minus)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Connect own signals
|
||||||
|
addCallback
|
||||||
|
(
|
||||||
|
"hot",
|
||||||
|
F_METHOD_CALLBACK (this, &dialogWidget::cb_set_red)
|
||||||
|
);
|
||||||
|
|
||||||
|
addCallback
|
||||||
|
(
|
||||||
|
"regular",
|
||||||
|
F_METHOD_CALLBACK (this, &dialogWidget::cb_set_black)
|
||||||
|
);
|
||||||
|
|
||||||
|
addCallback
|
||||||
|
(
|
||||||
|
"cold",
|
||||||
|
F_METHOD_CALLBACK (this, &dialogWidget::cb_set_blue)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void cb_plus (FWidget*, FDataPtr)
|
||||||
|
{
|
||||||
|
if ( t < 100 )
|
||||||
|
t++;
|
||||||
|
|
||||||
|
if ( t == 30 )
|
||||||
|
emitCallback("hot");
|
||||||
|
else if ( t == 1 )
|
||||||
|
emitCallback("regular");
|
||||||
|
|
||||||
|
setTemperature();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cb_minus (FWidget*, FDataPtr)
|
||||||
|
{
|
||||||
|
if ( t > -99 )
|
||||||
|
t--;
|
||||||
|
|
||||||
|
if ( t == 0 )
|
||||||
|
emitCallback("cold");
|
||||||
|
else if ( t == 29 )
|
||||||
|
emitCallback("regular");
|
||||||
|
|
||||||
|
setTemperature();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cb_set_blue (FWidget*, FDataPtr)
|
||||||
|
{
|
||||||
|
label.setForegroundColor (fc::Blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cb_set_black (FWidget*, FDataPtr)
|
||||||
|
{
|
||||||
|
label.setForegroundColor (fc::Black);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cb_set_red (FWidget*, FDataPtr)
|
||||||
|
{
|
||||||
|
label.setForegroundColor (fc::Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTemperature()
|
||||||
|
{
|
||||||
|
label.clear();
|
||||||
|
label << t << "°C";
|
||||||
|
label.redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
int t = 20;
|
||||||
|
FLabel label{FString() << t << "°C", this};
|
||||||
|
FButton plus {"&+", this};
|
||||||
|
FButton minus {"&-", this};
|
||||||
|
};
|
||||||
|
|
||||||
|
int main (int argc, char* argv[])
|
||||||
|
{
|
||||||
|
FApplication app(argc, argv);
|
||||||
|
dialogWidget dialog(&app);
|
||||||
|
app.setMainWidget(&dialog);
|
||||||
|
dialog.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
*(Note: You can close the window with the mouse,
|
||||||
|
<kbd>Shift</kbd>+<kbd>F10</kbd> or <kbd>Ctrl</kbd>+<kbd>^</kbd>)*
|
||||||
|
|
||||||
|
|
||||||
|
After entering the source code in *emit-signal.cpp* you can compile
|
||||||
|
the above program with gcc:
|
||||||
|
```cpp
|
||||||
|
g++ -O2 -std=c++11 -lfinal emit-signal.cpp -o emit-signal
|
||||||
|
```
|
||||||
|
|
|
@ -54,6 +54,13 @@ FButton::~FButton() // destructor
|
||||||
delOwnTimer();
|
delOwnTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FButton operator
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
FButton& FButton::operator = (const FString& s)
|
||||||
|
{
|
||||||
|
setText(s);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// public methods of FButton
|
// public methods of FButton
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
|
@ -1130,11 +1130,8 @@ inline void FDialog::drawZoomedButton()
|
||||||
void FDialog::drawTextBar()
|
void FDialog::drawTextBar()
|
||||||
{
|
{
|
||||||
// Fill with spaces (left of the title)
|
// Fill with spaces (left of the title)
|
||||||
std::size_t center_offset
|
std::size_t center_offset = 0;
|
||||||
, width
|
std::size_t x = 1;
|
||||||
, zoom_btn
|
|
||||||
, length
|
|
||||||
, x;
|
|
||||||
|
|
||||||
if ( getMaxColor() < 16 )
|
if ( getMaxColor() < 16 )
|
||||||
setBold();
|
setBold();
|
||||||
|
@ -1144,12 +1141,14 @@ void FDialog::drawTextBar()
|
||||||
else
|
else
|
||||||
setColor (wc.titlebar_inactive_fg, wc.titlebar_inactive_bg);
|
setColor (wc.titlebar_inactive_fg, wc.titlebar_inactive_bg);
|
||||||
|
|
||||||
width = std::size_t(getWidth());
|
std::size_t width = getWidth();
|
||||||
zoom_btn = getZoomButtonWidth();
|
std::size_t zoom_btn = getZoomButtonWidth();
|
||||||
length = tb_text.getLength();
|
std::size_t length = tb_text.getLength();
|
||||||
|
|
||||||
|
if ( width > length + MENU_BTN + zoom_btn )
|
||||||
center_offset = (width - length - MENU_BTN - zoom_btn) / 2;
|
center_offset = (width - length - MENU_BTN - zoom_btn) / 2;
|
||||||
|
|
||||||
for (x = 1; x <= center_offset; x++)
|
for ( ; x <= center_offset; x++)
|
||||||
print (' ');
|
print (' ');
|
||||||
|
|
||||||
// Print title bar text
|
// Print title bar text
|
||||||
|
|
|
@ -80,6 +80,9 @@ class FButton : public FWidget
|
||||||
// Disable assignment operator (=)
|
// Disable assignment operator (=)
|
||||||
FButton& operator = (const FButton&) = delete;
|
FButton& operator = (const FButton&) = delete;
|
||||||
|
|
||||||
|
// Overloaded operator
|
||||||
|
FButton& operator = (const FString&);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
const char* getClassName() const;
|
const char* getClassName() const;
|
||||||
FString& getText();
|
FString& getText();
|
||||||
|
|
Loading…
Reference in New Issue