Boost logo

Boost :

From: Nicolas Fleury (nfleury_at_[hidden])
Date: 2003-05-19 15:01:03


Hi,

I've built a small library based on boost::signals to provide a
mechanism to update related-values across an application. Any comment
welcome.

Note that the documentation is very minimal for now and I continue
working on it, but I think there is enough to have feedbacks and to
discuss the place of such library in boost. Feedbacks may also
influence how I will continue working on it.

Regards,

Nicolas Fleury


Event-Driven Values

EDV (Event-Driven Values)


Introduction

Separate the view from the model, and in the MVC architecture, is a common practice in application design.  However, most currently available GUI toolkits often violates this design by including data in their widgets.  For example, a label usually contains the text it displays, even if this text is in fact the direct transformation of data in the model.  This forces the programmer to continuously update the data in widgets in function of the data in the model.

The purpose EDV library is to provide a flexible mechanism to update related values used in different parts of an application.

The value Class

The value class is the base class for all values classes.  Values encapsulate a read-only value and call a signal each time this value changed.  The basic interface of value is:

template <typename Type>
class value
{
public:
  typedef Type type;
  typedef boost::signal<void (type previous_value)> change_signal;
  typedef boost::signal<void ()> deletion_signal;
 
  inline type get() const;
  inline boost::signals::connection listen_change(
    const typename change_signal::slot_type slot) const;
  inline boost::signals::connection listen_deletion(
    const typename deletion_signal::slot_type slot) const;
  ...
protected:
  void set(type);
  ...
};


The simpler class derived from the value class is the concrete_value class.  This class basically make the set member function public.

Value Views

Value views are used to create values that have the same value of another value object.  An operation can also be specified to make the view the result of that operation.

int double_value(int v) { return v * 2; }
concrete_value<int> i(4);
value_view<int> j(i);
value_view<int> k(j, boost::function<int (int)>(&double_value));
i = 6;  // j now equal to 6, k to 12


Operation Values

Most binary and unary operators have their correspondant value class.  These value classes are used to build values that are the result of a basic operation on one or two other values.

concrete_value<int> i(4), j(6);
sum_value<int> sum(i, j);  // sum now equal to 10
diff_value<int> diff(i, j);  // diff now equal to -2
i = 6;  // sum now equal to 12, diff to 0


The constructors of these value classes also accept pointers for adoption or simple constant values (it is the same for all composite values presented in this document):

sum_value<int> result(i, new diff_value<int>(j, 7));

String Values

The string_convert_value class is the simpler class to produce a value containing the string equivalent of another value.

concrete_value<int> i(3);
string_convert_value<int, std::string> str(i);  // str content is "3"
i = 0;  // str content becomes "0"


The ostringstream_value class is a more powerful utility to create string values from multiple values.

ostringstream_value<std::string> str2;
concrete_value<int> i(4), j(6);
str2 << "The sum of " << i << " and " << j << " is " << new sum_value<int>(i, j);
i = 6;  // str2 content is changed accordingly


Sync Values

The sync_value class provides a mechanism to build values that have a bi-directional update relation.

sync_value<double> i(4);
sync_value<double> j(6);
sync_value<double> k(8);
make_equal_relation(i, j);  // i and j equal to 4
make_diff_relation(j, k, 10.0);  // k now equal to 14
i = 2;  // j now equal to 2 and k to 12
j = 3;  // i now equal to 3 and k to 13
k = 4;  // i and j now equal to -6


Custom relations can also be made by calling the connect function.

Triggers

Triggers are similar to signals with two major differences:
Triggers are particularly useful for actions triggered by a UI.  For example, a button widget using a trigger could be disabled as long as there's no action associated with it.

(Note: triggers in early development)



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk