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

Delphi

В контексте своих предыдущих постов я неоднократно упоминал те или иные компоненты доступа к данным. В данном обзоре я хочу рассказать о продуктах компании DevArt. В мире Delphi эта компания хорошо известна именно благодаря компонентам доступа к данным. Если вы искали с помощью чего подключиться, например, к Oracle или Postgre SQL, то наверняка обращали внимание на ODAC или PgDAC, соответственно.

В настоящий момент компания предлагает несколько специализированых библиотек для подключения к различным СУБД (Interbase/FireBird, Oracle, Postgre SQL, MySQL, SQLite, MS SQL). Кроме этого, существует универсальное решение – UniDAC. Эта библиотека поддерживает различные СУБД, подключаясь к ним различным способом (см. схему). “Самые быстрые и надежные решения для работы с любыми базами данных” – гласит слоган на русскоязычной странице библиотеки.

Совершенно недавно я получил возможность на практике познакомиться с возможностями  UniDAC, использовав данный набор в проекте DB Meta Studio. Сама функциональность данного приложения предполагает универсальность и возможность работать с разными СУБД. Здесь я попытаюсь дать общее представление о UniDAC и поделиться своими субъективными впечатлениями. Читать далее

Вышло обновление FireDAC для пользователей XE4. Данное обновление распространяется сразу в трех редакциях, в зависимости от того, какая используется редакция базового продукта.

FireDAC XE4 Update 2 for RAD Studio Pro & Delphi Pro w/ Mobile

Доступна только зарегистрированным пользователям  Professional редакции Delphi XE4 с Mobile Add-On Pack, Professional редакции RAD Studio XE4 или Embarcadero All-Access XE Bronze level.

FireDAC XE4 Update 2 for RAD Studio/Delphi/C++ Ent/Ult/Arch

Доступна только зарегистрированным пользователям Enterprise, Ultimate или Architect редакций  Delphi XE4, C++Builder XE4 или RAD Studio XE4 или Embarcadero All-Access XE Silver level и выше.

Напоминаю, что до 28 июня вы можете воспользоваться скидкой на продукты Embarcadero редакции XE4, а также получить дополнительные продукты на сумму $300. В том числе вы можете приобрести:

Ознакомиться с ценами для всех редакций и купить Delphi XE4 и RAD Studio XE4.

Создание FireMonkey приложения с использованием FireDAC. #0

Создание FireMonkey приложения с использованием FireDAC. #0.5

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

Простой редактор данных в таблице, обычно является частью комплексного приложения. Для редактирования таблиц я обычно использую отдельную форму. Начнем со списка продуктов.  Прежде всего, нам необходимо создать DataSet для доступа к данным таблицы. В нашем случае вполне можно воспользоваться компонентом TADTable. Поместим его в DataModule и укажем значение свойства Connection. В редакторе свойства TableName появится список таблиц, из которого выбираем таблицу Products. Если вы все сделали правильно, то сможете присвоить свойству Active значение True. Компонент лучше сразу переименовать (например, ADTProduct). После этого я, обычно, создаю для DataSet’а набор полей. Вызываем редактор полей (двойное нажатие мыши на компоненте) и в контекстном меню выбираем пункт Add All Fields.

(в настоящее время ссылка не доступна)

Для тех, кто не в курсе поясню суть данной операции. Здесь мы создаем предустановленный набор полей DataSet’a. Если мы этого не сделаем вручную в режиме проектирования, то, в принципе, ничего страшного не произойдет. В RunTime этот набор будет создан автоматически. Но я, все же, предпочитаю создавать его вручную. Причин тому несколько. Во-первых, так удобнее управлять набором полей, ведь мы можем создавать дополнительные (вычисляемые или lookUp) поля самостоятельно в режиме проектирования. Можем так же менять свойства самих полей. А кроме того, мы получаем возможность обращаться в коде к полям по имени компонента TField, что, на мой взгляд, существенно упрощает написание кода.

Как и в случае с VCL приложением, подключим к набору данных компонент TDataSource. Этот компонент обеспечит связь между набором данных и визуальными элементами управления. Свойство DataSet компонента должно ссылаться на наш набор данных (ADTProduct). Ниже я привожу фрагмент DFM файла

 

  object ADTProduct: TADTable
    IndexFieldNames = 'ID'
    Connection = ADConnection
    UpdateOptions.UpdateTableName = 'Product'
    TableName = 'Product'
    Left = 64
    Top = 192
    object ADTProductID: TADAutoIncField
      FieldName = 'ID'
      Origin = 'ID'
      ProviderFlags = [pfInWhere, pfInKey]
      ReadOnly = True
    end
    object ADTProductTitle: TStringField
      FieldName = 'Title'
      Origin = 'Title'
      Size = 50
    end

  object dsProduct: TDataSource
    DataSet = ADTProduct
    Left = 120
    Top = 192
  end

Обратите внимание на одну любопытную особенность, файл формы DataModule сохраняется не в формате FMX, как обычная FireMonkey форма, а в формате DFM, как и в VCL.

Следующим шагом будет создание процедуры открытия набора данных, которую мы должны будем вызывать в RunTime при запуске программы. Создадим ее в том же DataModul’е. Код процедуры предельно прост:

procedure TDM.ConnectToDB;
begin
  ADConnection.Open();
  ADTProduct.Open();
end;

Вызов процедуры разместим в обработчике события OnCreate для DataModule. Читать далее

Очередной пост, рожденный из практической задачи.

Я уже неоднократно писал о том, что для защиты приложений использую ASProtect SKE, и время от времени мне приходится решать нестандартные задачи, связанные с его использованием. Как раз сегодня, мне пришлось поэкспериментировать с одной из таких задач. Суть в следующем. В нашем проекте существует основное приложение и несколько приложений сателлитов. Эти дополнительные приложения продаются отдельно и, соответственно, защищаются отдельными ключами. В один прекрасный момент мы решили одно из таких приложений объединить с главным, сохранив при этом необходимость его регистрации.

Иными словами, приложение должно проверять не один ключ, а сразу два. Можно ли это реализовать с помощью ASProtect? Я решил это проверить.

Актуальная версия ASProtect SKE – 2.65. Хотя я продолжаю использовать более раннюю версию (2.2), рекомендую все же скачать и установить последнюю. Дело в том, что в ней представлен исправленный файл aspr_api.pas, адаптированный для работы с новыми версиями Delphi, поддерживающими unicode. В принципе, вы можете использовать и более раннюю версию продукта с обновленными api заголовками.

В качестве базового я взял пример из комплекта поставки (..Reg_trial\Delphi).

Прежде всего, давайте откроем .aspr2 файл – проект ASProtect. В оригинальном примере он содержит два режима: Trial Mode и Registered Mode. Кроме того, следует убедиться, что ключ хранится в текстовом файле. Для этого откройте пункт меню Options | Keys storage area type:

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

Вдогонку к предыдущему посту. Вопрос об именах таблиц.

Попытаюсь объяснить логику.

Если соблюдать все рекомендации по разработке приложений, то начинать следует с модели предметной области. Существует несколько разных подходов к моделированию и разных видов моделей. Остановимся на одном из самых популярных видов – ER модели, предполагающей определение сущностей и связей между ними. Обычно имена сущностей выражаются существительным в единственном числе.

Собственно, давайте определимся с этими сущностями и связями в нашей задаче. Думаю я на русском, поэтому сначала выделим и обзовем сущности по-русски.

Как процесс выглядит в реальности (без автоматизации)? Я беру лист бумаги и записываю на нем список продуктов, возможно с указанием их количества. С этим листом бумаги я иду в магазин и отмечаю, что куплено, что нет.

Очевидно, что первой сущностью будет сам ПРОДУКТ. Ведь набор наименований продуктов, в принципе, конечен. Да и при автоматизации процесса их удобно выбирать из предустановленного списка.

Я берусь утверждать, что сам листок с записями так же следует выделить в качестве сущности. Я завел машину и тут мне позвонил сосед. Ты, мол в супермаркет? Купи мне пиво и хлеб (с)… И я беру второй лист бумаги и пишу: “Продукты для соседа”. Ставлю дату (вот уже два атрибута у сущности!) и записываю чего он там хочет… Как означить эту сущность? СПИСОК ПРОДУКТОВ – плохая идея. Хотя бы потому, что набор экземпляров сущности ПРОДУКТ тоже а некотором смысле список продуктов. Поэтому более удачным названием будет СПИСОК ПОКУПОК (насколько может быть удачным имя сущности, содержащее слово СПИСОК).

Но нам потребуется и третья сущность. По идее, две первые сущности связаны отношением много-много, и на уровне логической модели ничего добавлять не надо. Но, у нас завис такой атрибут как количество покупаемого продукта. Поэтому вводим сущность, соответствующую записи в списке покупок. И опять логично бы было назвать эту сущность СПИСОК ПРОДУКТОВ и опять это не совсем хорошая идея. Я просто решил обозначить эту сущность комбинацией имен связанных сущностей – СПИСОК ПОКУПОК – ПРОДУКТ. А, поскольку это не совсем удобочитаемо, то просто – СПИСОК-ПРОДУКТ.

Возможно, название ПУНКТ СПИСКА ПРОДУКТОВ (Shoping List Item) тоже имеет право на существование.

ERModel

Теперь на основе полученной модели надо создать таблицы. Естественно, что их имена должны либо транслитерироваться, либо переводиться. Я выбрал последний вариант.

Product, ShopingList, List_Product.

По сути, все “правила” именования сущностей и таблиц носят исключительно рекомендательный характер. И говорить о том, что они названы правильно или не правильно, не совсем корректно. Основной критерий здесь, на мой взгляд, удобство.

Ну, и в контексте данного поста напомню о DB Meta Studio – утилите, которая позволяет вставлять в код элементы структуры БД по заранее заданному шаблону. Читатели моего блога могут получить утилиту в подарок.

Отдельное спасибо Николаю Звереву за присланный отзыв о DB Meta Studio.

Очередной небольшой пост-шпаргалка.

Как и большинство компонентов доступа к БД, FireDAC позволяет получить списки имен таблиц и полей. Однако, отличительной особенностью FireDAC является то, что при получении этих списков, в случае, если имя поля совпадает с ключевыми словами SQL, оно заключается в квадратные скобки. Это можно использовать для анализа структуры БД и поиска “проблемных имен полей”. К слову, если структура БД составлена не достаточно аккуратно, такие поля могут доставить массу неприятностей при отладке SQL запросов.

Все действительно довольно просто. Я покажу как решить задачу на примере СУБД MS Access. Принципиальных отличий при работе с другими СУБД быть не должно. Поместим на форму три компонента:

ADConnection: TADConnection;
ADPhysMSAccessDriverLink1: TADPhysMSAccessDriverLink;
ADGUIxWaitCursor1: TADGUIxWaitCursor;

Настроим подключение ADConnection с помощью редактора. Так же расположим на форме кнопку и компонент Memo. Обработаем нажатие кнопки следующим образом:

procedure TForm1.Button1Click(Sender: TObject);
var
Lst, fldLst: TStrings;
tblName, fldName: string;
begin
try
  Lst:= TStringList.Create;
  ADConnection.Connected:= True;
  ADConnection.GetTableNames(  '', '', '', Lst, [osMy],[tkTable, tkTempTable, tkLocalTable]);
  for tblName in Lst do
  begin
   try
   FldLst:= TStringList.Create;
   ADConnection.GetFieldNames('', '', tblName, '', FldLst);
   for fldName in fldLst do
   begin
     if Pos('[', fldName)=1 then
     begin
       Memo1.Lines.Add(tblName+ ' --> '+fldName);
     end;
   end;

   finally
    FreeAndNil(fldLst);
   end;
  end;

finally
  FreeAndNil(Lst);
end;
end;

Как видно из кода, списки имен таблиц и полей формируются при помощи двух методов (GetTableNames и GetFieldNames). Если имя поля заключено в квадратные скобки, оно выводится в Memo.  Результат выполнения данного кода может вас изрядно удивить.

tblCompanies –> [Currency]
tblCompanies_PDA –> [Password]
tblDeleted –> [Unique]
tblEmployee_tblVariables –> [Value]
tblEmployees –> [Password]
tblModifications –> [Unique]
tblProjects_PDA –> [Password]
tblSchedule –> [Unique]
tblTiming –> [Unique]
tblTiming_PDA –> [Unique]
tblTiming_PDA –> [Password]
tblVariables –> [Value]

А самое интересное, что попытка обратиться к этим полям непосредственно из MS Access без использования квадратных скобок вызывает ошибку.

В заключение хочу напомнить, что 22 мая 2013 г. заканчивается время действия вводной скидки на Delphi, C++Builder и RAD Studio XE4.

Купить сейчас и сэкономить 10%.

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

Как ни странно, не смотря на достаточно интенсивную информационную поддержку продукта, многие не понимают что из себя представляет FireDAC и зачем он включен в состав Delphi/C++ Builder/RAD Studio.  Поэтому вкратце…

FireDAC это новая библиотека компонентов доступа к данным, созданная на базе хорошо известной AnyDAC. Фактически она стала заменой альтернативой  dbExpress. Сочетает в себе простоту использования, стабильность работы и широкие функциональные возможности. Кроме этого впечатляет набор поддерживаемых СУБД.

Владельцы старших редакций Delphi получают FireDAC бесплатно. Владельцы Professional редакции могут купить Пакет дополнений к Delphi XE4 Professional для клиент-серверного подключения FireDAC .

Подобный продукт для меня представляет особый интерес, хотя бы потому, что мне есть с чем сравнивать (о чем еще будет отдельный разговор). И практически-прикладная задача сразу же нашлась. Я уже писал о том, что в утилите DB2Clipboard реализовал импорт модели, создаваемой ER/Studio из XML формата. Теперь же, с использованием FireDAС,  никто не мешает подключаться к БД напрямую. При правильной подходе можно организовать импорт структуры из любой СУБД, поддерживаемой FireDAC.

Настройка подключения.

В силу определенных причин, первым делом я попробовал настроить соединение с БД MS Access. Все оказалось достаточно просто. На форму водружаются компоненты
TADConnection, TADPhysMSAccessDriverLink и TADGUIxWaitCursor. Даблклик по компоненту TADConnection вызывает диалог настройки соединения.

Читать далее

В этом посте, как и обещал, немного расскажу об утилите, позволяющей вставлять элементы структуры БД в текст, посредством буфера обмена. Рабочее название DB2Clipboard.

Зачем это нужно?

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

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

Как это работает?

В данной версии программы, структура базы данных загружается из  .xsd файла, который генерируется с помощью ERStudio (см. предыдущий пост). В отличие от предыдущего варианта данная версия может работать практически с любой СУБД. Минус, собственно заключается в том, что требуется ERStudio. Как и раньше на экране висит StayOnTop форма в левой части которой находится список таблиц (представлений, запросов и т.д.), а справа – набор кнопок, каждая из которых соответствует полю в соответствующей таблице. То, как это выглядит на практике показано на видео. Рекомендую смотреть в HD в полноэкранном режиме.

 Что сделано?

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

FieldByName(‘<fn>’).as<ft>;,

то вместо <fn> в текст будет вставляться имя поля, а вместо <ft> – его тип. Так же реализована поддержка циклического перебора полей и имитация нажатия некоторых клавиш (Enter, Home, Tab и т.д.).

Как это реализовано?

Поразмыслив, я решил полностью переработать структуру программы. Написал несколько классов.

TmbsTimer = class(TTimer)
 {skip}

 public
  property fgw: HWND read Ffgw write SetFGW;
end;

TmbsTableInfo = class
{skip}
 public

 constructor Create;

  property TblName: string read GetTableName write SetTableName;
  property FieldList: TmbsFieldList read GetFieldList  write SetFieldList;
end;

TmbsTableList = class
{skip}
  public
    { public declarations }
    constructor Create;
    procedure Add(pTable: TmbsTableInfo);
    procedure Delete(Index: Integer);
    function Count: Integer;
    procedure ImportXML(FileName: string);
    procedure Clear;

    property Tables[Index: Integer]: TmbsTableInfo read GetTable; default;
end;

TmbsFieldInfo =  class
{skip}
  public
  property FldName: string read GetFLDName write SetFLDName;
  property Table: TmbsTableInfo read GetTable write SetTable;
  property FldSize: integer read GetFldSize write SetFldSize;
  property FldType: string read GetFldType write SetFldType;
  property Checked: boolean read GetChecked write SetChecked;

end;

TmbsFieldList = class

{skip} 

  public
    { public declarations }
    constructor Create;
    procedure Add(pField: TmbsFieldInfo);
    procedure Delete(Index: Integer);
    function Count: Integer;
    property Table: TmbsTableInfo read GetTable write SetTable;
    property Fields[Index: Integer]: TmbsFieldInfo read GetField; default;
  published
    { published declarations }
end;

  TmbsCustomButton = class(TBitBtn)
{skip}
  public
    { Public declarations }
    procedure Click; override;
    property FGW: HWND read FFGW write SetFGW;
    constructor Create(AOwner: TComponent);  override; //; Fld: TmbsFieldInfo
    destructor Destroy; override;
  published
    { Published declarations }
    property InsertedText: string read GetInsertedText write SetInsertedText;
    property Timer: TmbsTimer read GetMbsTimer write SetmbsTimer;
  end;

  TmbsTblButton = class(TmbsCustomButton)
{skip}
  public
    { Public declarations }
     function ExpressionToInsString(AEpression: string): string;
     procedure Click; override;

  published
    { Published declarations }
    constructor Create(AOwner: TComponent);  override; //; Fld: TmbsFieldInfo
    property Expression: string read GetExpression write SetExpression;
    property DefExpressionIndex: integer read GetDefExpressionIndex write SetDefExpressionIndex;
    property Table: TmbsTableInfo read GetTable write SetTable;
  end;

  TmbsFieldButton = class(TmbsCustomButton)
{skip}
  public
    { Public declarations }
    class function ReplaceTblTags(s: string; aTbl: TmbsTableInfo): string; static;
     function ExpressionToInsString(AEpression: string): string;
     procedure Click; override;
  published
    { Published declarations }

    constructor Create(AOwner: TComponent);  override; //; Fld: TmbsFieldInfo
    property Field: TmbsFieldInfo read GetField write SetField;
    property InsertType: TmbsFldInsType read GetInsertType write SetInsertType;
    property Expression: string read GetExpression write SetExpression;
    property DefExpressionIndex: integer read GetDefExpressionIndex write SetDefExpressionIndex;
  end;

  TmbsFieldCheckBox = class(TcheckBox)
{skip}

 published
    { Published declarations }

    constructor Create(AOwner: TComponent);  override; //; Fld: TmbsFieldInfo
    property Field: TmbsFieldInfo read GetField write SetField;

  end;

Выше приведены фрагменты описания классов. Вкратце, что для чего…

  • TmbsTimer – таймер, который “слушает” систему на предмет текущего окна, хэндл которого и хранит в свойстве fgw.
  • TmbsTableInfo – информация о таблице, содержит название таблицы и список полей.
  • TmbsTableList – список таблиц. Кроме обычных для списка методов содержит метод ImportXML.
  • TmbsFieldInfo- информация о поле
  • TmbsFieldList- список полей
  • TmbsCustomButton- базовый класс, реализующий кнопку, которая вставляет текст в активное окно (то самое, хэндл которого хранит таймер).
  • TmbsTblButton – кнопка, вставляющая информацию о таблице.
  • TmbsFieldButton – кнопка, вставляющая информацию о поле.
  • TmbsFieldCheckBox- чекбокс, для выбора полей, обрабатываемых в выражении.

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

Что дальше?

Естественно, самым логичным шагом было бы обеспечить прямой импорт структуры непосредственно из БД. Что я и планирую сделать используя FireDAC.

Кроме того, работа над эргономикой. Например, фильтр таблиц, “горячие клавиши” и т.д.

А можно посмотреть?

Все что сделано в рамках данного проекта, я делал для себя. Пока я не имею представления о дальнейшем его развитии. Возможно, это будет полностью бесплатное приложение, возможно коммерческое, а возможно очередной “мёртвый проект”. Я не спешу выкладывать его в открытый доступ, но обещаю, что все читатели моего блога при желании смогут получить программу бесплатно. Те, кому не терпится посмотреть как это работает могут написать сюда и получить ссылку на приложение в том виде, в котором оно есть.

Одной из отличительных особенностей современных IDE является набор инструментов, делающих разработку комфортной. И Delphi здесь не исключение. От версии к версии эта среда разработки “обрастает” новыми полезными инструментами, что не может не радовать. Скажу честно, когда мне приходится запускать Delphi 7 для того, что бы посмотреть какой-нибудь старый проект, я уже испытываю чувство дискомфорта. Многих полезных вещей там попросту не хватает. В последних же версиях Delphi стало появляться столько всего полезного, что некоторые инструменты попросту остались незамеченными. В частности, лично я пропустил появление в комплекте Delphi мощной утилиты для сравнения текста – Beyond Compare. Она не особо афишировалась, и

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

Beyond Compare Lite включен в состав RAD Studio, начиная с версии XE (собственно, утилита доступна и тем, кто покупает Delphi или C++ Builder отдельно). Вызывается она из IDE (Edit | Compare) или путем запуска исполняемого файла BCompareLite.exe, размещенного в каталоге Bin. Лично я вывел иконку  Beyond Compare Lite на рабочий стол и зачастую использую отдельно, не запуская IDE.

Читать далее

Недавно нашел в просторах Рунета (не скажу, что совсем случайно) интересную программу. FireMonkey Style Editor – название говорит за себя. Программа предназначена для создания и редактирования FireMonkey стилей.

Работа с редактором довольно проста. Собственно, ничего сложного, загружаем существующий FireMonkey стиль и редактируем любой из компонентов, используя инспектор объектов, позволяющий менять свойства любого из элементов стилей. Все практически так же как и в естественной среде Delphi.

Список возможностей редактора (взято с сайта программы):

  • быстрый выбор нужного элемента стиля;
  • быстрый доступ к свойствам стиля через инспектор свойств;
  • фильтрация по стилю;
  • копирование, вставка, удаление элементов стиля;
  • добавление отдельных элементов из другого стиля;
  • предпросмотр готового стиля;
  • перетаскивание элементов в структуре стиля;
  • так же есть улучшенные диалоги (TBrush, TColor, TGradient, TPath, TImage);
  • поддержка стилей FireMonkey XE2, FireMonkey2.0 XE3.

И хотя в настоящий момент на сайте автора доступна лишь бета версия продукта, и еще имеются некоторые проблемы, с помощью FireMonkey Style Editor уже сейчас вполне можно создавать оригинальные стили.

Остается пожелать автору успешного развития его продукта.

Если вы хотите узнать больше о стилях в FireMonkey, рекомендую посмотреть запись вебинара “Стили FireMonkey с Евгением Крюковым”(в настоящее время ссылка не доступна).

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