Если при использовании множественного наследования имеются классы, производные от QObject, мы должны всегда располагать производные от QObject классы первыми для того, чтобы компилятор moc мог их извлечь.
Мы объявляем три свойства для чтения и записи и одно свойство только для чтения. Макрос Q_ENUMS() необходим для указания компилятору moc на то, что SpeedValue имеет тип enum (перечисление). Это перечисление объявляется в открытой секции класса:
09 public:
10 enum SpeedValue { Slow, Normal, Fast };
11 AxBouncer(QWidget *parent = 0);
12 void setSpeed(SpeedValue newSpeed);
13 SpeedValue speed() const { return ballSpeed; }
14 void setRadius(int newRadius);
15 int radius() const { return ballRadius; }
16 void setColor(const QColor &newColor);
17 QColor color() const { return ballColor; }
18 bool isRunning() const { return myTimerId != 0; }
19 QSize sizeHint() const;
20 QAxAggregated *createAggregate();
21 public slots:
22 void start();
23 void stop();
24 signals:
25 void bouncing();
Конструктор AxBouncer является стандартным конструктором виджета с параметром parent. Макрос QAXFACTORY_DEFAULT(), который мы используем для экспорта компонента, предполагает, что у конструктора именно такая сигнатура.
Функция createAggregate() класса QAxBindable переопределяется. Мы рассмотрим ее вскоре.
26 protected:
27 void paintEvent(QPaintEvent *event);
28 void timerEvent(QTimerEvent *event);
29 private:
30 int intervalInMilliseconds() const;
31 QColor ballColor;
32 SpeedValue ballSpeed;
33 int ballRadius;
34 int myTimerId;
35 int x;
36 int delta;
37 };
Защищенная и закрытая секции этого класса имеют тот же вид, как и для стандартного виджета Qt.
01 AxBouncer::AxBouncer(QWidget *parent)
02 : QWidget(parent)
03 {
04 ballColor = Qt::blue;
05 ballSpeed = Normal;
06 ballRadius = 15;
07 myTimerId = 0;
08 x = 20;
09 delta = 2;
10 }
Конструктор AxBouncer инициализирует закрытые переменные этого класса.
01 void AxBouncer::setColor(const QColor &newColor)
02 {
03 if (newColor != ballColor &&
04 requestPropertyChange("color")) {
05 ballColor = newColor;
06 update();
07 propertyChanged("color");
08 }
09 }
Функция setColor() устанавливает значение свойства color (цвет). Она вызывает функцию update() для перерисовки виджета.
Необычной частью являются вызовы функций requestPropertyChange() и propertyChanged(). Эти функции наследуются от класса QAxBindable и в идеальном случае должны вызываться при всяком изменении свойства. Функция requestPropertyChange() спрашивает у клиента разрешение на изменение свойства и возвращает true, если клиент дает такое разрешение. Функция propertyChanged() уведомляет клиента о том, что свойство изменилось.
Устанавливающие свойства функции setSpeed() и setRadius() следуют этому же образцу, и так же работают слоты start() и stop(), поскольку они изменяют значение свойства running (приложение выполняется).
Осталось рассмотреть еще одну интересную функцию—член класса AxBouncer:
QAxAggregated *AxBouncer::createAggregate()
{
return new ObjectSafetyImpl;
}
Функция createAggregate() класса QAxBindable переопределяется. Она позволяет нам реализовать интерфейсы СОМ, которые модуль QAxServer еще не реализовал, или обойти определенные по умолчанию в QAxServer интерфейсы СОМ. Ниже мы делаем это для обеспечения интерфейса IObjectSafety, который используется в Internet Explorer для доступа к свойствам безопасности компонента. Это является стандартным способом устранения непопулярного сообщения об ошибке «Object not safe for scripting» (объект небезопасен при использовании в сценарии) в Internet Explorer.
Ниже приводится определение класса, которое реализует интерфейс IObjectSafety:
01 class ObjectSafetyImpl : public QAxAggregated, public IObjectSafety
02 {
03 public:
04 long queryInterface(const QUuid &iid, void **iface);
05 QAXAGG_IUNKNOWN
06 HRESULT WINAPI GetInterfaceSafetyOptions(REFIID riid,
07 DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions);
08 HRESULT WINAPI SetInterfaceSafetyOptions(REFIID riid,
09 DWORD pdwSupportedOptions, DWORD pdwEnabledOptions);