Чтение онлайн

ЖАНРЫ

QT 4: программирование GUI на С++

Саммерфилд Марк

Шрифт:

14 }

Функция capabilities возвращает объект, который показывает, что может делать с данным форматом изображений обработчик изображений. Существует три возможных действия (CanRead, CanWrite и CanReadIncremental), а возвращаемое значение объединяет допустимые варианты порязрадной логической операцией ИЛИ.

Если формат «cur», наша реализация возвращает CanRead. Если формат не задан, мы создаем обработчик курсора и проверяем его способность чтения данных с заданного устройства. Функция canRead только просматривает данные и проверяет возможность распознавания файла, не изменяя указатель файла. Возвращение 0

означает, что данный обработчик не может ни считывать, ни записывать файл.

01 QImageIOHandler *CursorPlugin::create(QIODevice *device,

02 const QByteArray &format) const

03 {

04 CursorHandler *handler = new CursorHandler;

05 handler->setDevice(device);

06 handler->setFormat(format);

07 return handler;

08 }

Когда файл курсора открыт (например, с помощью класса QImageReader), будет вызвана функция оболочки подключаемого модуля create с передачей указателя устройства и формата «cur». Мы создаем экземпляр CursorHandler для заданного устройства и формата. Вызывающая программа становится владельцем обработчика и удалит его, когда он не станет нужен. Если приходится считывать несколько файлов, для каждого из них создается новый обработчик.

Q_EXPORT_PLUGIN2(cursorplugin, CursorPlugin)

В конце файла .cpp мы используем макрос Q_EXPORT_PLUGIN2, чтобы гарантировать распознавание в Qt подключаемого модуля. В первом параметре задается произвольное имя, используемое нами для подключаемого модуля. Второй параметр содержит имя класса подключаемого модуля.

Подкласс QImageIOPlugin создается достаточно просто. Реальная работа подключаемого модуля делается обработчиком. Обработчики форматов изображений должны создать подкласс QImageIOHandler и переопределить некоторые или все его открытые функции. Сначала рассмотрим заголовочный файл:

01 class CursorHandler : public QImageIOHandler

02 {

03 public:

04 CursorHandler;

05 bool canRead const;

06 bool read(QImage *image);

07 bool jumpToNextImage;

08 int currentImageNumber const;

09 int imageCount const;

10 private:

11 enum State { BeforeHeader, BeforeImage, AfterLastImage, Error };

12 void readHeaderIfNecessary const;

13 QBitArray readBitmap(int width, int height, QDataStream &in) const;

14 void enterErrorState const;

15 mutable State state;

16 mutable int currentImageNo;

17 mutable int numImages;

18 };

Открытые функции имеют фиксированную сигнатуру. Здесь нет некоторых функций, которые не надо переопределять в обработчике, обеспечивающем только чтение, в частности отсутствует функция write. Переменные—члены объявляются с ключевым словом mutable, потому что они изменяются внутри константных функций.

01 CursorHandler::CursorHandler

02 {

03 state = BeforeHeader;

04 currentImageNo = 0;

05 numImages = 0;

06 }

После создания обработчика мы сначала настраиваем его параметры. Номер текущего изображения

курсора устанавливается на первый курсор, но поскольку переменная количества изображений numImages принимает значение 0, ясно, что у нас пока еще нет изображений.

01 bool CursorHandler::canRead const

02 {

03 if (state == BeforeHeader) {

04 return device->peek(4) == QByteArray("\0\0\2\0", 4);

05 } else {

06 return state != Error;

07 }

08 }

Функция canRead может вызываться в любой момент для определения возможности считывания обработчиком изображений дополнительных данных с устройства. Если функция вызывается до чтения данных в состоянии BeforeHeader, выполняется проверка конкретной метки, по которой опознаются файлы курсоров в Windows. Вызов QIODevice::peek считывает первые четыре байта без изменения указателя файла на данном устройстве. Если функция canRead вызывается позже, мы возвращаем true при отсутствии ошибки.

01 int CursorHandler::currentImageNumber const

02 {

03 return currentImageNo;

04 }

Эта простая функция возвращает номер курсора, на который позиционирован указатель файла устройства.

После создания обработчика пользователь может вызвать любую его открытую функцию, причем последовательность вызовов функций может быть произвольной. В этом кроется потенциальная проблема, поскольку необходимо исходить из того, что файл можно читать только последовательно, поэтому сначала надо один раз считать заголовок файла и затем выполнять какие-то другие действия. Эту проблему решаем путем вызова readHeaderIfNecessary в тех функциях, для которых требуется предварительное считывание заголовка файла.

01 int CursorHandler::imageCount const

02 {

03 readHeaderIfNecessary;

04 return numImages;

05 }

Эта функция возвращает количество изображений, содержащихся в файле. Для правильного файла, при чтении которого не возникает ошибок, она возвращает по крайней мере 1.

Рис. 19.2. Формат файла .cur.

Следующая функция довольно сложная, поэтому мы рассмотрим ее по частям:

01 bool CursorHandler::read(QImage *image)

02 {

03 readHeaderIfNecessary;

04 if (state != BeforeImage)

05 return false;

Функция read считывает данные изображения, начинающегося в текущей позиции указателя устройства. Если успешно считан заголовок файла или указатель устройства после чтения изображения находится в начале другого изображения, можно считывать следующее изображение.

06 quint32 size;

07 quint32 width;

08 quint32 height;

09 quint16 numPlanes;

10 quint16 bitsPerPixel;

11 quint32 compression;

12 QDataStream in(device);

13 in.setByteOrder(QDataStream::LittleEndian);

14 in >> size;

15 if (size != 40) {

16 enterErrorState;

17 return false;

Поделиться с друзьями: