Файл: Технологии программирования.docx

Добавлен: 23.10.2018

Просмотров: 2354

Скачиваний: 30

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Конечно, все эти поля будут частными.

  • У класса должен быть конструктор, который берет размер дисплея в качестве параметра, затем хранит это значение в соответствующем поле и также инициализирует объекты фрактального генератора и диапазон. Обратите внимание на то, что конструктор не должен устанавливать компоненты Swing; они будут установлены в следующем методе.

  • Обеспечьте createAndShowGUI () метод, который инициализирует GUI Swing: JFrame, содержащий JImageDisplay, возращает и кнопку для сброса дисплея. Вы должны установить фрейм, использующий java.awt. BorderLayout для его содержания; добавьте объект дисплея изображения в BorderLayout. Центральная позиция и кнопку в BorderLayout.

Вы должны также дать фрейму подходящий заголовок для своего приложения и установить операцию закрытия фрейма по умолчанию "выходить" (см. JFrame.setDefaultCloseOperation ()).

Наконец, после того как компоненты UI инициализированы и размечены, включают эту последовательность операций:

frame.pack ();

frame.setVisible (истина);

frame.setResizable (ложь).

Это правильно разметит содержание фрейма, заставит его быть видимым (окна не видимы, когда они создаются: сконфигурировать их прежде, чем вывести на экран), и затем отказаться от изменения размеров окна.

  • Вы должны реализовать частный метод помощника, чтобы вывести на экран фрактал, например, вызванный drawFractal (). Этот метод должен циклично выполниться через каждый пиксель в дисплее (т.е. x будет колебаться от 0 до размера дисплея), и сделайте следующее:

Вычислите количество итераций для соответствующих координат в области дисплея фрактала. Вы можете определить координаты с плавающей точкой для определенного набора пиксельных координат, используя FractalGenerator.getCoord () метод помощника; например, чтобы получить x-координату, соответствующую пиксельной - X координате, вы сделали бы это:

//x - пиксельная координата; xCoord - координата в пространстве фрактала

double xCoord = FractalGenerator.getCoord (range.x, range.x + range.width, displaySize, x);


Если количество итераций - 1 (т.е. точка не выходит, se цвет пикселя к черному цвету (rgb оценивают 0)). Иначе вы должны выбрать значение на основе количества итераций. Мы можем на самом деле использовать цветовое пространство HSV для этого: поскольку оттенок колеблется от 0 до 1, мы получаем гладкую последовательность цветов от красного до желтого, зеленого, синего, фиолетового, и затем назад к красному! Вы можете реализовать работу

float hue = 0.7f + (float) numIters / 200f;

int rgbColor = Color.HSBtoRGB(hue, 1f, 1f);

Конечно, если вы придумываете некоторый другой интересный способ окрасить пиксели на основе количества итераций, не стесняйтесь использовать его!

Дисплей должен быть обновлен с цветом для каждого пикселя, таким образом, вы будете использовать свой drawPixel (), работающий с запоминанием предыдущего результата.

Когда вы закончили тянуть все пиксели, вы должны вынудить JImageDisplay быть перекрашенным, чтобы соответствовать текущему содержанию его изображения. Сделайте это, вызвав перекрашивание на компоненте. Если вы забудете сделать это, ваш дисплей никогда не будет обновляться!


Создайте внутренний класс, чтобы обработать java.awt.event. События ActionListener от кнопки сброса. Обработчик просто должен сбросить диапазон к начальному диапазону, определенному генератором, и затем потянуть фрактал.

Как только вы завершили этот класс, обновите свой createAndShowGUI () метод, чтобы зарегистрировать экземпляр этого обработчика на кнопке сброса.

Создайте другой внутренний класс, чтобы обработать java.awt.event. События MouseListener от дисплея. Действительно, вы только должны обработать событие щелчка мышью, таким образом, вы должны получить этот внутренний класс из класса MouseAdapter AWT. Когда этот обработчик получает событие щелчка мышью, он должен отобразить пиксельные координаты щелчка в область фрактала, который выводится на экран, и затем вызовать recenterAndZoomRange генератора - метод с координатами, по которым щелкнули, и с масштабом 0.5. Таким образом, только, нажимая на расположение во фрактальном дисплее увеличит масштаб этого расположения!

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

После того как этот класс сделан, обновите свой createAndShowGUI () метод, чтобы зарегистрировать экземпляр этого обработчика на компоненте фрактального дисплея.

Наконец, вы должны создать статический основной метод для фрактального проводника так, чтобы это могло быть запущено. Основной метод будет очень прост в данный момент:

Инициализируйте новый экземпляр FractalExplorer с размером дисплея 800.

Вызовите createAndShowGUI () на объекте проводника.

Вызовите drawFractal() на проводнике, чтобы видеть начальное представление!

Как только вы завершили все эти шаги, вам необходимо «путешествовать» вокруг рассмотрения фрактала Мальдерброта. Если вы увеличите масштаб достаточно, то столкнетесь с двумя интересными проблемами:

  • во-первых, вы в конечном счете найдете, что уровень детализации заканчивается; это вызвано тем, что нам были бы нужны больше чем 2000 итераций, чтобы узнать, находится ли точка во множестве Мандельброта или нет. Конечно, мы могли бы испытать желание увеличить максимальные итерации, но тогда черные области фрактала действительно замедлят нас;

  • во-вторых, если вы увеличите масштаб действительно сильно, вы столкнетесь с пикселированным выводом дисплея! Это вызвано тем, что вы сталкиваетесь с пределом того, какую двойную точность значения с плавающей точкой могут представлять.

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








Задание №5. Выбор и сохранение фракталов

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

Верх генератора фракталов включает два виджета, которые позволяют пользователю выбирать фрактал, а внизу есть функция "Сохранить", чтобы сохранить текущее изображения фрактала.

Так как теперь будет несколько источников событий (action-event sources), вы можете научиться обращаться с ними с первоначальной реализацией одного ActionListener в классе.

Поддержка множественных фракталов

Очень легко добавить несколько фракталов в ваш генератор фракталов, именно потому что мы ввели абстракцию FractalGenerator в нашу изначальную реализацию. Научимся добавлять поддержку нескольких фракталов, и пользователь сможет выбирать между ними, используя combo-box . Эта самая распространенная метафора пользовательского интерфейса (UI) (т.е. стиль взаимодействия с которым пользователи уже знакомы из множества других пользовательских интерфейсов), поэтому это должно быть легко для понимания. Программный интерфейс Swing (Swing API) предоставляет combo-bo) через javax.swing.JComboBox класс, а еще лучше удаляет ActionEvents когда выбран новый предмет. Вот, что вам нужно сделать.

Создайте две новые имплементации генератора фракталов.
Первый фрактал - tricorn, который должен быть в файле Tricorn.java. Как и раньше, вам следует создать подкласс FractalGenerator, и имплементация будет почти идентична фракталу Мандельброта, кроме двух изменений. На самом деле, вы даже можете скопировать код источника Мандельберта и просто изменить следующие строки:

Равенство is zn = zn-12 + c. Единственное отличие только в том, что мы берем сложное сопряжение zn-1. Каждая итерация должна начинаться с изначальной областьи определения фрактала tricorn и должна быть от (-2, -2) до (2,2).

Второй фрактал, который мы будем имплементировать, это «горящий корабль», который так назван, потому что очень похож на горящий корабль. Вот детали:

Равенство zn = (|Re(zn-1)| + i |Im(zn-1)|)2 + c. Другими словами, вы берете абсолютное значение каждого компонента zn-1. Каждую итерацию
начинаем с изначальной области определения данного фрактала, т.е. от (-2, -2.5) до (2,1.5).

Swing combo-boxes может управлять коллекцией объектов, но объекты должны предоставлять имплементацию to String(). Убедитесь, что вы сделали имплементацию toString() для каждой имплементации фрактала, которая дает имя, например Мандельброт, Трикорн и «Горящий корабль».

Очень легко настроить JComboBOx в вашем пользовательском интерфейсе. Вы можете использовать безаргументный конструктор и затем использовать метод addItem(Object), чтобы добавить каждую имплементацию вашего генератора фракталов. Как говорилось в предыдущем шаге, выпадающий список будет использовать toString () метод вашей имплементации, чтобы отобразить генераторы в выпадающем списке.


Вам также следует добавить label в ваш пользовательский интерфейс перед выпадающим списком, что объяснит, для чего нужен выпадающий список. Вы можете это сделать, создав новый объект JPanel, добавив JLabel объект и JComboBOx объект в него, а затем поставить панель в ваш фрейм в позицию NORTH от слоя фрейма.

И наконец, вам нужно добавить поддержку вашего выпадающего списка имплементации ActionListener. Вы можете проверить, является ли выпадающий список источником action-event и если да, вы можете извлечь выбранный объект из виджета и сделать его текущим генератором фракталов (вы можете использовать метод getSelectedItem()). Не забудьте сбросить изначальную область определения и перерисовать фрактал!

Чтобы убедиться в правильности выполненной работы, вот изображения Трикорна и «горящего корабля»



Сохранения изображения фрактала

Следующее ваше задание состоит в сохранении текущего изображения фрактала на диск. Возможно звучит пугающе, но Java API (программный интерфейс) предоставляет несколько инструментов чтобы сделать это задание простым.

Во-первых вам нужно добавить кнопку «Сохранить изображение» на ваш дисплей. Вы можете поставить обе кнопки «Сохранить» и «Сбросить» на вашу новую JPanel, а затем поставить эту панель в SOUTH часть фрейма, почти так же, как вы добавляли label и выпадающий список. (Не используйте одинаковые объекты панели (panel objects) в обоих местах, иначе получите довольно странные результаты!)

Кнопка Сохранить также должна обрабатываться имплементацией ActionListener (action-events handled by your ActionListener implementation. Вам нужно дать вашим кнопкам «Сохранить» и «Сбросить» свои команды (например, сохранить и сбросить), чтобы обработчик (action-handler) событий мог отличить эти две кнопки.

В вашем обработчике кнопки Сохранить вам нужно разрешить пользователю указывать, какой файл он хочет сохранить в изображение. Вы можете сделать это с классом javax.swing.JFileChooser, который упрощает задачу. Этот класс предоставляет метод showSaveDialog(), который дает всплывающее диалоговое окно «Сохранить файл», позволяя пользователю выбрать директорию для сохранения. Этот метод принимает графический компонент, который является родительским элементом выбора. Это позволяет центрировать выбор по отношению к его родительскому элементу. Используйте фрейм приложения как родительский. Вы можете заметить, что этот метод возращает int значение, указывая исход операции выбора файла. Если метод возвращает JFileChooser.APPROVE_OPTION, тогда вы можете продолжить операцию сохранения файлов, в противном случае, пользователь отменил запрос, поэтому просто вернитесь. Если пользователь выбрал место для сохранения файла, это место доступно через getSelectedFile() метод, как объект файла.

Вам также нужно настроить выборщик файлов, чтобы он сохранял только png изображения, это пока единственный формат, с которым вы будете работать. вы можете это сделать с javax.swing.filechooser.FileNameExtensionFilter с таким фрагментом кода


JFileChooser chooser = new JFileChooser();

FileFilter filter = new FileNameExtensionFilter("PNG Images", "png");

chooser.setFileFilter(filter);

chooser.setAcceptAllFileFilterUsed(false);

Последняя строка гарантирует, что пользователь не разрешает использование не png файлов.

Если пользователь успешно выбрал файл, следующим шагом является сохранение изображения фрактала на диск. Это может быть сложным, но Java уже включает в себя эту функцию. Класс javax.imageio.ImageIO позволяет реализовывать простые операции загрузки и хранения изображения. Вы можете использовать версию write(RenderedImage im, String formatName, File output. Формат будет png. Рендерингованное изображение - это просто под программа буферного изображения из вашего компонента JImage Display (Вам также нужно предоставить публичный доступ этому члену/пользователю)

Конечно, вы заметите что метод write() может выдать исключение, поэтому вам нужно закрыть wrap запрос в блоке try/catch и разобраться с возможной ошибкой. Ваш блок catch должен проинформировать пользователя диалоговым окном. Опять же swing предоставляет класс javax.swing.JOptionPane чтобы упростить процесс создания информационных диалоговых окон или создания ввода да/нет. В таком случае, вы можете использовать статичный метод JOptionPane.showMessageDialog (Component parent, Object message, String title, int messageType) с сообщением JOptionPane.ERROR_MESSAGE. Ваше сообщение об ошибке может быть тем, что исключение возвращает из метода getMessage (), а заглавие может быть наподобие такого «Невозможно сохранить изображение». Родительский компонент должен быть фреймом, чтобы ошибка появлялась в центре фрейма.

Как только вы закончили с этим, опробуйте ваш feature. Теперь вы можете исследовать различные фракталы и видеть их во всей красе, а также вы сможете сохранять их на диск. Вы также можете опробовать ваш написанный код для ошибок, попробовав сохранить картинку в файл, который уже существует, но в котором стоит атрибут только чтение. Вы можете попробовать сохранить файл, чье имя является директорией папки для сохранения.



Задача № 6. Многоядерный исследователь/генератор фракталов


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

До сих пор, осознали ли вы это или нет, все наши фрактальные вычисления и чертежи/рисование были выполнены в Swing's Event-Dispatch Thread. Это поток, который обрабатывает все события Swing, такие, как нажатие кнопок, перерисовка и т. д. Вот почему ваш пользовательский интерфейс зависает во время вычисления фрактала. Поскольку вычисление выполняется в ядре обработке событий (event dispatch thread), никакие события не могут быть обработаны до завершения вычисления.