Re: communication between different parts of application via signals



On Jun 26, 2006, at 8:11 PM, Joe Van Dyk wrote:
On 6/26/06, Michael Ekstrand <michael elehack net> wrote:
On Sun, Jun 25, 2006 at 10:12:13AM -0700, Joe Van Dyk wrote:
Say a user clicks a checkbox in a menu that affects three other parts
of the application.  Would a signal be the best way to communicate
that change to the rest of the application?  How would that work?
Would I create a custom signal or slot?  How would the other parts of
the application listen to that signal?  Would I create the slot and
then pass that slot to the other parts of the application (i.e. in a
constructor)?

What exactly you do to accomplish depends on what you're doing,
obviously. However, signals and slots are frequently a decent way to do this kind of thing. For example, in my application, I have a singleton
class that manages application settings.  My preferences dialog sets
configuration items in this config class when its checkboxes, etc. are
manipulated. Other parts of the application can then connect to signals
the configuration engine fires when config keys are changed.  So when
you check the "always show tabs" checkbox, it sets the "tabalways"
configuration key to True in the config engine. The config engine then
fires the signal connected to the "tabalways" key, so any listening
application component knows that the "tabalways" option has changed, and
can adjust itself appropriately.  It provides a very flexible, and
somewhat centralized, wah of disseminating such events.

How do the various application components listen to the signal?

The key is that the configuration object is a singleton. It is managed by an App object (also a singleton). And my App object (to which a pointer is globally available - a getApp() function would also work) has a get_config() method, which returns a reference to the Config object. So a window can do

app->get_config().signal_changed("mainwindow", "tabalways").connect(some_listener)

The config object stores signals in a map, and signal_changed returns the existing signal for a particular config key if one exists, or creates a new signal and stores it in the map if one doesn't.

I've gone through the tutorial for libsigc++ and it's still terribly
confusing to me.
http://libsigc.sourceforge.net/libsigc2/docs/manual/html/ch02s02.html
says "Handily it derives from sigc::trackable already".  I have no
idea why that's handy.  First time sigc::trackable is referenced in
the document.

Actually, sigc::trackable is referenced in the introduction, where it says that a slot can use a pointer-to-a-member-function and that its object should inherit from sigc::trackable.

Why it's handy is that sigc::trackable provides the necessary mechanism so that signals don't try to call member functions bound to deleted objects. It provides a virtual destructor that disconnects all signal connections with members of the now-deleted object as slots, so that you don't have strange segfaults. So any time you use sigc::mem_fun to build a slot pointing to a method, the object containing the method should inherit from sigc::trackable. That should be cleared up though.

Any chance someone would like to update that tutorial to make it a bit
more clear?  And possibly also introduce functors in it?

A functor has the same definition as it does in the STL - to quote SGI's excellent STL documentation, "any object that can be called as if it is a function."

So the problem is probably that the tutorial doesn't document prerequisite knowledge... it's probably best read with an STL reference in hand. Perhaps a note should be added to the introduction that the tutorial assumes familiarity with STL concepts and terminology. Which, I've learned, is about necessary in order to do much with templates.

I would work on enhancing the tutorial, but I'm already behind enough without adding more tasks to my summer... Maybe if I get good and sick sometime...

- Michael




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]