Блог Александра Божко
Архивы
Рубрики

Технические приемы

Небольшой пост-шпаргалка. Буду предельно краток.

Допустим, у нас есть некий перечисляемый тип. Например:

  TFieldType = (ftUnknown, ftString, ftSmallint, ftInteger, ftWord, // 0..4
ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, // 5..11
ftBytes, ftVarBytes, ftAutoInc, ftBlob, ftMemo, ftGraphic, ftFmtMemo, // 12..18
ftParadoxOle, ftDBaseOle, ftTypedBinary, ftCursor, ftFixedChar, ftWideString, // 19..24
ftLargeint, ftADT, ftArray, ftReference, ftDataSet, ftOraBlob, ftOraClob, // 25..31
ftVariant, ftInterface, ftIDispatch, ftGuid, ftTimeStamp, ftFMTBcd, // 32..37
ftFixedWideChar, ftWideMemo, ftOraTimeStamp, ftOraInterval, // 38..41
ftLongWord, ftShortint, ftByte, ftExtended, ftConnection, ftParams, ftStream, //42..48
ftTimeStampOffset, ftObject, ftSingle); //49..51

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

GetEnumName(TypeInfo(TFieldType), Ord(aDataSet.Fields[I].DataType));

На выходе получаем строку, содержащую название типа для поля aDataSet.Fields[I].

Одним из главных преимуществ Berlin‘а, является визуальный редактор ListView Item. За три месяца с момента выпуска продукта о нём не написал только ленивый. И он действительно удобен. Он экономит “массу времени, сил и духовной энергии…” (с). Но есть одна проблема, с которой столкнулся я, и судя по записям в многочисленных форумах, не я один. Как только свойство Item Appearance принимает значение DynamicAppearance, при работе с представлениями формы начинается чехарда.

ItemApp Читать далее

К сожалению, времени на всё запланированное банально не хватает. Смена хостера, обновление движка Delphifeeds и многое другое. Тем не менее, начал писать подробный мануал по созданию полноценного мобильного приложения и даже собрал команду болельщиков в этом начинании. Но быстро сказка сказывается, да не быстро дело делается. А пока решил сделать несколько постов в новую рубрику. Как следует из названия, здесь будут публиковаться “зарубки на память”, небольшие лайфхаки и прочие материалы, которые назвать оригинальными можно с натяжкой, но под рукой иметь полезно. Для начала маленький лайфхак для начинающих разработчиков.

Представьте, что в режиме проектирования вам нужно клонировать на форме какой-то сложный объект, например, DataSet. Казалось бы всё просто. Выделяете объект и копируете его в буфер обмена (Ctrl+C). Затем вставляете его на форму и переименовываете новый объект. Но здесь есть один не совсем приятный момент. Если мы откроем редактор полей, то обнаружим, что поля вновь созданного объекта не имеют осмысленных названий, а называются примерно так, как показано на рисунке.

Кроме типа поля из названия смысловой информации мы не получим. Конечно, в данном случае есть простое решение. Удаляем все поля, затем копируем все поля из исходного DataSet’а и вставляем в новый DataSet. Все поля приобретут осмысленные названия. которые мы сможем использовать в коде.

Но что делать, если копирование полей не поддерживается, как, например в TdxMemData от DevExpress? Конечно, можно создать заново все поля вручную, но значительно проще отредактировать код формы. Для этого я использую Notepad++. В принципе подойдёт любой редактор, с поддержкой глобальной замены текста. Всё просто. В Delphi IDE мы выбираем текстовое представление формы. Копируем и переносим код интересующего нас объекта вместе с вложенными объектами в редактор и производим замену по шаблону. После этого вставляем код нового объекта в исходный код формы. Что бы не возиться с описаниями объекта в pas-модуле, просто вырежьте и снова вставьте его на форму.

Часть #0

Создание клиентского приложения

Поскольку в нашем случае речь идёт о мобильном приложении, клиентской приложение будет создано с помощью FireMonkey.

  • Создаем новое Multi-Device приложение (настройки не критичны);

DataSnapClient000

Я создаю клиентское приложение в группе, что дает возможность параллельно отлаживать и серверное приложение.

Читать далее

Создание отчётов в приложениях никогда не относилось к категории моих любимых занятий. Тем не менее, так или иначе, этим приходится заниматься. В своем рабочем проекте, о котором я уже не раз рассказывал, я перевёл практически все отчеты с Rave на FastReport. Последний инструмент сейчас является безусловным лидером “отчётостроения” и если есть необходимость поддерживать проект в управляемом состоянии, то подобное преобразование просто необходимо выполнить. Естественно, при этом хотелось максимально эффективно использовать возможности FastReport и оптимизировать во всех отношениях старые отчеты. Одной из типичных проблем отчётах всегда была проблема отображения Memo полей. Они могут содержать достаточно объемный текст, а могут, напротив, иметь пустые значения. Если такие данные отображать в столбце рядом с обычными данными, то визуально это будет выглядеть малопривлекательно. Читабельность отчета снижается и данные воспринимаются значительно хуже. Проблема довольно типичная, поэтому я решил сделать небольшой пост на эту тему.

На уровне логики всё решается достаточно просто. Значения Memo полей можно опционально выводить под строкой, содержащей основные данные. Примерно так:

Решение простое и логичное. При этом обратите внимание на то, что в случае отсутствия данных в Memo поле, не остается пустого места между строками. Читать далее

lost_timerПрежде чем продолжить рассказ о таймере – две новости.

Во-первых, вышел первый апдейт XE7. По традиции он доступен зарегистрированным пользователям. Список исправленных багов вы можете найти здесь. Мне хотелось посмотреть как поведет себя приложение в обновленной среде. Собственно, никаких исправлений вносить не пришлось, хотя поле для экспериментов осталось.

Вторая новость. Действие специальных предложений Embarcadero продлено до конца года:

  • возможен апгрейд с любой старой версии на новую версию XE7: Delphi, C++ Builder и RAD Studio.
  • покупатели редакций Enterprise, Ultimate и Architect получают бесплатную лицензию Rapid SQL XE6.

Ну, а теперь непосредственно к теме поста. В принципе, все, что нам осталось – попытаться запустить уже созданное приложение под Android. Для это используем то, о чем я писал в предыдущих постах. А именно новый FireUI. Я отлаживал данное приложение на Nexus 7, соответственно добавил представление Android 7″ Tablet. Дизайн пришлось “подрихтовать” лишь самую малость.

Читать далее

В прошлой части мы практически полностью реализовали логику приложения. Сейчас я хочу рассказать о, возможно, самой интересной части разработки приложения. Построении пользовательского интерфейса. Если вы еще не в курсе, что такое FireUI, то, вероятно удивитесь, что большая часть работы по построению и отладке GUI Android приложения будет производится в Windows, без использования мобильного устройства. Субъективно, я в восторге. Это быстро, удобно и во всех отношениях легко.

Приступим…

Итак, у нас есть чистая (в смысле используемых стилей) форма, с четырьмя кнопками и меткой TLabel. Конечно у меня, изначально было  искушение бросить на форму TStyleBook, а метку отобразить каким-нибудь диковинным шрифтом. Посмотрев на приложение Владимира Тимофеева я отказался от этой идеи. Подобную красоту придется рисовать руками. Или немного схитрить, используя возможности библиотеки классов FireMonkey. Я выбрал второй вариант. Немного погуглив по слову Scoreboard, я нашел на коммерческом стоке графических изображений симпатичный алфавит, дополненный цифрами.

Digital alphabetic

Так выглядит выбранный мною клипарт. Вооружившись чувствительной мышкой и терпением я вырезал из него цифры. Читать далее

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

Разрабатывать мы будем именно таймер, в англоязычном понимании этого термина. Т. е. на экране будет отображаться циферблат и четыре кнопки – “Пуск”, “Пауза”, “Стоп” и “Отмена”. Отсчет будет производиться в прямом направлении (т. е. время будет увеличиваться). Вариант, при котором задается время и идет обратный отсчет в англоязычной терминологии называется Stop Watch, возможно я попробую реализовать его позже.  То, приложение, которым займемся мы, по функциональности ближе к секундомеру.

Delphi XE7, позволяет значительно упростить процесс разработки, за счет того, что теперь мы можем создать и отладить реальное приложение для Win32, а затем просто добавить представления форм для необходимых мобильных устройств и, немного подкорректировав их, получить рабочее мобильное приложение. Звучит слишком красиво, что бы быть правдой? Возможно. Но проверить данное утверждение я и хочу, реализовав поставленную задачу. Читать далее

Технология App Tethering появилась еще в прошлой версии Delphi. И рассказать о ней я собирался еще после выхода XE6, однако, как это часто бывает “не дошли руки”. Этот механизм предназначен для взаимодействия приложений на разных устройствах. Примечательно, что он поддерживается как в VCL, так и в FireMonkey. В XE7 в App Tethering были добавлены новые возможности, что для меня стало очередным поводом разобраться и сделать пару примеров. Обдумывать идеи для тестового приложения долго не пришлось. Так получилось, что сейчас у меня на рабочем столе  стоит два ПК и, время от времени появляется планшет и смартфон (оба под управлением Android). Работаю я с этими устройствами практически одинаково интенсивно и, соответственно, возникает необходимость оперативно обмениваться не только файлами, но и текстовыми фрагментами, ссылками и т. д.. Конечно, существуют сотни программ, решающих это задачу, но коль скоро у нас имеется инструмент, то грех не написать собственное приложение, реализующее данный функционал.

В идеале мне бы хотелось бы создать некоторое приложение, работающее как под Windows, так и под Android, которое позволяло бы:

  • осуществлять обмен файлами между устройствами;
  • осуществлять обмен содержимым буфера обмена.

При этом хотелось бы исключить сложную процедуру настройки соединения для различных устройств.

Поскольку изобилия русскоязычных материалов по App Tethering пока не наблюдается, я буду перемежать рассказ о процессе разработки приложения  выдержками из документации.

Разработку начнем с реализации простейшего функцонала – обмена файлами между ПК. Для того, что бы упростить понимание принципов работы App Tethering создадим два приложения – приложение, передающее файлы (“передатчик”) и приложение, принимающее файлы (“приемник”). Во избежание путанницы я сознательно не стану использовать термины “клиент”, “сервер” и т.д. “Передатчик” реализуем на VCL, а “приемник” – на FireMonkey. Опять же все это из соображений наглядности. В идеале это должно быть одно мультиплатформенное приложение, совмещающее в себе функции приема и передачи файлов. К этому вопросу, надеюсь, мы вернемся чуть позже.

Итак создадим два приложения,VCL и FireMonkey(Multi-device application), назовем их PrjSender и PrjReceiver и объеденим их в одной группе проектов. Механизм App Tethering в Delphi реализуют всего два компонента TTetheringManager и TTetheringAppProfile  (менеджер и профиль). Размещаем их на главной (и пока единственной) форме обоих приложений. В обоих случаях для TetheringAppProfile устанавливаем значение свойства TetheringManager – TetheringManager1, таким образом связываем менеджер с профилем.

Для чего нужны эти компоненты? Документация гласит следующее:

Менеджер может обнаруживать и попарно связываться с другими менеджерами, представляющие удаленные профили, которые могут “расшаривать” данные для зарегистрированных профилей вашего менеджера. Менеджер может быть связан с одним или несколькими профилями. Основные функции менеджера:

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

Все это звучит немного сумбурно, но попробуем разобраться во всем на практике. Прежде всего, нам нужно обеспечить соединение между двумя приложениями. В верхней части главной формы приложения-приемника разместим компонент ListBox (lbSenders) и кнопку (btnGetAvailableSenders). По нажатию на кнопку отобразим список доступных удаленных менеджеров. Для этого определим обработчик события OnEndManagersDiscovery следующим образом:

procedure TfRecMain.TetheringManager1EndManagersDiscovery(const Sender: TObject;
  const ARemoteManagers: TTetheringManagerInfoList);
var
  I: Integer;
begin
 lbSenders.Clear;

 for I := 0 to aRemoteManagers.Count - 1 do
 begin
  lbSenders.Items.Add(ARemoteManagers[i].ManagerText);
 end;

end;

А по нажатию на кнопку вызовем метод DiscoverManagers компонента TetheringManager.

procedure TfRecMain.btnGetavailableSendersClick(Sender: TObject);
var
i: integer;
begin
  for I := TetheringManager1.PairedManagers.Count - 1 downto 0 do
    TetheringManager1.UnPairManager(TetheringManager1.PairedManagers[I]);

  lbSenders.Clear;
  TetheringManager1.DiscoverManagers;

end;

Предварительно здесь мы очищаем список и разрываем все связи (метод UnPairManager). Читать далее

В одном из постов, если не ошибаюсь в блоге у Всеволода Леонова, довелось мне прочесть про забавный кейс. В программе было предусмотренно ограничение длины поля ввода пароля. При том, ограничивалось оно тихо, просто “съедая” лишние символы. Естественно, что после этого с паролями возникла неразбериха. В принципе, вопрос ограничения длины поля ввода сам по себе является философским, а возможно даже теологическим, но просто взять и “откусить хвост” вводимому тексту, на мой взгляд – не совсем правильно. Однако, в большинстве случаев, если задать свойство MaxLength для контрола, отвечающего за ввод текста, именно так и произойдет.

Компонент TcxTextEdit и другие компоненты из набора DevExpress  могут красиво решать данную проблему благодаря событию OnValidate.

Код, который я использую выглядит примерно так:

procedure TfrmEditBenefit.txtBenefitNamePropertiesValidate(Sender: TObject;
  var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean);
begin
 if Length(txtBenefitName.Text)>125 then
 begin
   ErrorText:= 'Benefit name value is too long.';
   Error:= True;
 end;
end;

Для наглядности можно показать значок ошибки рядом с полем ввода.

 

txtBenefitName.Properties.ValidationOptions:= [evoRaiseException, evoShowErrorIcon];

Выглядеть это будет примерно так:

TextValueIsTooLong

Ошибка генерируется если текст длиннее допустимого значения при попытке передать фокус другому контролу. При этом пользователь зразу видит что и где не так. По-моему очень удобно и наглядно.

Другие статьи серии:

DevExpress. TIPS & TRICKS #0
DevExpress. TIPS & TRICKS #1
DevExpress. TIPS & TRICKS #2
DevExpress. TIPS & TRICKS #3
DevExpress. TIPS & TRICKS #4
DevExpress. TIPS & TRICKS #5
DevExpress. TIPS & TRICKS #5.5
DevExpress. TIPS & TRICKS #6

Продукты DevArt
Купить онлайн:



Читай русскоязычные Delphi блоги
Каталог блогов Blogdir.ru
Яндекс.Метрика