Содержание сайта
Главная Новичку Цитаты Реализации Статьи Документация
Компании Программы Ссылки Обсуждение Обсуждение 2 Гостевая

Компонент "Блокнот для рисунков" (Scribble Pad)

Перевод Дмитрия Замоткина

Здесь приведено описание простой компоненты "Блокнот для рисунков" в качестве пособия для создания новой составной MVP-триады.

У нас нет желания пройти весь процесс создания шаг за шагом, мы упомянем лишь вопросы дизайна MVP, в то время как Вы параллельно будете просматривать уже готовый код. Поэтому, если компонента отсутствует в Вашем образе (image) Smalltalk, загрузите пакет Scribble.pac из папки Samples\Scribble используя Браузер Пакетов (Package Browser).

Итак, начнем.

Начнем с Модели (Model)

При создании составной MVP-триады я всегда начинаю с модели. Программисты, использующие "визуальные" средства разработки чаще начинают с пользовательского интерфейса, но по моему опыту это ведет к дизайну, перевернутому с ног на голову. Сначала, давайте увидим Блокнот в действии. Выполните:

Scribble show

Базовым объектом данных для Блокнота является InkStroke (Росчерк Пера). Найдите этот класс с помощью Браузера Классов (Class Browser). Экземпляры класса InkStroke знают о точках, по которым передвигался курсор мыши за один росчерк (с нажатой клавишей). Существующая модель Блокнота, очевидно, является коллекцией объектов InkStroke. Я выбрал в качестве модели блокнота экземпляр ListModel (Модель Списка), который содержит коллекцию InkStroke. Я мог бы создать для этого новый класс (скажем, ScribbleModel), но в этом простом примере он не имел бы никаких методов и лишь усложнял дизайн. Вы всегда можете создать подобный класс, если потребуется.

Подсказка: Вы должны сделать это, если хотите реализовать дополнительные методы, например #compress для сжатия данных о росчерке.

В любом случае, давайте сделаем небольшой тест InkStroke и модели, подготовленной для его использования.

stroke := InkStroke new.
stroke addPoint: 50@50; addPoint: 100@100; addPoint: 80@20.
model := ListModel with: OrderedCollection new.
model add: stroke.
model do: [:each | each drawOn: View desktop canvas ].

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

Отобразим Модель на View

Итак, у наc уже есть часть M от MVP-триады. Это ListModel, которая содержит (и только) набор InkStroke. На следующем этапе необходимо подумать о View, способном отобразить нашу модель на экране. Как правило, можно использовать экземпляр уже существующего класса для отображения данных модели. Например, мы можем использовать ListBox или ListView для нашей модели ListModel. Это сработает, но не принесет желательного результата, мы увидим лишь список текстовых представлений InkStroke. Но, боюсь, нам придется создать новый подкласс View для адекватного отображения модели.

Я должен создать класс ScribbleView как подкласс View. При проектировании view надо помнить об его обязанности по отображению данных модели и изменению их. View не должно отвечать за взаимодействие с пользователем, подменяя юрисдикцию ассоциированного презентера (Presenter). Класс ScribbleView перекрывает метод #onPaintRequired: для отображения модели. Он также перехватывает события (в методе #model:), генерируемых моделью для изменения view в случае изменения модели.

Давайте протестируем ScribbleView: создадим его, установим модель, и поместим на пустой ShellView.

view := ScribbleView new.
view model: model.
shell := ShellView new show.
shell addSubView: view.

Перейдем к Презентеру (Presenter)

Следующий объект в MVP-триаде - presenter. Он обязан обеспечивать интерфейс с пользователем, интерпретировать его и отражать эти изменения в модели. Давайте создадим класс Scribble как presenter.

Мы могли бы создать его как подкласс ListPresenter, поскольку его моделью тоже является ListModel. Однако ListPresenter содержит методы, малопригодные для функциональности Блокнота, поэтому мы будем наследовать Scribble напрямую от класса Presenter.

Метод класса #defaultModel указывает на дефолтную ListModel при создании нового экземпляра класса. Обратите внимание, что Scribble не перекрывает на стороне класса метод #defaultView, поскольку ожидается существование ассоциированного view в Менеджере Ресурсов (Resource Manager) с именем 'Default view'. Мы должны установить экземпляр класса ScribbleView в Менеджер Ресурсов с этим именем. Вы можете сделать это, просто выполнив:

Scribble addView: ScribbleView asResource: 'Default view'.

Затем Вы можете редактировать этот ресурс в View Composer'е: найдите его в Браузере Ресурсов (Resource Browser) и вызовите двойным щелчком. Вы можете захотеть сделать это для установки цвета фона или подобных манипуляций.

Сейчас создадим экземпляр класс Scribble, выполнив:

scribble := Scribble show.

Пишите, рисуйте, творите.

Доступ к изображению

Вы можете получить данные изображения, используя метод #model и сохранив их на будущее.

inkData := Scribble model.

Теперь закройте изначальное окно. Теперь попробуем восстановить рисунок на новом презентере Scribble.

scribble := Scribble showOn: inkData.

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

Scribble showOn: inkData.

Теперь, когда Вы рисуете в одном окне, его содержимое дублируется во втором. На этом мы и закончим пособие по компоненте Блокнот.




Есть комментарии? Пишите.