Beginning with Kylix needs some understanding between signals and slots, the way
Linux/Qt deals with events and the Qt-library
VisualCLX is the part of CLX that represents the Visual Components that would
noramlly reside in the TWinControl hierarchy in the VCL.
VisualCLX framework is a set of classes that represent Visual Controls but have to
work (if possible) on both MS Windows and X in Linux.
The controls represented by the VisualCLX components are implemented by a C++ class
library called Qt and widgets, from the Norwegian development company called
Trolltech. Qt is also available on Windows.
- The VCL TWinControl class is called TWidgetControl
Qt is a C++ class library, cause of differences in C++ and OP
(ObjectPascal)details, an OP program cannot directly manipulate Qt widgets.
Instead, VisualCLX makes use of an additional library, called the Qt interface
library (written in C++ as libqtintf.so) which exports all the Qt functionality in
a manner that is accessible to OP code.
The import unit for this interface library is called Qt.pas but this means that
rather than being declared as classes, the Qt widget methods are all imported as
flat methods or strictly speaking functions.
We define a flat method as a method of a class that is declared as a standalone
subroutine or function.
However, since at the C++ side they are indeed classes, almost every flat method
takes one extra parameter, which is the reference to the Qt widget. You think this
might slow applications but most of the time you won't measure any difference in
So what's the difference in a architectural manner:
In a known OP application, you call methods via object references, e.g.:
2 myButton.setBounds(15, 15, 65, 35);
Turning the method into a flat method, the object reference is passed as the first
parameter so the method code knows which instance it should be invoking. Here is a
"it goes almost like this" example flat method, which is equivalent to the method
4 QButton_SetBounds(myButton, 15, 15, 65, 35);
or in a Kylix Qt-manipulation:
6 uses Qt, QTypes;
7 var Btn: QButtonH;
8 Btn := QButton_create(Handle, PChar('Btn'));
9 QButton_setGeometry(Btn, 15, 15, 65, 35);
Of course you would normally have no need to write code like this as a QButton does
it all for you, but it serves as a simplified example of how CLX components do
their thing by using the CLXDisplayAPI.
What's the CLXDisplayAPI
The CLXDisplay API is the official name for the Qt.pas unit that ships with Kylix
and also with Delphi6 or later. It acts as an import unit for the Qt widget library
used by VisualCLX.
So things in life are a bit more complicated than this. Qt is a C++ class library,
and OP cannot direct manipulate C++ classes. Because of this, Borland wrote an
additional library to lay between a CLX application and the Qt library. This extra
library is called libqtintf.so (the Qt interface library), and Qt.pas is actually
the import unit for this interface library.
Understanding Signal/Slot mechanism
A hook object is a simple C++ object that exists in the Qt interface library as we
said as an intermediary. So you want to customise the reaction of a widget like in
windows with eventhandlers, signal/slot play the role:
- A signal (event) from a widget
- A slot (event handler) responds to a signal
So we learnt, it's not possible to have the slot written directly in OP, means the
Qt interface library defines a hook class for each widget class. The hook class
implements a simple slot for each available widget signal, whose sole job is to
call some code in our Kylix application.
More on signal / slot and the Way Kylix does:
So it seems that messages (callback functions) are not the CLX way of doing things,
it means not that CLX provides no support of messages, but it's not the Kylix way
of doing things so. We suggest, e.g. mouse movements, that you let CLX respond to
the mouse and simply override the methods that CLX uses for those events.
Creating a component and need to catch the mouse messages, you can use the
11 procedure MouseMove(shift: TShiftState; X, Y: integer); override;
The way we have to think is that in Qt, developers do not respond directly to
messages. Instead they work with a signal / slot mechanism and the connect function
13 QObject::connect(timer, SIGNAL(timeout)), SLOT(timerSlot()));
14 timer -> start(1000);
or another example to get acustomed to:
16 QObject::connect(myslider, SIGNAL(sliderMoved(in )),
17 mylcdNumber, SLOT(display(in )));
There is nothing special about the sliderMoved and display methods. Just ordinary
C++ methods that are marked as signals and slots, just as some Kylix methods are
marked as being virtual.
QObject is the base class in Qt, just as TObject is the base class in OP
(ObjectPascal). QObject has a class or static method named connect. An OP class
method is the same thing as a C++ or Java static method. In particular, you can
call a class or static method without
first creating an instance of the object to which it belongs.
And where's the event-loop in Kylix?
Here is the event loop that lies at the center of CLX applications:
Hooks again and Overview
Fact: So you learned that Qt uses a signal and slot mechanism,
and CLX uses an event mechanism. It's not so important how the two are connected,
it might be valuable some time later, but here is an overview:
Qt has a signal and slot mechanism. CLX has an event mechanism.
To translate Qt signals and slots into CLX events, the Kylix team created a
mechanism known as hooks. Each CLX object type has a hook object. This hook object
converts the signals and slot events associated with a particular object into CLX
events. It then sends these events to the appropriate CLX control.
In particular, there is a CLX method of TWidgetControl named
EventFilter that receives the majority of these events.
You can find more on this topic on the Kylix2 CompanionTool CD:
chapter 7 CLX architecture & Visual Development or
Code Central Entry ID #16795
Here an impressive extract:
If you feel the urge to go beyond the usual CLX
API, then here is one of the methods that you want to override:
19 function TWidgetControl.EventFilter(Sender: QObjectH; Event: QEventH): Boolean;
This one is the big Kahuna. EventFilter gets most of the events that Qt and the OS
throws at it. Just opening up QControls and looking at the 500+ lines that form the
implementation of this method is enough to send any sane programmer running for the
safety of the standard
CLX APIs. However, some people like to live on the edge. They claim that the air is
thinner but cleaner out there.
21 function TWidgetControl.MainEventFilter(Sender: QObjectH; Event: QEventH): Boolean;
23 var Form: TCustmForm;
26 if csDesigning in ComponentState then begin
27 Form := GetParentForm(Self);
28 if (Form <> nil) and (Form.DesignerHook <> nil) and
29 Form.DesignerHook.IsDesignEvent(Self, Sender, Event) then begin
30 Result := True;
34 Result := EventFilter(Sender, Event);
37 Result := False;