Friday, March 21, 2008

Event-Driven Programming

Hey guys, how are you?
Here we discuss windows event-driven programming. There are some stuff must to know, I know they sound hard but in fact they are very easy.


The Message Queue


Unlike MS-DOS-based applications, Windows-based applications are event-driven. They do not make explicit function calls (such as C run-time library calls) to obtain input. Instead, they wait for the system to pass input to them.
The system maintains a single system message queue and one thread-specific message queue for each graphical user interface (GUI) thread.


Whenever the user moves the mouse, clicks the mouse buttons, or types on the keyboard, the device driver for the mouse or keyboard converts the input into messages and places them in the system message queue. The system removes the messages, one at a time, from the system message queue, examines them to determine the destination window, and then posts them to the message queue of the thread that created the destination window. A thread's message queue receives all mouse and keyboard messages for the windows created by the thread. The thread removes messages from its queue and directs the system to send them to the appropriate window procedure for processing.


With the exception of the WM_PAINT message, the system always posts messages at the end of a message queue. This ensures that a window receives its input messages in the proper first in, first out (FIFO) sequence.


The WM_PAINT message is a message from the system to tell the application it must draw itself. It has the highest priority in the message queue to maintain responsive GUI.


The Message Loop


The main task of the WinMain function is processing the message queue. It will get a message from the queue and pass the message to the appropriate function to process it then remove it from the message queue.


// this is a generic simplified C++ windows application's WinMain body
while(GetMessage(&msg)) // retrieve a message from the application message queue (by reference)
{
    TranslateMessage( &msg ); // prepare that message in the message queue to be processed
    DispatchMessage( &msg ); // determine and call the function that will handle that message
}

So, the DispatchMessage will know which Control will process the message and call its WndProc function and from there The OnClick, for example, and then raise the Click event.

Events


Events are delegates that will be invoked when specific actions happen.


public delegate void SampleEventDelegate(string someData); // here we define the delegate singature
public class SampleEventSource
{
   public event SampleEventDelegate SampleEvent; // here we declare that there is a public event named SampleEvent of the same signature as the delegate SampleEventDelegate
}

The same rules of delegates apply to events. So, when we add an event handler to that event it must be of the same signature. The following line we create an object of the SampleEventSource and add an event handler to its event.


obj.SampleEvent += new SampleEventDelegate(myfunction); // that we already have a function called myfunction in the class we're declaring the obj object with the following declaration.
private void myfunction(string data)
{
    MessageBox.Show("Event raised with these data\n" + data);
}

You deal with event the same way you deal with delegate. So, any of following lines of code will do the job.


obj.SampleEvent += new SampleEventDelegate(myfunction);
obj.SampleEvent += myfunction; // implicit conversion to delegate
obj.SampleEvent += delegate(string data) { MessageBox.Show("Event raised with these data\n" + data); }; // anonymous method

As you see here, there is no EventArgs e or object sender in the code above and yet the code is correct. The EventArgs e is to supply the data you want to the event in conventional way instead of passing your data as single parameters like the code above. So, if you want to pass data along with the event, create a new class that inherits from the EventArgs class and extend it with the members and functions you want.


What about the object sender? Because of the fact that a single function can handle more than one event, these events can be events of different objects, you need something to tell you which object triggered that function. This becomes handy in situations like when you're creating a calculator application, instead of having 10 functions with almost the same code to handle the Click event of the 10 numeric Buttons, you make only one function to handle the 10 Buttons' Click and then use a switch statement to control the function behavior.


You can handle the same event with more than one function and they will get executed in the same order they were added to the invocation list of the delegate.


Windows Controls Events


Windows Controls provide events that will automatically be raised by the control itself. All you have to do is assigning event handlers.


Examples,
The Control.Click event will be raised when the control gets clicked.

The Control.MouseEnter will be raised when the mouse enters the control's region.


Here is a simple demo of events, I hope I covered everything.


And some useful CodeProject articles, you may find extra information in them but it's ok, skip the advanced parts.
http://www.codeproject.com/KB/cs/event_fundamentals.aspx
http://www.codeproject.com/KB/cs/events.aspx


The information provided about the Message Queue and the message loop are from the Platform SDK for Windows XP SP2.

1 comment:

Anonymous said...

That part i think dr roshdy said before he goes, great explanation