уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Итак, конкурс на DelphiFeeds.ru успешно окончен, голоса подсчитаны, призы розданы. Поздравляю всех победителей конкурса и надеюсь, что нам ещё предоставят возможность немного посоревноваться и в других конкурсах и, желательно, с большим количеством участников :). Надо сказать, что лично для меня время проведения конкурса оказалось не совсем удачное, поэтому конкурсную программку «Я математик» я отправлял на конкурс в виде полуфабриката — вроде бы идея должна была быть понятной всем, а вот реализация была не совсем удачной. Но, что было — то было. Нет худа без добра — теперь есть небольшое приложение на основании которого можно продолжить цикл статей «Firemonkey. От простого к сложному«, а заодно и доработать «Я математик» и реализовать в нем те идеи, которые возникали в ходе работы над программой в рамках конкурса.

Чтобы Вы могли вместе со мной работать над программой и изучать FireMonkey на «живом» примере, можете скачать саму программу и исходники со страницы «Софт» блога. Там я выложил архив, который был ранее опубликован на странице DelphiFeeds.ru в Facebook.

И первое, что необходимо исправить в программе — это сортировку вопросов. Если Вы запускали программу и пробовали решать задачи, то могли заметить, что они (задачи) идут по порядку. Однако, как указал в своих замечаниях соавтор программы  Гимаев Наиль, такой порядок неверен, если нам надо двигаться от более простых задач к сложным. Порядок должен быть таким:

  1. Умножение на 9. В этом типе задач  математические знания не требуются — только умение правильно и быстро загибать пальцы.
  2. Умножение на 11. Задача сводится к сложению двух однозначных чисел.
  3. Возведение в квадрат чисел заканчивающихся на 5. Эта задача сводится к умножению двух однозначных чисел, что проще, чем следующий тип задач.
  4. Умножение чисел на 5. Здесь уже происходит деление на 2, деление, как заметил Наиль (и я с ним согласен) всегда сложнее умножения.
  5. Корень квадратный. Ну тут, думаю, без комментариев :)
В программе сортировка вопросов по сложности проводится в зависимости от значения свойства Section у класса TTask и компаратор выглядит так:
function TQuestionComparator.Compare(const Left, Right: TQuestion): Integer;
begin
  Result:=Ord(Left.FTask.Section)-Ord(Right.FTask.Section);
end;

Само же свойство Section — это одно из значений:

TTaskSection = (tsNaN = 0,
                tsMultiplyBy5 = 2,
                tsMultiplyBy9 = 4,
                tsMultiplyBy11 = 6,
                tsSquaringNumbers =8,
                tsRootDoubleDegree = 10
                );

и все, что нам сейчас надо — это изменить этот тип вот таким образом:

TTaskSection = (tsNaN = 0,
                tsMultiplyBy5 = 8,
                tsMultiplyBy9 = 2,
                tsMultiplyBy11 = 4,
                tsSquaringNumbers =6,
                tsRootDoubleDegree = 10
                );

Потом, если нам вдруг захочется добавить новый тип задач в программу — достаточно будет добавить новое значение, например так:

TTaskSection = (tsNaN = 0,
tsAnyNewTask = 3, {задача по сложности проще, чем умножение на 11, но сложнее, чем умножение на 9}
tsMultiplyBy5 = 8,
tsMultiplyBy9 = 2,
tsMultiplyBy11 = 4,
tsSquaringNumbers =6,
tsRootDoubleDegree = 10
);

Теперь следующий момент, который хотелось реализовать, но не получилось — разделение игры по уровням сложности.  Сейчас задачи хоть и сортируются по сложности и выводятся по порядку, однако идея деления игры по уровням не реализована. Первоначально предполагалось, что в интерфейсе появятся вот такие кнопки, показывающий текущий прогресс игрока:

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

Когда я хотел реализовать такую возможность в программе, то даже накидал стиль таких кнопок в FireMonkey и даже начал расписывать необходимые события, но потом, когда уже понял, что не успею доработать программу в срок — оставил эту идею и, в принципе, правильно сделал. В чем может быть недостаток такого интерфейса?  На мой взгляд основная проблема — это подсказки к кнопкам. Нет, то, что в FireMonkey почему-то не предусмотрен показ Hint’ов — это не та проблема. Реализовать показ текста можно было бы хоть бы и через TText (пришлось бы, конечно, повыделываться чуток с позиционированием компонента, но это мелочь).  Проблема именно в том, что само название уровня можно посмотреть только, наведя курсор мыши на кнопку. А т.к. игра идёт на время, то сие действие (наведение указателя мыши на кнопку) хоть чуть-чуть да и отнимет у игрока драгоценные секунды. Писать текст на кнопке? Можно, конечно, только, почему тогда вместо кнопок не использовать уже имеющийся компонент TTabControl с немного доработанным стилем? Ведь в FireMonkey, как мы уже знаем, можно любой компонент переделать как нашей душе угодно. И тут мы приступим к работе с FireMonkey.

Доработка компонента TTabControl для «Я математик»

Добавление связей для TTabItem в LiveBindings

Первое, что делаем — это убираем со слоя (TLayout’а), который называется TestLayout компонент TImage, содержащий текстуры листа бумаги (его, если потребуется, мы вернем позже) и кидаем на слой компоненты TTabControl и TStatusBar или TPanel так, чтобы получился вот такой вид окна:

Наш TTabControl сейчас содержит ровно столько элементов, сколько типов задач содержится в программе, т.е. ровно пять. Каждый TTabItem подписан так, что игроку достаточно будет взглянуть на верх окна, чтобы понять на каком уровне он находится. Теперь, пока далеко не углубились в работу со стилем, сразу реализуем показ необходимых TTabItem’ов в зависимости от того, какие настройки были выбраны в игре.

Для этого переходим на слой TitleLayout и ищем на нем список опций — вот этот:

Чтобы скрыть или показать вкладку на TabControl’e в зависимости от состояния CheckBox’a нам не требуется писать никаких обработчиков событий — для этого у нас есть механизм LiveBindings, который позволит нам реализовать задачу показа/скрытия вкладок без единой строчки кода. Пусть у нас вкладка для задачи «Умножение на 9» носит название tabMultiplyBy9, а checkbox в опциях для этой задачи называется Multiply9Check. Чтобы сделать связь в LiveBindings выбирам нужный нам чекбокс, жмем правую кнопку мыши и выбираем «New LiveBinding«. Воспользуемся простым TBindExpression:

Свойства выражения для LiveBindings делаем такими:

  • ControlComponent = Multiply9Check
  • ControlExpression = IsChecked
  • SourceComponent = tabMultiplyBy9
  • SourceExpression = Visible
  • Direction = dirControlToSource

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

Всё. Теперь, если мы в опциях ставим не все задачи, а скажем, только три, то в работающей программе TabControl будет теперь таким:

Ну, а запрет перехода к следующему уровню сложности без выполнения текущего мы реализуем непосредственно в коде приложения. Теперь перейдем непосредственно к стилю TTabControl’а.

Доработка стиля TTabControl

Здесь нам необходимо сделать так, чтобы в закладке на TTabItem’e как-либо отображалось на каком этапе мы находимся — тренировка или экзамен, а также сделать возможность перехода к необходимому этапу игру по клику мышки. Первым делом можем вернуть на место текстуру тетрадного листа (если он вам нужен). Для этого жмем правой кнопкой мыши в любом месте TabControl’а и выбираем «Edit Custom Style«. В редакторе ищем TRectangle и изменяем ему свойство Fill, загрузив в качестве «заполнителя» Bitmap:

Теперь все пространство TabControl’a будет выглядеть так же, как и прежде, но закладки (TabItem‘ы) так и останутся стандартного цвета и размера т.к. их стиль редактируется отдельно.

Для редактирования стиля TTabItem необходимо выбрать его в окне Structure, например, так:

Теперь в окне дизайнера жмем правую кнопку мыши и выбираем «Edit Custom Style«:

Как и в случае с TTabControl откроется окно редактора стиля, но уже для нашей закладки.

Стиль TTabItem’а по умолчанию носит название tabitemstyle.  Убедиться в этом довольно просто: достаточно положит на форму компонент StyleBook и загрузить в него стили по умолчанию *воспользоваться в редакторе компонента опцией «Load Default»

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

Обоим TImage выставляем свойство Align = alRight, а для TText Align=alClient. Ширину кнопки сделаем равной 16px. Должно получиться как на рисунке выше. Загружаем картинки кнопок в TImage и можем теперь сохранить наш стиль, чтобы посмотреть, что у нас в итоге получилось. А получилось следующее:

Чтобы применить новый стиль закладки сразу ко всем закладкам всех TabControl’ов на форме достаточно присвоить свойству Name значение tabitemstyle.

Можно заметить, что крайняя правая кнопка «жмется» к краю TabItem’а, чтобы такого не происходило достаточно у этого TImage отредактировать свойство Padding.Right, установив ему значение, например 3. Тогда закладки станут выглядеть более презентабельно:

Теперь остается добавить несколько эффектов (TEffect) для наших кнопок, чтобы зделать наши импровизированные кнопочки более живыми. Например, можем воспользоваться эффектом TShadowEffect, который будет активироваться при наведении курсора мыши на кнопку. Для этого бросаем два TShadowEffect на наши TImage как показано на рисунке:

и выставляем для обоих эффектов свойства:

  • Enabled = False;
  • Trigger = ‘IsMouseOver = True’

Вот и все. Сохраняем стиль, запускаем программку и любуемся эффектом тени на кнопках:

Что дальше? А дальше мы приступим к разработке небольшого класса-наследника TTabItem, который и будет у нас отвечать за работу с только что «нарисованными» кнопками, однако этой частью работы мы займемся в следующий раз.

Кстати, если кого-то заинтересовала работа с TTabControl — можете прогуляться в блог Роман.Янковский.me и посмотреть как там автор расширял TTabControl в FireMonkey и к какие выводы были сделаны. А я тем временем структурирую материал для новой части цикла «FireMonkey. От простого к сложному»  и расскажу как далее дорабатывался «Я математик».

 

0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
2 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Keeper
10/08/2012 01:38

Влад, чиркни в блоге, как дался тебе новый фреймворк (в сравнении с VCL или WPF).
P.S. Мои личные впечатления выразить пока не могу — в первую очередь, потому что они не радужные: пробовал перенести небольшой дипломный проект, но так и не смог — то одного нет, то другое не работало и т.д.