Page 1 of 1

Observer pattern (aka. Notifications) for wxWidgets

Posted: Mon Nov 01, 2004 4:34 pm
by ezequielv
Hi. I've recently developed (not finished yet, I'm just polishing everything before releasing it) a group of classes for implementing the observer pattern and event forwarding under wxWidgets.

The idea is to implement notifications using the event system that wxWidgets provides. Furthermore, it allows arbitrary plugging of external event handler functions without disrupting the object's normal event handling mechanism.

The main features are:

* Event handling mechanism for wxEvtHandler-derived objects is unchanged (no hidden event handlers are "pushed" nor "popped").
* For non-wxEvtHandler-derived classes: you can make any class a "model" ("subject"), without requiring you inheriting from any specific class.
* You can extend existing wxEvtHandler-derived classes with forwarding capabilities wihout the limitations of wxWidgets (ie. dynamic method attachment to handle events can only be made to the handler object (you can't connect other object's handlers to a wxEvtHandler object); push/pop event handlers require right sequence for disconnecting a specific handler (that is only available in wxWindow-derived classes anyway), etc.).
* You can (if templates support is enabled) forward event handling to any class, without requiring the target class to be inherited from wxObject, wxEvtHandler or any other.
* If templates are not enabled, all you need is your forward destination class to be inherited from wxObject (not necessarilly from wxEvtHandler), so it's still very lightweight.
* You can disconnect, without knowing the particulars, all methods for a particular object in a single function call (see example below).
* You can attach a "strategy" for event processing regardless of each event handler's code (to simulate notifications, in which handlers should not interfere with each other).
* No changes to wxWidgets library are required, and it's (should be) fully compatible with all platforms (it does not need templates) wxWidgets supports.
* The same limitations apply to virtual functions as forward (or notification) destinations (they work as regular functions) as in wxWidgets.

As I said, it's almost finished. I found this crucial to implement the observer pattern.

In plain english, you could do this:

[syntax="c"]
// notifier as member (for model classes that should not be re-inherited from other classes).
class CMyClass1
{
public:
wxNotifier m_notifier;
void SomeMethod( void );
};

void CMyClass1::SomeMethod( void )
{
// operations...

// notify
m_notifier.ProcessEvent( wxEvent( m_id, wxEVT_MODEL_NOTIFICATIONS ) );
};

// notification as a transparent added mechanism for this wxEvtHandler-based model class
class CMyClass2 :
// its own inheritance (somehow derived from wxEvtHandler)
public wxEvtForwarderImpl
{
// ...
DECLARE_EVTFORWARDER_CLASS(CMyClass2)
};

IMPLEMENT_EVTFORWARDER_CLASS(CMyClass2)

void CMyClass2::SomeMethod( void )
{
// operations...

// notify
ProcessEvent( wxEvent( m_id, wxEVT_MODEL_NOTIFICATIONS ) );
};

class CMyManager // somehow derived from wxObject
{
protected:
// my specific model class in this context.
// could be a singleton referred in the code below, etc.
CMyClass1 * m_pModel1;
CMyClass2 * m_pModel2;

public:
void ProcessNotification( wxEvent& event );
void ProcessToolbarClicked( wxEvent& event );
};

// example
CMyManager::SetupConnections( void )
{
// ...

// using "notifier" object
pModel1->m_notifier.ConnectObj( ID_MODEL1, wxEVT_MODEL_NOTIFICATIONS, this, (wxObjectEventFunction) (wxEventFunction) &CMyManager::ProcessNotification, pMyCallbackData1 );
// using wxEvtHandler-derived class directly.
pModel2->ConnectObj( ID_MODEL2, wxEVT_MODEL_NOTIFICATIONS, this, (wxObjectEventFunction) (wxEventFunction) &CMyManager::ProcessNotification, pMyCallbackData2 );

// interesting: connect dynamically to handle a toolbar click
wxGetApp().ConnectObj( ID_CMDSOMEACTION, wxEVT_COMMAND_TOOL_CLICKED, this, (wxObjectEventFunction) (wxEventFunction) &CMyManager::ProcessToolbarClicked );
}

void CMyManager::ProcessNotification( wxEvent& event )
{
// handling code
}

void CMyManager::ProcessToolbarClicked( wxEvent& event )
{
// handling code
}

CMyManager::~CMyManager()
{
// safe 'disconnect all' method
m_pModel1->m_notifier.DisconnectObj( this );
m_pModel2->DisconnectObj( this );
wxGetApp().DisconnectObj( this );
}
[/syntax]

My post is mainly to ask people if there is an interest in having this sort of functionality in wxWidgets and to gather questions and suggestions. Basically, I want to know if it makes sense to continue this further, and make it go in a direction that people is interested in.

I've been using wxWidgets 2.4.2 as my reference code, but I don't think the functionality in 2.5.x is any different than 2.4.x's with respect to what I use.

Sorry for the clumsiness of the post but I don't have much time today.

Ideas, suggestions, comments are all welcome :)

Posted: Tue Nov 02, 2004 10:22 am
by Jorg
I wanted to reply to this post. YES I am interested. You should however document it very well, and provide a few samples. If you want this to be accepted by the wxWidgets community it should also fit in the contrib model (dir structure) so Julian or who else can easily fit it in when it is really used by the majority.

I would suggest CMake for compilation, or use the Bakefiles so everybody (Mac, Windows, Linux) can compile them. I wanted to look into Bakefiles, but due to a lacking GUI to create the bakefiles itself (I am reluctant in learning another script XML based language) I prefer CMake.

By the by ... maybe you should also post this on the mailing list (wx-user and wx-dev) so core devs can take a look at it and help you. It sounds really interesting.

ps. I moved this to the announce section as you are announcing it more then requesting help..



Regards,
- Jorgen

Posted: Tue Nov 02, 2004 10:29 am
by ezequielv
Jorg wrote:I wanted to reply to this post. YES I am interested. You should however document it very well, and provide a few samples. If you want this to be accepted by the wxWidgets community it should also fit in the contrib model (dir structure) so Julian or who else can easily fit it in when it is really used by the majority.

I would suggest CMake for compilation, or use the Bakefiles so everybody (Mac, Windows, Linux) can compile them. I wanted to look into Bakefiles, but due to a lacking GUI to create the bakefiles itself (I am reluctant in learning another script XML based language) I prefer CMake.

ps. I moved this to the announce section as you are announcing it more then requesting help..

Regards,
- Jorgen
Fantastic! My idea is to document it very well, as it fits the event handling model very well, although it does not require any hacking to wxWidgets itself :)

As for the building process, it's a personal mission to use something that works, it's portable, and can integrate well with other building systems (note this last one is kind of tricky). For example, Boost has its own building program (I don't remember the name just now), GNU/Linux use autotools these days (I can't make my mind as to use that and target GNU-based systems such as Linux and Cygwin, for example), and there are several other well-intentioned building tools available. I came across CMake yesterday browsing your wxWidgets website ;) and it looks promising.

On the other hand, wxGTK use autotools to detect configuration options, libraries, etc., so I'm not really sure CMake is necessarilly right for this. What do you think?

Posted: Tue Nov 02, 2004 10:38 am
by Jorg
Hi,

You must think of CMake as a tool that distantiates you from the autoconfig tools from the OS it is ran on. For example:

On Windows it can generate
- Makefiles (NMAKE)
- Visual Studio .NET
- Visual Studio 6

On Linux it can generate:
- Makefiles
- KDevelop files
- ?

On MAC it can generate:
- Makefiles

All those projects spring from one and the same script you are using. The OS dependent flags are kept abstract by shared directives so you don't have to figure that out. So with one script this all is maintained.

For example, I had wxTreeMultiCtrl and could only test it on linux and win32. Someone with HP-UX wanted to use it as well. It appeared one tiny darn directive in the compiler flags was making that HP-UX compiler gag and generate faulty code. I never knew, he never knew, but the CMake guys knew. When I converted my build env to CMake, the HP-UX files that were auto generated worked flawlessly.

So, this is what CMake does. I think the effort they put in it is great. And all my controls are in use everywhere, nobody ever complained about missing project files (since they also have to use CMake to compile my source).

As for the observer pattern, I am looking forward in using it in one of my projects. I already worked some with other patterns and tried to create my own observer pattern once. So if you need it reviewed I would like to help you with that ..

Regards,
- Jorgen

Posted: Tue Nov 02, 2004 10:48 am
by ezequielv
Jorg wrote:All those projects spring from one and the same script you are using. The OS dependent flags are kept abstract by shared directives so you don't have to figure that out. So with one script this all is maintained.

For example, I had wxTreeMultiCtrl and could only test it on linux and win32. Someone with HP-UX wanted to use it as well. It appeared one tiny darn directive in the compiler flags was making that HP-UX compiler gag and generate faulty code. I never knew, he never knew, but the CMake guys knew. When I converted my build env to CMake, the HP-UX files that were auto generated worked flawlessly.

So, this is what CMake does. I think the effort they put in it is great. And all my controls are in use everywhere, nobody ever complained about missing project files (since they also have to use CMake to compile my source).
Yes, it does sound great. It comforts me knowing that you have all your wxWidgets contributions source code using the CMake build system. If there is a problem in the future or with integrating the code to wxWidgets, well, there'll be at least two of us :)

Just remember that autotools are (supposedly) also meant to generate standard Makefiles. aclocal && automake && autoconf && ./configure && make :)
Jorg wrote:As for the observer pattern, I am looking forward in using it in one of my projects. I already worked some with other patterns and tried to create my own observer pattern once. So if you need it reviewed I would like to help you with that ..
Sure thing. I'll be tidying things up before releasing even the first version.

One more thing. Is there any "standard" unit testing system in use for making sure wxWidgets works? I mean, I could try and (learn and) use cppunit, but I want to concentrate on coding instead of unit testing at this stage. On the other hand, I want to make sure the code actually works, and for this sort of non-GUI code unit testing would be a great asset.

Edit: fixed typo

Posted: Tue Nov 02, 2004 2:47 pm
by Ryan Wilcox
the wxWidgets core devs use CppUnit. I actually prefer something a little lighter and use a modified version of Chuck Allison's TestSuite, from an article in the C++ Users Journal. With a small GUI wrapper around this, to run my unit tests I simply launch my main program, and click the "Test" button.

See http://www.wilcoxd.com/products/WDTestHarness.html for more info.

Posted: Tue Nov 02, 2004 2:52 pm
by ezequielv
Ryan Wilcox wrote:the wxWidgets core devs use CppUnit. I actually prefer something a little lighter and use a modified version of Chuck Allison's TestSuite, from an article in the C++ Users Journal. With a small GUI wrapper around this, to run my unit tests I simply launch my main program, and click the "Test" button.
Cheers, Ryan. I'll look into that. I'll still be considering cppunit, but I have to factor the time-to-production in the equation :)

Posted: Tue Nov 02, 2004 10:38 pm
by tierra
Mmmmm... Observer pattern....

This is very handy in Java, I don't see why it wouldn't be helpful here.

Posted: Sat Jan 15, 2005 5:10 pm
by gunnar
Hello ezequielv,
this stuff seems rather nice for wxWidgets users.
But now there are more than 2 month since the last post.
Is there an chance, to get acess to your code, ezequielv?

regards,
gunnar

Project not dead, only slightly delayed...

Posted: Sun Jan 16, 2005 11:00 am
by ezequielv
gunnar wrote:Hello ezequielv,
this stuff seems rather nice for wxWidgets users.
But now there are more than 2 month since the last post.
Is there an chance, to get acess to your code, ezequielv?
Sorry, I've been busy :? (setting up Gentoo Linux at my laptop and struggling with the dodgy hardware it has).

However, I *do* have some code working, although not thoroughly tested. I'd like to create a project at, say, sf.net and host it there. Maybe I'll do so in the next few days, if there's enough interest.

The interface to each of the classes is still not deffinitive, but some things are very likely to stay as they are (especially at the high level).

So, how many people are interested in this? Please PM me and say "I do" :) . If it's only a few people, maybe I'd just add some copyright and license information to my source files and send them privately to those interested. At least until I have some time and host them properly @sf or somewhere else.

Posted: Sun Jan 16, 2005 1:05 pm
by gunnar
Hmm i am too dumb to figure out how to send a private mail.
So i make a public "I do" request.

regards,
gunnar

Posted: Sun Jan 16, 2005 8:36 pm
by ezequielv
To send a Private Message ("PM"), just click on the "PM" link just at the bottom of a post made by the user you want to send the message to. For example, to send a PM to me, you'd click on the "PM" link just below this text 8)