Логин: Пароль:    Регистрация Всеми возможностями сайта можно пользоваться
только после авторизации.
   Забыли пароль?

Поиск
L



Статистика
u
Пользователи онлайн: нет
Гостей онлайн: 9
Всего онлайн: 9
Зарегистрировано юзеров: 7432
Комментариев на сайте: 665
Новый юзер: puskkk



Последние комментарии
c
Ginaneula прокомментировал "Урок 3 - Конструкция IF...THEN...ELSE":
[img]https://kapsuly-lipocarnit.ru/files/lipocarnit_1/img/product-head1.png[/img] [url=https://kapsuly-lipocarnit.ru/][img]https://karga.info/wp-content/uploads/2019/02/orig.jpg[/img][/url] Купить Липокарнит в Могилёве (Беларусь) через интернет-аптеку Функции Производитель: ООО "КоролевФарм" Форма выпуска: капсул Упаковка: полимер Объем: 72 г Срок действия: 2 года Доставка: почтой, курьером Оплата : наличными, карта Фотографии продукции Чтобы заказать Липокарнит, оставьте свои контактные данные в форме ниже, и мы свяжемся с вами как можно скорее. [url=https://kapsuly-lipocarnit.ru/]lipocarnit отзывы реальные[/url] - Мы обещаем полную анонимность. Ваши данные не будут переданы 3 людям. Внимание: внимательно проверьте введенный номер и не забудьте включить телефон, чтобы наш оператор мог с вами связаться. Левокарнитин для похудения Городская суета стимулирует постоянный стресс. Большинство людей не справляются с ними, они начинают компенсировать отвратительное настроение избытком соленой и высококалорийной пищи, что приводит к увеличению веса. Ожирение является предпосылкой других приобретенных заболеваний, таких как диабет, гипертония, склероз сосудистого русла, болезни сердца. Чтобы сохранить здоровье на долгие годы, вы должны иметь нормальный вес. Для этого есть комплекс Липокарнит. Что это за продукт Липокарнит - фармацевтический продукт, созданный российскими и швейцарскими учеными специально для лечения ожирения у пациентов с избыточным весом. Преимуществом продукта является стопроцентная натуральная композиция растительного происхождения, которая не подвергает организм чрезмерным нагрузкам при метаболизме его компонентов. Биологически активная добавка к пище доступна в форме капсул от производителя. Обмана нет Перед выпуском лечебного средства для продажи производитель выполнил медицинские тесты. Была взята контрольная группа клиентов, которые худели с помощью ежедневных физических нагрузок, правильного питания, различных органических добавок. Исследуемая группа не изменила привычного распорядка дня и образа жизни. Он просто воспринимал продукт Липокарнит. Динамика снижения веса один раз в день регистрировалась в дневнике. Данные контрольной группы были значительно ниже, чем в исследовании. Испытания и противопоказания для введения фармацевтического продукта По крайней мере, некоторые продукты имеют свои собственные ограничения на потребление. Пищевая добавка Липокарнит характеризуется небольшим перечнем противопоказаний. Отзывы Противопоказания Любая степень ожирения беременность; лактация; отвратительная переносимость фармацевтического продукта; аллергическая реакция на активные или вспомогательные компоненты препарата; Дефицит лактазы. Медицинские исследования не выявили побочных эффектов при введении биодобавки. Влияние [url=https://kapsuly-lipocarnit.ru/]липокарнит купить в могилеве[/url]а на организм Продукт положительно влияет на работу всех органов и систем пациента. Нормализует работу печени, восстанавливает ее клетки. Помогает очистить кишечный тракт, средство удаления накопившихся токсических веществ. Оказывает разрушительное действие на атеросклеротические бляшки артерий, что увеличивает их внутренний просвет. Благодаря этому эффекту улучшается питание органов и тканей, снижается риск инфаркта миокарда и инфаркта миокарда. Липокарнит снижает уровень холестерина и уровень сахара в крови. Биокомплекс повышает активность клеток мозговой ткани, ускоряет проведение нервных импульсов, улучшает память и общее самочувствие. Биоактивная добавка ускоряет клеточный метаболизм за счет истончения подкожного жира. В дополнение к этим эффектам липокарнит способен нормализовать гормональный фон организма человека. Препарат устраняет нарушение функции щитовидной железы. Многие женщины с историей гипотиреоза заметили улучшение своего общего состояния, укрепление ногтей, волос, нормализацию менструального цикла и отсутствие ночного пота при приеме Липокарнита. Состав и характеристика фармацевтического препарата Биокомплекс содержит три активных элемента. К ним относятся: липоевая кислота; L-корнитин; пиколинат хрома Основные эффекты биологических компонентов активной добавки компоненты Воздействие на организм ускоряет обмен веществ в клетках; подавляет всасывание обычных углеводов; разрушает жировые клетки, направляет энергию, выделяемую для восстановления силы тела; оказывает омолаживающее действие на кожу. облагораживает познавательные способности человека; стимулирует физическую активность пациента; снимает синдром приобретенной усталости; Способ введения энергии от расщепления жиров в конструкцию молекул белкового соединения ускоряет рост мышц. удаляет токсичные соединения, свободные радикалы, способ их абсорбции в кишечнике; снижает уровень сахара в крови; восстанавливает клетки мышечной и костной ткани. В совокупности эти три вещества выполняют регенеративную функцию для всех тканей организма. Примечание о введении биоактивных добавок Фармацевтический препарат следует употреблять потребителям с ожирением и избыточным весом по 1-2 капсулы 2 раза в день во время еды утром и вечером, запивая большим количеством воды. Вступительный курс составляет 1 месяц. Если результат не был достигнут, потребление Lipocarnitum может быть продолжено после 2-месячного перерыва. Перед введением препарата проконсультируйтесь с врачом. Не принимайте биологический комплекс самостоятельно. Где я могу найти Липокарнит Товар эксклюзивный, аналогов не имеет. В аптеке пт нет. Липокарнит можно приобрести только на нашем официальном сайте. Сейчас идет акция: фармацевтический продукт можно получить со скидкой 50% для всех посетителей. Рекламная продукция ограничена (осталось 60 упаковок). Поставщик имеет все необходимые лицензии и сертификаты для внедрения продукта. Посетите сайт производителя, закажите отличный продукт для похудения. Чтобы не покупать поддельный фармацевтический продукт, не покупайте биокомплекс в магазинах и других местах. Каждый пакет имеет свой уникальный код безопасности. Он может быть размещен на сайте производителя для проверки подлинности лечебного средства. Сколько стоит диетический продукт Общая стоимость липокарнита - 1980 руб. Цена лечебного средства со скидкой 50% составляет 990 рублей. Количество товара ограничено. Возьми комплекс по хорошей цене, сожги лишние килограммы, наслаждайся своей безупречной фигурой. Мы стараемся сделать все, чтобы вы не спали и были красивыми.
AshleyDuh прокомментировал "Урок 3 - Конструкция IF...THEN...ELSE":
[img]https://kapsuly-lipocarnit.ru/files/lipocarnit_1/img/product-head1.png[/img] [url=https://kapsuly-lipocarnit.ru/][img]https://karga.info/wp-content/uploads/2019/02/orig.jpg[/img][/url] Липокарнит в Казани Аптека 24 г. [url=https://kapsuly-lipocarnit.ru/]липокарнит для похудения[/url] - Казань, ул. Энергетиков, 3, 7 (843) 205–57–99 Таттехмедфарм г. Казань, ул. Охранники, 31/42, 7 (843) 222–00–03 Сакура, аптека № 1 г. Казань, ул. Адоратского, 1а, 7 (843) 527–61–72 Приусадебный участок г. Казань, ул. Ричард Зорге, 57, 7 (843) 204–05–60 Вита Казань, ул. Декабристы, 131, 7 (843) 239–15–20 Аккуратная аптека Казань, Сибирский тракт, 22, 7 (843) 279–50–35 Последняя покупка: просто Сейчас 99 человек смотрят этот продукт Последняя покупка: просто Сейчас 99 человек смотрят этот продукт Приготовление натуральных ингредиентов Это не лекарство и пищевая добавка Доставка : от 99 руб. укажите оператор Платеж : наличные / карта при получении Липокарнит - правильный курс для естественной потери веса до 10 кг на курс Для 90% людей с великолепными формами похудение сравнимо с изощренными пытками инквизиции. Отказ от любимых блюд, строгий контроль аппетита, ежедневные изнурительные нагрузки и постоянное нервное напряжение до следующего взвешивания. До недавнего времени через него проходили все, кто осмелился избавиться от лишнего веса в виде жира на боку, животе, бедрах и других частях тела. Но такие методы помогают только 40% людей с избыточным весом, потому что очень часто причиной его набора является не недостаточная активность или переедание, а замедление метаболических процессов. Чтобы стать победителем в борьбе за гармонию, диетологи рекомендуют покупать Липокарнит - в Казани нет других средств для похудения, которые могут деликатно и безопасно разгонять обменные процессы и сжигать жировые отложения без потери здоровья. Что такое Липокарнит, состав продукта Препарат Липокарнит - это 100% органический продукт, состоящий из активных аминокислот, способствующих расщеплению жировых клеток. Выпускается в виде желатиновых капсул, внутри которых находится белый порошок. Их удобно принимать, а активные вещества всасываются в кишечнике, отвечают за всасывание органических аминокислот. Благодаря этому активные ингредиенты полностью усваиваются. В состав препарата входит: Липоевая кислота - это органическое вещество, участвующее в переработке глюкозы и других сахаров. При ее участии утилизируются метаболиты, потенциально опасные для клеток печени, а жировые ткани превращаются в энергию и воду.Липоевая кислота показана для использования профессиональными спортсменами для улучшения метаболических процессов и поддержания физической формы. Пиколинат хрома - органическое производное триптофана, способствует образованию мышечной массы и расщеплению жира. Полезным свойством соединения при похудении является ослабление аппетита. [img]https://kapsuly-lipocarnit.ru/files/lipocarnit_1/img/review-3.jpg[/img] L-карнитин - это органическая аминокислота, которая превращает жировую ткань в энергию и воду. Дополнительным полезным свойством этого вещества является снижение уровня холестерина в крови. Аминокислота подавляет всасывание жиров в кишечнике. Средство оказывает комплексное воздействие на организм: помогает уменьшить количество жира в организме и предотвращает его повторное накопление. Как работает [url=https://kapsuly-lipocarnit.ru/]липокарнит в аптеках казани[/url] Действие препарата сильно отличается от других препаратов для похудения. Препарат не создает чувства сытости, не изменяет процесс пищеварения, но в то же время помогает избавиться от жировых отложений. Это стало возможным благодаря уникальной способности Lipocarnitum перепрограммировать обмен энергии и обмен веществ в организме. Активные вещества сами по себе не влияют на жировые клетки. Они заставляют организм активизировать свои собственные ресурсы. Результат: разрушение мембран жировых клеток; Расщепление жира - энергия и вода высвобождаются; Энергия, получаемая от сжигания жира, направляется в жизненно важные органы. Эта короткая схема содержит естественный процесс, представленный природой, но по какой-то причине нарушенный. Возвращение в состояние, естественное для здорового организма, не проходит бесследно. На фоне снижения веса нормализуются артериальное давление, уровень глюкозы в крови и холестерина. Общее состояние организма улучшается, энергия увеличивается. При использовании Липокарнита нет необходимости менять привычки питания. Тренировки в тренажерном зале также необязательны. После недели приема препарата прилив энергии будет таким, что сам организм потребует повышенной активности. С курсом приема препарат не вызывает привыкания. Тело, настроившись на режим, необходимый для похудения, продолжает бороться с лишним весом самостоятельно. Эффект длится 60 дней. Как взять Несмотря на то, что Липокарнит не продается в аптеке в Казани, применение препарата следует проводить строго по инструкции. Нарушение описанных в нем правил потенциально опасно для здоровья. Липокарнит на завтрак и ужин принимайте по 1 или 2 капсуле в зависимости от исходного веса. Курс похудения длится 30 дней. За это время наблюдается потеря веса не менее 2 кг (при небольшом лишнем весе). У тучных людей с высокой степенью ожирения потеря веса достигает до 20 кг в месяц. При необходимости дальнейшего похудения курс повторяют через 60 дней, когда предыдущий теряет силу. Побочные эффекты и противопоказания При использовании в соответствии с инструкцией побочные эффекты после приема Липокарнита не возникают. Ему также не хватает серьезных противопоказаний. Препарат подходит для похудения у диабетиков и тех, кто испытал гормональные изменения. Единственная категория людей, которым противопоказано применение препарата - это беременные и кормящие женщины. В редких случаях после применения капсул индивидуальные реакции непереносимости возникают в виде: дискомфорт в кишечнике; сыпь на коже; n; [img]https://kapsuly-lipocarnit.ru/files/lipocarnit_1/img/review-2.jpg[/img] заложенность носа. При появлении симптоматических препаратов, назначенных лечащим врачом, это поможет. Купить Липокарнит Не рекомендуется приобретать капсулы для похудения данной марки в магазинах товаров для здоровья. Производитель не поставляет препарат в розничные сети. Вы можете заказать его только у официальных представителей в интернете.Это позволило гарантировать, что цена на Липокарнит в Казани соответствует заявленной производителем, поскольку нет торговых наценок. Кроме того, при покупке у дистрибьюторов, к которым относится Аптека-5, предоставляется 100% гарантия качества и подлинности товара. В Аптеке-5 вы можете заказать Липокарнит со скидкой, пока действует акция. Постоянным клиентам предоставляются дополнительные бонусы. Вы можете совершить покупку через корзину без регистрации или заказав обратный звонок менеджера. Инструкция по применению Прием препарата Липокарнит рекомендуется в течение 30 дней. Пить по 1 или 2 капсулы в день на завтрак и ужин. При необходимости курс повторяют через 2 месяца после окончания предыдущего.

Применение фреймов для написания правильных приложений

Не знаю как вы, а я в свое время часто встречался со следующей ситуацией. При разработке довольно больших проектов количество форм с временем разрасталось. И чем далее, тем хуже. Но даже это не было большой проблемой до тех пор, пока я работал сам – все таки себя можно самодисциплинировать – заставить использовать единообразные наименования форм, методов, переменных. Но после того, как я стал работать в команде, проблема стала во весь рост – рефакторинг зачастую стал сводиться к “переписать все”, так как у каждого программиста свое понимание “правильно написаного кода”.После некоторых раздумий я решил создать некий “движок”, который облегчит написания немаленьких проектов. В основу этого движка я поставил такие принципы:
1. Все без исключения объекты для работы с базами данных должны находится в модулях данных, причем количество объектов в базе данных не должно превышать некий критический предел (для меня – до 50 объектов) – дальше стает сложно ориентироваться;
2. Все операции по работе с данными з БД должны также описываться в модулях данных, в соответствующих событиях или ActionList;
3. В главной форме не должно содержаться кода по работе с режимами, только вызов режима и вызов абстрактных, общих для всех методов, которые будут переопределяться в каждом соответствующем режиме.
4. Пользовательский интерфейс всех режимов должен быть полностью единообразен.
5. Режим должен иметь “право” изменения главного окна.
6. Режим не должен знать о существовании других режимов и и других форм вообще, для режима должно быть доступны только главная форма и модули данных.
7. Модули данных не должны знать о существовании режимов.
8. Режимы должны создаваться динамически, дабы не занимать лишнюю память.

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

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

Потому было решено отойти от “тяжелого наследия” :) процедурного программирования и использовать основные принципы ООП.

И действительно, оказалось что все фреймы можно (более того, нужно) сделать наследниками некоего базового фрейма. Код базового фрейма приведен ниже.

unit UnitFrameBase;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  shellapi, DB, DBGrids, UnitConstTypes_etc;

type
  TFrameBase = class(TFrame)
  private
    {описание фрейма - для вывода в заголовке программы}
    FrameDescription: string;
    {основной источник данных}
    FrameCurrentDataSet: TDataSet;
    {флаг загрузки данных}
    LoadingData: Boolean;
    {флаг выполнения длительной работы - например генерации очень большого отчёта}
    MakeLongTimeWork: Boolean;
  public
    { функция, выполняющаяся сразу после создания фрейма}
    procedure InitialisationFrame(Param1, Param2: Integer); virtual;
    { виртуальная функция фильтра данных }
    procedure Filter(Param1, Param2: Integer); virtual;
    { виртуальная функция показа дополнительной информации}
    procedure ShowAdditionalInformation(); virtual;
    { виртуальная функция скрытия/показа наследуемых контролов}
    procedure ShowContols(); virtual;
    { виртуальная функция открытия наборов данных (подключения к уже открытым}
    procedure OpenNeededTables(Param1, Param2: Integer); virtual;
    {процедуры работы с наборами данных}
    {добавление}
    function AddRecord(): TFunctionResult; virtual;
    {редактирование}
    function EditRecord(): TFunctionResult; virtual;
    {удаление}
    function DeleteRecord(): TFunctionResult; virtual;
    {Сохранить}
    function PostRecord(): TFunctionResult; virtual;
    {Отменить}
    function CancelRecord(): TFunctionResult; virtual;
    {Открыть свойства}
    function GetProperty(): boolean; virtual;
    {функции экспорта в различные форматы}
    function ExportData(Parameter: string): TFunctionResult; virtual;
    {функции импорта из различных форматов}
    function ImportData(Parameter: string): TFunctionResult; virtual;
    {Комментарий: функции записи/чтения заголовка фрейма}
    function GetDesc: string;
    procedure SetDesc(Description: string);
    {Процедуры перехода к следующей, предыдущей, первой, последней записи}
    procedure GotoNextElement; virtual;
    procedure GotoPrevElement; virtual;
    procedure GotoFirstElement; virtual;
    procedure GotoLastElement; virtual;
    {функция, возвращающая главный Grid фрейма}
    function GetMainGrid: TDBGrid;virtual;
   {функции установки состояния загрузки данных}
    procedure SetLoadingData(LD: boolean);
    function GetLoadingData: boolean;
   {функции установки состояния длительного процесса}
    procedure SetMakeLongTimeWork (LTW: boolean);
    function GetMakeLongTimeWork : boolean;
    {функции возвращающие текущий источник данных}
    procedure SetFrameCurrentDataSet(DS: TDataSet);
    function GetFrameCurrentDataSet: TDataSet;
    {виртуальный деструктор}
    destructor Destroy;override;
    {процедуры записи/чтения настроек фрейма в файлы}
    {эти процедуры не вызываются автоматически в конструкторах/деструкторах}
    {вызов этих функций лучше покласть на процедуру вывода фрейма}
    function SaveFrameToFile(FileName: TFileName): TFunctionResult; virtual;
    function LoadFromFileToFrame(FileName: TFileName): TFunctionResult; virtual;
  published
    {описание фрейма – для отображения режима в заголовке}
    property FrameDesc: string read GetDesc write SetDesc;
  end;

implementation

uses UnitFormMain, MyDBGrid;

{$R *.dfm}

procedure TFrameBase.ShowAdditionalInformation();
begin
//---в принципе часто нужно что-то помещать в статусбар
end;


procedure TFrameBase.Filter(Param1, Param2: Integer);
begin
//---фильтрация текущего набора данных
//---два параметра передаются через SendMessage
end;

procedure TFrameBase.ShowContols();
begin
//---чтобы скрывать/отображать нужные в текущем режиме контролы
end;

procedure TFrameBase.OpenNeededTables(Param1, Param2: Integer);
begin
// по умолчанию откроем текущий датасет фрейма
 if Assigned(FrameCurrentDataSet) then
  FrameCurrentDataSet.Active := true;
end;

procedure TFrameBase.InitialisationFrame(Param1, Param2: Integer);
begin
//-------------
  SetLoadingData(true);
//откроем нужные таблицы
  OpenNeededTables(Param1, Param2);
//отфильтруем их
  Filter(Param1, Param2);
//покажем нужные контролы
  ShowContols;
  SetLoadingData(false);
end;

{процедуры работы с наборами данных}

{добавление}
function TFrameBase.AddRecord(): TFunctionResult;
var
 E: Exception;
begin
//попытаемся добавить запись в текущий датасет фрейма
 Result.Successful := false;
 if Assigned(FrameCurrentDataSet) then
  begin
  try
  FrameCurrentDataSet.Append;
  Result.Successful := true;
  except on E:Exception do
    Result.MessageOnError := E.Message;
  end;
  end;
end;

{редактирование}
function TFrameBase.EditRecord(): TFunctionResult;
var
 E: Exception;
begin
//попытаемся изменить запись в текущем датасете фрейма
 Result.Successful := false;
 if Assigned(FrameCurrentDataSet)then
  begin
  try
  FrameCurrentDataSet.Edit;
  Result.Successful := true;
  except on E:Exception do
    Result.MessageOnError := E.Message;
  end;
  end;
end;

{удаление}
function TFrameBase.DeleteRecord(): TFunctionResult;
var
 E: Exception;
begin
//попытаемся удалить запись из текущего датасета фрейма
 Result.Successful := false;
 if Assigned(FrameCurrentDataSet) then
  begin
  try
  FrameCurrentDataSet.Delete;
  Result.Successful := true;
  except on E:Exception do
    Result.MessageOnError := E.Message;
  end;
  end;
end;


{Сохранить}
function TFrameBase.PostRecord(): TFunctionResult;
var
 E: Exception;
begin
//попытаемся послать Post
 Result.Successful := false;
 if Assigned(FrameCurrentDataSet) then
  begin
  try
  FrameCurrentDataSet.Post;
  Result.Successful := true;
  except on E:Exception do
    Result.MessageOnError := E.Message;
  end;
  end;
end;


{Отменить}
function TFrameBase.CancelRecord(): TFunctionResult;
var
 E: Exception;
begin
//попытаемся послать Cancel
 Result.Successful := false;
 if Assigned(FrameCurrentDataSet) then
  begin
  try
  FrameCurrentDataSet.Cancel;
  Result.Successful := true;
  except on E:Exception do
    Result.MessageOnError := E.Message;
  end;
  end;
end;


{Открыть свойства}
function TFrameBase.GetProperty(): boolean;
begin
  Result := false;
   if Assigned(FrameCurrentDataSet) then
     if not FrameCurrentDataSet.IsEmpty then
      Result := true;
end;

{функции экспорта в различные форматы}
function TFrameBase.ExportData(Parameter: string): TFunctionResult;
var
 FResult: TFunctionResult;
begin
  Result.Successful := False;
  Result.MessageOnError := 'Not Save';
//если передан параметр AsIs
//то сохранить текущий грид в xls
  if (Parameter = 'AsIs') then
  begin
    with TSaveDialog.Create(Self) do
    try
      begin
        Filter := 'Файли гіпертексту|*.htm';
        Title := 'Вкажіть назву файлу';
        DefaultExt := 'htm';
        Options := Options + [ofPathMustExist];
        if Execute then
        begin
          FResult := TMyDBGrid(GetMainGrid).SaveToHTML(FileName, false);
          Result := FResult;
          ShellExecute(Self.Handle, 'open', PChar(FileName), nil, nil, SW_SHOW);
        end
      end;
    finally
      Free;
    end;
  end;
end;

function TFrameBase.ImportData(Parameter: string): TFunctionResult;
begin
  Result.Successful := False;
  Result.MessageOnError := 'Not implemented method';
end;

{Комментарий: функции записи/чтения заголовка фрейма}
function TFrameBase.GetDesc: string;
begin
  Result := FrameDescription
end;

procedure TFrameBase.SetDesc(Description: string);
begin
  FrameDescription := Description
end;

procedure TFrameBase.GotoNextElement;
begin
   if Assigned(FrameCurrentDataSet) then
    if not FrameCurrentDataSet.Eof then
     FrameCurrentDataSet.Next;
end;

procedure TFrameBase.GotoPrevElement;
begin
   if Assigned(FrameCurrentDataSet) then
    if not FrameCurrentDataSet.Bof then
     FrameCurrentDataSet.Prior;
end;

procedure TFrameBase.GotoFirstElement;
begin
   if Assigned(FrameCurrentDataSet) then
    if not FrameCurrentDataSet.Bof then
     FrameCurrentDataSet.First;
end;

procedure TFrameBase.GotoLastElement;
begin
   if Assigned(FrameCurrentDataSet) then
    if not FrameCurrentDataSet.Eof then
     FrameCurrentDataSet.Last;
end;


procedure TFrameBase.SetLoadingData(LD: boolean);
begin
  LoadingData := LD;
end;

function TFrameBase.GetLoadingData: boolean;
begin
  Result := LoadingData;
end;

function TFrameBase.GetMainGrid: TDBGrid;
begin
 Result := nil;
end;

procedure TFrameBase.SetMakeLongTimeWork (LTW: boolean);
begin
  MakeLongTimeWork := LTW;
end;

function TFrameBase.GetMakeLongTimeWork : boolean;
begin
  Result := MakeLongTimeWork;
end;

{функции возвращающие текущий источник данных}
procedure TFrameBase.SetFrameCurrentDataSet(DS: TDataSet);
begin
  FrameCurrentDataSet := DS;
end;

function TFrameBase.GetFrameCurrentDataSet: TDataSet;
begin
  Result := FrameCurrentDataSet;
end;


destructor TFrameBase.Destroy;
begin
  if Assigned(FrameCurrentDataSet) then
   FrameCurrentDataSet.Active := false;
  inherited Destroy;
end;

{процедуры записи/чтения настроек фрейма в файлы}
function TFrameBase.SaveFrameToFile(FileName: TFileName): TFunctionResult;
var
  E: Exception;
  ms: TMemoryStream;
  fs: TFileStream;
begin
  try
  fs := TFileStream.Create(FileName, fmCreate or fmOpenWrite);
  ms := TMemoryStream.Create;
  try
    ms.WriteComponent(self);
    ms.Seek(0, soFromBeginning);
    ObjectBinaryToText(ms, fs);
  finally
    ms.Free;
    fs.free;
  end;
  Result.Successful := true;
  Except on E:Exception do
   begin
    Result.Successful := false;
    Result.MessageOnError := E.Message;
   end;
  end;
end;

function TFrameBase.LoadFromFileToFrame(FileName: TFileName): TFunctionResult;
var
 ComponentIdx: integer;
  ms: TMemoryStream;
  fs: TFileStream;
begin
//уничтожим все существующие на фрейме компоненты
//чтобы не было конфликтов
 for ComponentIdx := self.ComponentCount-1 downto 0 do
  self.Components[ComponentIdx].Free;
 try
//загрузим фрейм из файла
  ms := TMemoryStream.Create;
  fs := TFileStream.Create(FileName, fmOpenRead);
  try
    ObjectTextToBinary(fs, ms);
    ms.Seek(0, soFromBeginning);
    ms.ReadComponent(self);
  finally
    ms.Free;
    fs.free;
  end;
  Result.Successful := true;
 except on E:Exception do
  begin
   Result.Successful := false;
   Result.MessageOnError := E.Message;
  end;
 end;
end;
end.
Как можно заметить, многие функции базового фрейма возвращают значение типа TFunctionResult. Эта структура определена в модуле UnitConstTypes_etc, в который в будущем будут добавляться другие типы, константы. Функции возвращают флаг успешного завершения операции, а случае возникновения ошибки – текст сообщения об ошибке.

Это, понятно, шаблон. В моих нынешних приложениях вышеозначенных функций более чем достаточно. Однако, если вам нужно добавить какой-то специфический метод, в этом понятно не никакой сложности.

Кроме того, в процедуре экспорта данных вызывается метод SaveToHTML текущего грида фрейма. Этот метод определён в модуле MyDBGrid.

Перейдем к отображению фреймов на главной форме приложения.

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

Сначала создадим свой тип
 
type
  TFrameClass = class of TFrameBase;
  Теперь нужно создать правильно работающую главную форму. В uses добавим использование модуля UnitFrameBase, в раздел public внесем объект MainFrame класса TFrameBase. Теперь нужно написать функцию, которая будет корректно отображать нужный фрейм при открытии нужного режима.

function TFormMain.ProcShowFrame(FrameClassName: AnsiString; ParentPanel: TWinControl): TFunctionResult;
var
  FrameClass: TClass;
  FunctionResult: TFunctionResult;
  E: Exception;
begin
  Result.Successful := False;
  FrameClass := GetClass(FrameClassName);
  if FrameClass = nil then //если такой тип фрейма незарегистрирован
   begin
    Result.MessageOnError := Format('Class %s not registered',[FrameClassName]);
    Exit;
   end;
  //запретить прорисовку контейнера фреймов
  try
    begin
      LockWindowUpdate(ParentPanel.Handle); // не будем перерисовывать подложку, чтобы не было мерцаний
  //если фрейм не пуст, очистим его
      if Assigned(MainFrame) then
        if MainFrame.ClassType = FrameClass then
        begin
          Result.Successful := true;
          Exit; //если мы пытамся пересоздать текущий фрейм ним же, то выход
        end
        else
          begin
           FunctionResult := MainFrame.SaveFrameToFile(Format('%s.dat',[MainFrame.ClassName]));
           if not FunctionResult.Successful then
              ListBoxLog.Items.Add('Error on Save Frame: '+FunctionResult.MessageOnError);
           MainFrame.Destroy;
          end;
  //создать фрейм по указанному типу
      try
        MainFrame := TFrameClass(FrameClass).Create(FormMain);
        if FileExists(Format('%s.dat',[MainFrame.ClassName])) then
         begin
        FunctionResult := MainFrame.LoadFromFileToFrame(Format('%s.dat',[MainFrame.ClassName]));
        if not FunctionResult.Successful then
         ListBoxLog.Items.Add('Error on Load Frame: '+FunctionResult.MessageOnError);
       end;
      except on E:Exception do
        begin
          Result.MessageOnError := E.Message;
          MainFrame := nil;
          Exit;
        end;
      end;
      MainFrame.Parent := ParentPanel;
      MainFrame.Align := alClient;
    end;
  finally
    LockWindowUpdate(0); //разрешить прорисовку контейнера фреймов
  end;
  Result.Successful := true;
end;
Как же вызвать данную функцию? Создадим дополнительно сообщение

const FILTER_EVENT = WM_USER + 101, – для вызова процедур фильтрации. Param1 и Param2 используются для формирования нужных запросов в однотипных фреймах. Теперь нужно написать обработчик сообщения FILTER_EVENT.
procedure TFormMain.CX_FILTER(var Msg: TMessage);
begin
  if Assigned(MainFrame) and (not FormMain.isShutdown) then
  begin
    MainFrame.Filter(Msg.wParam, Msg.LParam);
    MainFrame.ShowAdditionalInformation;
  end;
end;
Перейдем к отображению меню фреймов. В качестве источника хранения структуры древовидного меню можно использовать xml файл (это удобно, если приложение не использует БД), таблицу в используемой в приложении БД или же хранить структуру прямо в приложении (очень удобно это делать в dxTreeList от DevExpress, однако эти компоненты платные). Так как во всех моих приложениях используются базы данных (в основном СУБД Oracle или Firebird), то я выбрал второй вариант. Создадим таблицу следующей структуры
CREATE TABLE TECH_APP_MENU (
    MENU_ID       IDENTIFIER NOT NULL,
    ITEM_TYPE     VARCHAR(10) DEFAULT 'item' NOT NULL,
    ITEM_CAPTION  VARCHAR(32) NOT NULL,
    FRAME_NAME    VARCHAR(32) DEFAULT 'TFrameUnknown' NOT NULL,
    PARAM1        NONIDENTIFIER,
    PARAM2        NONIDENTIFIER,
    PARENT_ID     NONIDENTIFIER NOT NULL,
    ITEM_ICON     NONIDENTIFIER
);
Кроме того, для обеспечения целостности дерева, с таблицей связано несколько триггеров и ограничений. Полностью структуру таблицы и тексты ограничений вы можете помотреть в исходном тексте БД.

Из этой реляционной таблицы довольно легко создать дерево с помощью рекурсивной процедуры, текст которой вы также можете посмотреть в исходном тексте БД. Заметим, что принципы создания такой процедуры взяты из книги “Мир InterBase”.

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

Процедура отображения дерева приведена ниже. Сначала определим структуру элементов меню
type TMenuNodes = record
    MENU_ID: integer;
    ITEM_TYPE: WideString;
    ITEM_CAPTION:  WideString;
    FRAME_NAME:    WideString;
    PARAM1: integer;
    PARAM2: integer;
    PARENT_ID: integer;
    LEVEL: integer;
    ISLEAF: boolean;
    ParentNode: TTreeNode;
   end;
PTMenuNodes = ^TMenuNodes;
Естественно, что структура элемента меню совпадает со структурой таблицы в БД. Создадим меню следующей функцией
procedure TFormMain.GenerateMenu(Tree: TTreeView);
var
  vData : PTMenuNodes;
  Node, LastNode : TTreeNode;
begin
 try
 LockWindowUpdate(Tree.Handle);
 SendMessage(Tree.Handle, TVM_DELETEITEM, 0, Longint(TVI_ROOT)); //очистим дерево
 if not DataModuleMain.DBMain.Connected then
  Exit; 
 with DataModuleMain.GET_MENU do
  begin
   LastNode := nil;
   Active := True;
   First;
   while not Eof do
    begin
     New(vData);
      with vData^ do
       begin
     MENU_ID := FieldByName('MEM_ID').AsInteger;
     ITEM_TYPE := FieldByName('ITEM_TYPE').AsString;
     ITEM_CAPTION := FieldByName('ITEM_CAPTION').AsString;
     FRAME_NAME := FieldByName('FRAME_NAME').AsString;
     PARAM1 := FieldByName('PARAM1').AsInteger;
     PARAM2 := FieldByName('PARAM2').AsInteger;
     PARENT_ID := FieldByName('MEM_PID').AsInteger;
     LEVEL := FieldByName('OUTLEVEL').AsInteger;
     ISLEAF := boolean(FieldByName('IS_LEAF').AsInteger);
      end;
     if vData.LEVEL = 1 then
      begin
     Node := TreeViewMenu.Items.Add(nil,vData^.ITEM_CAPTION);
     vData.ParentNode := nil;
      end
       else if PTMenuNodes(LastNode.Data)^.LEVEL<vData.LEVEL then
      begin
     Node := TreeViewMenu.Items.AddChild(LastNode,vData^.ITEM_CAPTION);
     vData.ParentNode := LastNode;
      end
       else if PTMenuNodes(LastNode.Data)^.LEVEL=vData.LEVEL then
      begin
     Node := TreeViewMenu.Items.AddChild(LastNode.Parent,vData^.ITEM_CAPTION);
     vData.ParentNode := LastNode.Parent;
      end
       else if PTMenuNodes(LastNode.Data)^.LEVEL>vData.LEVEL then
      begin
     while PTMenuNodes(LastNode.Data)^.LEVEL>=vData.LEVEL do
      LastNode := LastNode.Parent;
     Node := TreeViewMenu.Items.AddChild(LastNode,vData^.ITEM_CAPTION);
     vData.ParentNode := LastNode.Parent;
      end;
{здесь компилятор выдает сообщение, что Node может быть неинициализированной.
 Однако при используемой в программе схеме хранения данных
 данная переменная обязательно будет инициализирована}
     Node.Data := vData;
     Node.ImageIndex := FieldByName('ITEM_ICON').AsInteger;
     Node.SelectedIndex := FieldByName('ITEM_ICON').AsInteger;
     LastNode := Node;
     Next;
    end;
  end;
  finally
   LockWindowUpdate(0);
  end;
end;
Обработчик изменения элемента в меню будет иметь следующий вид
procedure TFormMain.TreeViewMenuChange(Sender: TObject; Node: TTreeNode);
var
  vData : PTMenuNodes;
  CurrentNodeIcon: TIcon;
  FunctionResult: TFunctionResult;
begin
 vData := Node.Data;
 FunctionResult := ProcShowFrame(vData^.FRAME_NAME,PanelFrame);
 if FunctionResult.Successful then
   begin
  MainFrame.InitialisationFrame(vData^.PARAM1,vData^.PARAM2);
  Caption := Format('%s - %s',[Application.Title,MainFrame.FrameDesc]);
  CurrentNodeIcon := TIcon.Create;
  ImageListApp.GetIcon(Node.SelectedIndex,CurrentNodeIcon);
  FormMain.Icon := CurrentNodeIcon;
  CurrentNodeIcon.Free;
   end
   else
    ListBoxLog.Items.Add(Format('Error on show frame %s: %s',[vData^.FRAME_NAME,FunctionResult.MessageOnError]));
end;
Создадим панель инструментов с кнопками, которые будут выполнять нужные функции. Как мы определили, обязательно нужны функции добавления, изменения, удаления, просмотра, экспорта в Excel и других отчетов, импорта из внешних источников. Код обработчиков нажатия на эти кнопки будет максимально прост. Например код для добавления
procedure TFormMain.ToolButtonAddClick(Sender: TObject);
var
 FResult: TFunctionResult;
begin
 if Assigned(MainFrame) then
  begin
  FResult := MainFrame.AddRecord;
  if not FResult.Successful then
   ListBoxLog.Items.Add('Error on Add: '+FResult.MessageOnError);
  end;
end;
Аналогично и для других. Кроме того, в главной форме нужно еще создать общие элементы для фильтрации. Это могут быть элементы для фильтрации по датам, по рассчетным счетам и т.д. Однако в обработчике изменения по этим элементам нужно всего-лишь послать сообщение CX_FILTER. Как обработать полученное сообщение, будет решать конкретный фрейм.

Кроме вышеперчисленного, в главной форме нужно будет зарегистрировать все типы фреймов. Делается это в секции initialization функцией RegisterClasses.

Теперь нужно создать фреймы. Фрейм должен наследоваться от созданного выше абстрактного фрейма TFrameBase. После этого нужно переопределить необходимые режимы.

В простейшем случае нужно переопределить конструктор фрейма, к котором переопределить описание фрейма, вызвав SetDesc и определить текущий датасет фрейма, вызвав SetFrameCurrentDataSet. Если на фрейме есть грид, то нужно переопределить функцию GetMainGrid, чтобы она возвращала нужный.

Таким образом для добавления нового режима в простейшем случае нужно прописать всего 9 строчек кода!

Однако его изменение (улучшение) фрейма абсолютно не приведет к никаким правкам главной формы. Функции работы с данными вызывают всего лишь методы соответствующих DataSet. В обработчике которых могут вызываться дополнительные модальные формы или диалоги.

Что дает такой подход? Написав каркас приложения в самом начале разработки проекта, далее все изменения (при появлении новых требований) сводится к включению нового фрейма (унаследованного от базового фрейма), добавлении записи в таблице меню (можно, кстати, создать визуальный редактор этой таблицы) и регистрации типа в в процедуре RegisterClasses. И все! Таким образом режимы могут разрабатываться разными разработчиками, которым не нужно согласовывать свои стили программирования (хотя, все же, это желательно) – все нужные функции определены, нужно их только переопределить и наполнить необходимым содержанием.

Вот и всё, Удачи!

iprotechno.net
Источник: www.thedelphi.ru
Автор: Савельев Александр
Опубликовано: 29 Декабря 2014
Просмотров:


Зарегистрируйтесь или авторизуйтесь, чтобы добавлять комментарии.