Delphi programming blog
Источник: http://teran.karelia.pro/articles/item_4503.html
 

FireMonkey и MyShows.ru #3

Опубликовано 09.01.2012 г. 23:42

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

В этой статье особо технических подробностей наверное не будет. Просто расскажу о том, какой клиент получился и поделюсь мб впечатлениями о работе с FireMonkey. До этого один клиент для сервиса уже был написан с использованием VCL, сейчас же код был полностью переписан. Имеется в виду, не только интерфейс, а вообще все написано с нуля, работа с API и т.п. Использование FMX еще далеко от идеала, в смысле работа с ним. Есть множество различных ошибок, и во время выполнения и во время проектирования. Но будем надеяться, что его не бросят и будут развивать, и что новых обновлений не придется ждать до ХЕ3, а они будут появляться и дальше. Картинка приложения получилась такая:
 
Собственно верхнее меню выполнено их простых элементов TTеxt, не считая TImage для кнопки настроек, что рядом с пунктом "Выйти". На текстовые элементы наложены эффекты свечения, отражения и анимации размера. Кнопка (Рисунок) настроек (слева от Выйти) имеет анимацию прозрачности при наведении. Написания дополнительного кода это не требует, и делается исключительно мышью. За эту простоту и программирование мышью конечно же приходится расплачиваться. Сегодня пробовал запускать программу на рабочей машине, где встроенное видео - загрузка процессора достигала иногда 25%, при наличии 4х ядерного Q8200 это означает, что одно ядро загружалось полностью (если туда обратно водить мышью над анимируемыми элементами меню). Главная область приложения - TListBox, в котором элементы имеют custom-стили, отображает список тв-шоу (сериалов), которые смотрит (собирается смотреть, смотрел, перестал смотреть) пользователь, согласно выбранному в верхнем меню пункту. Изначально у меня была проблема, когда при первом запуске, элементы списка отображаются не корректно. Решить проблему удалось с помощью дополнительного вызова ApplyStyle для листбокса при запуске приложения. Маловероятно имхо, что это "так и задумано". Есть у листбокса и еще один косяк. Разместив на нем какие нить другие элементы, например, я разместил на нем 3 элемента TImage, которые были невидимы во время выполнения. Такие элементы так же будут находятся в коллекции Children списка, поэтому список будет пытаться их отобразить в себе, т.е в виде самих элементов. В принципе конечно такое поведение с одной стороны логично, с другой вряд ли корректно, ибо отображать список должен бы тогда TListBoxItem и его потомков, а не все что угодно из своих Children. Вообще для формы применены стили, не помню уже точно какие, но что то из стандартного набора. Но все списки и таблицы сделаны с прозрачным фоном. А фон самой формы залит градиентом (это я к тому, что в стандартном черном стиле градиент направлен в другую сторону). Не сказал бы что работа со стилями удобна, но с выходом 3-го обновления, конечно, стала лучше. Напрягает логика работы с TStyleBook, если особенно вы хотите, чтобы ваши custom-стили элементов были в отдельной книге, а не в общей куче. Так же замечу, что допустим, вы создали главную форму приложения. Применили к ней, например, такую черную цветовую схему. Затем добавляете новую форму, и эта новая форма этот стиль главной конечно же не наследует. И вам приходится в свойстве StyleBook новой формы ссылаться на стили главной формы. Имхо подход стилей в VCL, где они применяются ко всему проекту более корректен. Справа на главной форме располагается TTabControl c тремя вкладками:
  1. Список серий по выбранному сериалу, которые уже вышли в эфир, но пользователь их еще не посмотрел (непросмотренные)
  2. Будущие - перечень серий с указанием дат, которые выйдут в ближайшем будущем.
  3. Сериал - информация о сериале, ссылки, рейтинги, страна производитель и т.п. Здесь же задаются настройки поиска файлов эпизодов - Директории в которых проводится поиск, и маска поиска (изначально маска формируется автоматически по названию сериала).
В "непросмотренных" есть возможность запуска поиска файлов эпизодов. Поиск выполняется в отдельном потоке и по мере нахождения файлов они отмечаются значком в списке. Значок имеет контекстное меню, где представлены файлы найденных эпизодов с соответствующими командами на сохранение или воспроизведение. Тут хотелось бы еще добавить команду воспроизведения по DLNA но пока даже не представляю, как это сделать (: Реализация контекстного меню для грида - тема отдельная и сильно выносящая мозг. Вобще контекстное меню имеет весьма минимальный функционал - всего пара методов. Так что вызов меню и для TListBox со списком сериалов и для списка эпизодов в TGrid пришлось делать вручную по OnMouseUp. Тут тоже кроются проблемы. Компоненты имеют пару процедур преобразования координат - из своих в абсолютные и обратно. Абсолютные это относительно формы. А вот popup-меню показывается в экранных координатах. А третья процедура LocalToScreen находится в protected секции TControl, ее можно вызвать через интерфейс IControl. Вообще использование интерфейсов немного меняет логику скрытия методов в protected/private секции. Для получения экранных координат проще к абсолютным прибавить left/top самой формы. У грида с показом попап-меню вообще проблемы - большие затруднения вносит HitTest: Если мы делаем редактируемые колонки - то они должны иметь HitTest = true. Следовательно фокус гриду не передается, и меню не показывается. Еще меню себя плохо ведет при открытии: в VCL если мы откроем меню, и кликнем еще раз правой кнопкой мыши, то меню откроется в новом месте клика - обычное вроде как поведение для Windows. В Fmx такого нет - меню будет висеть пока вы не кликните куда нить левой кнопкой. Возможно это косяк в Platform.StartMenuLoop. В редактируемом гриде напряегат, что я просто так не могу кликнуть в чекбокс для отметки эпизода. Первым кликом надо выбрать строку, а только потом кликать в чекбокс. Наверное, недоработка.

Пару слов о картинках, на рисунке выше их несколько. Во-первых - постер сериала - TImage, иконка на кнопке обзора папки справа внизу, и пара иконок в контекстном меню (элементы которого совпадают с содержимым представленной таблице "ссылки"). С первой картинкой - постером, разместив ее на форме я поэксперементировал с различными вариациями Align и Wrap, что в конечном итоге привело к тому, что как ты их не выставляй картинка всегда растягивалась. Пришлось удалить компонент, добавить новый и восстановить настройки. С Align вобще многие элементы ведут себя не корректно (при проектировании), особенно когда устанавливаешь его в alScale, особенно таблицы грешат тем, что улетают куда то далеко за видимую область формы. Также позиционирование элементов некорректно работает при максимизации и восставнолении формы. Вот, например, что происходит, если форму развернуть на весь экран, а потом восстановить обратно:

Раньше (до update3) некорректным поведением грешил TListBox. Что касается иконки на кнопках, то тут вообще беда (в смысле непривычности подхода). В FireMonkey нет компонентов наподобие TImageList, соответственно ни кнопки, ни элементы Popup и т.п. нельзя связать с каким нить набором иконок. Чтобы разместить иконку на кнопку, предполагается добавить на нее TImage, и загрузить элемент туда. На несколько кнопок вы загрузите их, конечно, а если вам понадобится 50 иконок различных? разных размеров и состояний? В общем в любом случае это потребует написания кода. Естественно второй путь - применить свой стиль к кнопке, где добавить иконку, но от написания кода для загрузки изображения это не спасет. Зато можно делать забавные эффекты, например, при наведении на кнопку иконка увеличивается. Либо с помощью эффектов и триггеров анимации можно добавить эффект того, чтобы при наведении рисунок становился цветным, а иначе был чернобелым. Но если ваша задача - снабдить кнопки или элементы списка/меню картинками то это печально (: С иконками popup-меню ситуация обстоит немного сложнее. В моем случае элементы меню генерируются автоматически. Следовательно каждый раз мне следует загружать иконку, а в VCL я бы один раз назначил TPopupMenu.Images, а затем при создании элементов выставлял бы только индексы иконок. Кстати говоря о динамическом создании элементов меню. Если столкнетесь с тем, что создав элемент, вместо него вы увидите только пустой прямоугольник - не отчаивайтесь, здесь вас опять спасет применение стиля. Хотя на самом деле, когда элементы меню создаются в режиме проектирования, то строка StyleLookup там пустая. А при динамическом создании возможно понадобится назначение StyleLookup := 'menuitemstyle'. Есть проблемы с показом модальных форм, а именно, в моем случае, при показе модального окна свойство Position не имеет никакого эффекта. Хоть как его ни ставь, а форма всегда показывается в верхнем левом углу экрана. В принципе вопрос, конечно, решаемый чтобы отобразить форму по центру главной формы приложения следует выполнить примерно такой код:
    mf := Application.MainForm;
    if assigned(mf) then begin
        top  := mf.Top + (mf.Height div 2) - (self.height div 2);
        left := mf.Left + (mf.Width div 2) - (self.width  div 2);
    end;
Однако это не сработает, если модальную форму вы показываете например в OnCreate главной формы приложения, поскольку Application.MainForm назначается уже после его выполнения. Кстати говоря о показе чего либо, свойство Visible у TTabPage скрывает вкладку ее и в режиме проектирования, что как то не особо удобно, ибо свойства TabVisible как в VCL у вкладок нет. Что касаемо взаимодействия с пользователем, то можно обратить внимание на окна сообщений. Говоря о них, сложно сказать, что они действительно "Native Windows look and feel". Вот к примеру, как выглядят окна ShowMessage & MessageDlg в VCL (слева) & FireMonkey (справа):
 
Если первый вариант выглядит все таки как системное окно, то второй вряд ли. Интересно, показываемые заголовки все таки когда-нибудь станут локализованными? :) Кстати, если в VCL вы можете написать просто
MessageDlg('msg text', mtInformation, [mbYes, mbNo], 0);
то в FireMonkey такая строка не скомпилируется, и следует писать
MessageDlg('msg text', TMsgDlgType.mtInformation, [TMsgDlgBtns.mbYes, TMsgDlgBtns.mbNo], 0);
что как то сложно назвать удобным. В причинах пока что не разбирался. Чтобы подытожить статью, скажу что вообще изучение нового фреймворка, это всегда интересно. Чем больше людей его изучают, тем больше появляется открытой и доступной информации, тем больше багов находится, как следствие составляются отчеты, и тем быстрее они будут исправлены. Хотелось бы чтобы на данную платформу были перенесены такие удобства как использование ImageList и иконок в списках/кнопках. Кстати говоря, потребление памяти программой почему то уменьшилось. Раньше при развороте ее на полный экран, объем используемой памяти возрастал почти в 2 раза, а сейчас остается тем же. Мб в update-3, что то поменяли? хотя я после его выхода вроде проверял. Для работы с API сервиса использовал DBXJSON. Если особо не мудрить, то вроде очень простой в работе модуль. Так же для обращений к сервису использовал потоки, что было тоже интересно попрограммировать, учитывая то, что практики применения их большой нет. А еще радует наличие компонента TAniIndicator, который крутится на главной форме, пока происходит авторизация и загрузка начальных данных. В общем то скоро программу можно будет выкладывать для скачивания, а пока что требуется доделать еще пару функций. Таких как поиск и добавление сериалов в свой список, или изменение статуса сериала (т.е назначение, например, "перестал смотреть"). Тем кто еще не отправил свои творения в FireMonkey на Новогодний Блиц желаю побыстрей заканчивать работу, отправить для участия в конкурсе. И поскольку поздравлений с прошедшими праздниками я еще нигде не писал, то всех, кто таки дочитал до конца - с наступившим Новым годом (:
Метки:  myshows  |  delphi  |  FireMonkey 

Комментарии

sky_dweller
13.01.2012 в 15:53
Отражение текста в майн меню просто убийтсвенно! :)
ter
13.01.2012 в 16:17
а то (:
IDS
13.01.2012 в 21:31
Я что-то не понял. А зачем при запуске программы спаршивать логин и пароль? И какие они на самом деле? По тексту проги я не нашёл их. Они какие-то шифрованные. Смысл?
ter
13.01.2012 в 21:24
ну для работы с сервисом требуется учетку там иметь, поэтому и пароль с логином спрашиваются.
для интересу если, то можно использовать demo/demo - учетные данные для тестирования API.
ter
13.01.2012 в 21:40
у меня сначала в коде и забиты были, пока не сделал опцию сохранения логина и пароля, потом в них отпала необходимость.
IL
10.10.2013 в 08:21
Почему все-таки вернули проект на VCL? Будете ли снова переписывать MyShows на FireMonkey и под Андроид? Спасибо.
- Имя
- e-mail*
- Сайт
вы можете использовать теги [i],[b],[code],[quote]
Дополнительно