Читать интересную книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 136 137 138 139 140 141 142 143 144 ... 337
alt="" src="images/_147.png"/>

Фигуры изображаются одна поверх другой, подобно листам бумаги, в порядке их добавления на экран. По этой причине объект path оказался на самом “дне”, просто потому, что он был связан с окном до объекта rita. Изображения могут кодироваться во множестве форматов. Здесь мы используем только два из них: JPEG и GIF.

struct Suffix {

  enum Encoding { none, jpg, gif };

};

В нашей библиотеке графического интерфейса изображение в памяти представляется как объект класса Image.

struct Image:Shape {

  Image(Point xy, string file_name,

    Suffix::Encoding e = Suffix::none);

  ~Image() { delete p; }

  void draw_lines() const;

  void set_mask(Point xy, int ww, int hh)

    { w=ww; h=hh; cx=xy.x; cy=xy.y; }

private:

  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. Сколько классов из библиотеки графического интерфейса нам понадобится, чтобы создать простой вывод графической информации?

3. Какие заголовочные файлы нужны для использования библиотеки графического интерфейса?

4. Какие классы определяют замкнутые фигуры?

5. Почему мы не используем класс Line для рисования любой фигуры?

6. Что означают аргументы конструктора класса Point?

7. Перечислите компоненты класса Line_style.

8. Перечислите компоненты класса Color.

9. Что такое система RGB?

10. В чем заключается разница между двумя объектами класса Line и объектом Lines, содержащим две линии?

11. Какие свойства можно задать для любого объекта класса Shape?

12. Сколько сторон объекта класса Closed_polyline определяются пятью объектами класса Point?

13. Что мы увидим на экране, если определим объект класса Shape, но не свяжем его с объектом класса Window?

14. Чем объект класса Rectangle отличается от объекта класса Polygon с четырьмя объектами класса Point (углами)?

15. Чем объект класса Polygon отличается от объекта класса Closed_polyline?

16. Что расположено сверху: заполненная цветом область или границы фигуры?

17. Почему мы не определили класс Triangle (ведь мы определили класс Rectangle)?

18. Как переместить объект класса Shape в другое место окна?

19. Как пометить объект класса Shape строкой текста?

20. Какие свойства текстовой строки можно задать в классе Text?

21. Что такое шрифт и зачем он нужен?

22. Для чего нужен класс Vector_ref и как его использовать?

23. В чем заключается разница между классами Circle и Ellipse?

24. Что произойдет, если мы попытаемся изобразить объект класса Image с заданным именем файла, а заданное имя файла не относится к файлу, содержащему изображение?

25. Как вывести на экран часть изображения?

Термины

Упражнения

Для каждого упражнения, в

1 ... 136 137 138 139 140 141 142 143 144 ... 337
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Оставить комментарий