Читаем Программирование полностью

  int w,h; // определяем "маскировочное окно" внутри изображения

           // по отношению к позиции (cx,cy)

  int cx,cy;

  Fl_Image* p;

  Text fn;

};


Конструктор класса Image пытается открыть файл с указанным именем, затем создать рисунок, используя кодировку, указанную в дополнительном аргументе или (как правило) в расширении файла. Если изображение невозможно вывести на экран (например, потому, что файл не найден), класс Image выводит на экран объект Bad_image. Определение класса Bad_image выглядит так:


struct Bad_image:Fl_Image {

  Bad_image(int h, int w):Fl_Image(h,w,0) { }

  void draw(int x,int y, int, int, int, int) { draw_empty(x,y); }

};


Работа с изображениями в графической библиотеке довольно сложна, но основная сложность класса Image кроется в файле, который обрабатывает его конструктор.


// более сложный конструктор, потому что ошибки,

// связанные с графическими файлами, трудно найти

Image::Image(Point xy, string s, Suffix::Encoding e)

      :w(0), h(0), fn(xy,"")

{

  add(xy);

  if (!can_open(s)) {         // можно ли открыть файл s?

    fn.set_label("Невозможно открыть \""+s+" ");

    p = new Bad_image(30,20); // ошибка графики

    return;

  }


  if (e == Suffix::none) e = get_encoding(s);


  switch(e) {                 // проверка кодировки

  case Suffix::jpg:

    p = new Fl_JPEG_Image(s.c_str());

    break;

  case Suffix::gif:

    p = new Fl_GIF_Image(s.c_str());

    break;

  default:                    // неприемлемая кодировка

    fn.set_label("Неприемлемый тип файла \""+s+" ");

    p = new Bad_image(30,20); // ошибка графики

  }

}


Расширение файла используется для того, чтобы определить вид объекта, создаваемого для хранения изображения ( Fl_JPEG_Image или Fl_GIF_Image). Этот объект создается с помощью оператора new и связывается с указателем. Подробности его реализации (в главе 17 рассматривается оператор new и указатели) связаны с организацией библиотеки FLTK и не имеют для нас большого значения.

Теперь настало время реализовать функцию can_open(), проверяющую, можно ли открыть файл для чтения.


bool can_open(const string& s)

  // проверка, существует ли файл s и можно ли его открыть

  // для чтения

{

  ifstream ff(s.c_str());

  return ff;

}


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

Если хотите, можете посмотреть на определение функции get_encoding(): она просто анализирует суффикс и ищет соответствие в таблице заранее заданных суффиксов. Эта таблица реализована с помощью стандартного типа map (подробнее об этом — в разделе 21.6).


Задание

1. Создайте объект класса Simple_window размером 800×1000 пикселей.

2. Разместите сетку размером 88 пикселей в левой части окна размером 800 на 800 пикселей (так что каждый квадрат сетки имеет размер 100×100 пикселей).

3. Создайте восемь красных квадратов, расположенных по диагонали, начиная с левого верхнего угла (используйте класс Rectangle).

4. Подберите изображение размером 200×200 пикселей (в формате JPEG или GIF) и разместите три его копии поверх сетки (каждое изображение покроет четыре квадрата). Если вы не найдете изображения, размеры которого точно равнялись бы 200 пикселям, то, используя функцию set_mask(), вырежьте соответствующий фрагмент более крупного изображения. Не закрывайте красные квадраты.

5. Добавьте изображение размером 100×100 пикселей. Перемещайте его с одного квадрата на другой, щелкая на кнопке Next. Для этого поместите вызов функции wait_for_button() в цикл, сопроводив его командами, выбирающими новый квадрат для вашего изображения.


Контрольные вопросы

1. Почему мы просто не используем какую-нибудь коммерческую или бесплатную графическую библиотеку?

2. Сколько классов из библиотеки графического интерфейса нам понадобится, чтобы создать простой вывод графической информации?

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже