Tuesday 25 December 2012

Event Handling (or Round and Round in Circles)

Today we are going to discuss how to wrap a Qt event handler function in BlitzMax.

Meet our friend, an event function :

void QLineEdit::changeEvent ( QEvent * ev )

This is called in Qt whenever the contents of a QLineEdit changes. Details of the event can be found in the QEvent object passed into the function.

In BlitzMax, our QLineEdit type has a matching method :

Method changeEvent(event:QEvent)

You can subclass QLineEdit with your own BlitzMax type, and whenever the text changes, your overriding method will be called :


Type MyQLineEdit Extends QLineEdit

Method changeEvent(event:QEvent)
Print "It Changed!"
End Method

End Type


Well, that's just great, says you, but how does the magic really happen!?

Ah, I'm glad you asked, because it's really rather interesting.

If we were writing in C++, it would simply be a case of creating our subclass and implementing the overridden function in our new class. For any events we don't care about, we don't override them. Job Done.
However, with a wrapper, because BlitzMax code sits so high above the C++ glue you need to override ALL of the event functions so that you can push them back into BlitzMax and either perform the default function, or call into the overridden method in the new Type.

So, the first step is to override, the event function :


void MaxQLineEdit::changeEvent(QEvent * ev) {
_qt_qwidget_QWidget__OnChangeEvent(maxHandle, ev);
}

In our QWidget BlitzMax type we already have a callback function set up for this event (since changeEvent() is a QWidget event that QLineEdit overrides itself), so we can call this. maxHandle is a handle to our BlitzMax object (the one with the method).


In the QWidget type, our callback function simply constructs BlitzMax objects and calls the real method :


Function _OnChangeEvent(obj:QWidget, event:Byte Ptr)
obj.changeEvent(QEvent._create(event))
End Function


Because BlitzMax is clever, if the "obj" object happens to be a subclass of QWidget, the changeEvent() method of that subclass will actually be called instead, and therefore, your overridden method will be called.

But what of those methods you haven't overridden? Shouldn't they perform their original functionality? Well, yes, of course, and therefore we must also supply this default functionality by calling back into Qt and handling the original event.

Our QWidget type has this default method call :


Method changeEvent(event:QEvent)
bmx_qt_qwidget_default_changeevent(qObjectPtr, event.qObjectPtr)
End Method


Subsequently calling this function in our C++ glue :


void MaxQWidget::defaultChangeEvent(QEvent * event) {
QWidget::changeEvent(event);
}


Which, as you can see is allowing Qt to handle the event as it would normally if we hadn't overridden it ourselves!

Ideally, in our original example, any events that your override yourself, you should really add a call to your superclass method so that Qt might have a chance of processing the event too. Otherwise you might your application acting strangely.
So, doing something like this is a good idea, unless you have a reason not to :


Method changeEvent(event:QEvent)
Print "It Changed!"
Super.changeEvent(event)
End Method



If you like going around in circles, writing wrappers may be for you!

Happy coding!

:o)

No comments:

Post a Comment