Показаны сообщения с ярлыком Расходы. Показать все сообщения
Показаны сообщения с ярлыком Расходы. Показать все сообщения

вторник, 6 марта 2012 г.

Урок 31. Работа с ресурсами. Создание компонентов - кнопок.



Доброго времени суток.

Чтобы продолжить создание программы "Расходы", мне понадобится пара кнопок.

Продвинутый программер Pascal/Delphi скажет, что кнопка есть на панели Standart, есть BitBtn на панели Additional, чего еще остается желать? Отвечу. Если Вы создаете одну программу, тогда можно пользоваться стандартными компонентами, наделяя их нужными свойствами. А мне по долгу службы иногда приходилось создавать по две-три формы в день, располагая на каждой по паре кнопок: "OK" и "Cancel". Ну и что, казалось бы? Но для каждой кнопки приходилось загружать рисунок, настраивать свойства привязки (якоря), убирать надпись и т.п. Ленивому как я человеку это быстро надоедает. И тогда на ум приходит идея создания собственных компонентов кнопок, свойства которых уже установлены в таком виде, в каком они чаще всего используются.


Итак, начнем.

Прежде всего, если у Вас установлена библиотека компонентов Pro Delphi Lib, деинсталлируйте ее.








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



Этот файл я назвал Set_16_16.bmp.



Второй файл я назвал Cancel_16_16.bmp







Рисунки имеют размеры 16 на 32 пикселя. Обязательно сохраните их в формате bmp. Это важно.

Фактически, можно было бы обойтись одним изображением 16 на 16, как это уже реализовано в библиотеке Pro Delphi Lib, но одним рисунком можно обходиться, если кнопки всегда доступны. Если же свойство Enabled установить в False, то на месте кнопки появится неприглядный квадратик без надписи и какого бы ни было изображения. Это не есть гуд...

Далее, при помощи блокнота создаем файл OK_Cancel_New.rc (файл OK_Cancel без New не годится, такой уже был). Обратите внимание на расширение "rc".

В этом файле пишем две строки:

OK Bitmap "Set_16_16.bmp"
CANCEL Bitmap "Cancel_16_16.bmp"

где OK и CANCEL - названия (имена, без них как обратиться к нужному?) будущих ресурсов, Bitmap - тип ресурса и далее - имена подготовленных файлов с изображениями.

Сохраните этот файл.

В папку с этим файлом и файлами рисунков скопируйте файл brcc32.exe (его можно найти в папке с делфёй ($Delphi\bin)).

Облегчим себе жизнь. Тут я и позавидую и порадуюсь одновременно за тех, кто не работал в DOS-е с командной строкой... Создадим еще один файл в той же рабочей папке с помощью того же блокнота, но, чтобы он стал исполняемым операционной системой, дадим ему расширение "bat", например: runme.bat, следующего содержания:

brcc32.exe OK_Cancel_New.rc

Эта строка запустит программу brcc32.exe, которая в качестве параметра получит ссылку на файл OK_Cancel_New.rc (еще раз подчеркиваю, что все должно быть в одной папке, чтобы не прописывать абсолютных путей и не искать потом: куда же делся результат?).

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

OK_Cancel_New.RES

Посмотреть его содержимое можно разными программами для работы с ресурсами, но увидите Вы примерно вот такую картину:



Открываем оболочкой Delphi файл PrDButtons.pas, содержащийся в библиотеке Pro Delphi Lib.




Внесем в него необходимые изменения:
вместо строки

{$R *.res}

запишем новую директиву компиллятору - ссылку на созданный нами файл ресурсов:

{$R OK_Cancel_New.RES}

Общие свойства, как вы можете видеть, задаются для компонента TPrDBUTTON в его конструкторе (от этого компонента наследуются новые кнопки TPrDOkButton = class( TPrDBUTTON ) и TPrDCancelButton = class( TPrDBUTTON ) ):



constructor TPrDBUTTON.Create( AOwner: TComponent );
begin
  inherited Create(AOwner);
  Width:=26;
  Height:=26;
  ControlStyle := ControlStyle - [ csSetCaption ];
  ShowHint:=True;
  Anchors:=[akRight]+[akBottom];  // Изменение свойств привязки к правому нижнему углу
end;





Далее - можно добавить в published разделы для кнопок свойства:



  TPrDOkButton = class( TPrDBUTTON )
  public
    constructor Create( AOwner: TComponent ); override;
  published
    property Default default True;
    property ModalResult default mrOK;
    property NumGlyphs;                             
  end;


  TPrDCancelButton = class( TPrDBUTTON )
  public
    constructor Create( AOwner: TComponent ); override;
  published
    property Cancel default True;
    property ModalResult default mrCancel;

    property NumGlyphs;                             

  end;


А в конструкторе компонентов задать значение этого свойства, равное 2, т.к. на каждую кнопку теперь полагается два рисунка:



constructor TPrDOkButton.Create( AOwner: TComponent );
begin
  inherited Create(AOwner);
  Default:= True;
  ModalResult:= mrOK;
  Hint:='Кнопка подтверждения (ОК)';
  Glyph.LoadFromResourceName(HInstance, 'OK');
  NumGlyphs:=2;                        
end;


constructor TPrDCancelButton.Create( AOwner: TComponent );
begin
  inherited Create( AOwner );
  Cancel := True;
  ModalResult := mrCancel;
  Hint:='Кнопка отмены (Cancel)';
  Glyph.LoadFromResourceName(HInstance, 'CANCEL');
  NumGlyphs:=2;                        
end;


Установите вновь библиотеку компонентов Pro Delphi Lib.


Грех - не применить модернизированные компоненты на практике. Если Вы следите за разработкой программы "Расходы", то, возможно, обратили внимание на то, что после редактирования строки нет возможности ее сохранить...


Добавьте на верхнюю панельку пару кнопок.


А дальше - по проторенной ранее дорожке: нужно добавить в список действий новую операцию:


Data_OK (внимание: свойство Caption нужно оставить пустым):


В секции частных объявлений дать декларацию новой процедуры, которую необходимо указать в обработчике onExecute новой операции:



  private
    { Private declarations }
    procedure SetPost();


Процедура SetPost выполнит следующие действия:

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


procedure TMainFrm.SetPost();
begin

  ADOTableMain.Edit;                                                // Перевод таблицы в режим редактирования
  ADOTableMain.FieldByName('MyDate').Value:=DataEdit.Value;         // Передача значений из
  ADOTableMain.FieldByName('D').Value:=DEdit.KeyValue;              // элементов управления формы
  ADOTableMain.FieldByName('K').Value:=KEdit.KeyValue;              // в поля таблицы
  ADOTableMain.FieldByName('Summa').Value:=SEdit.Value;
  ADOTableMain.FieldByName('Rem').Text:=PEdit.Text;

  Try
    ADOTableMain.Post;                                              // Попытка записи
  Except
    ADOTableMain.Cancel;                                            // Сброс в случае ошибки
    MyMessenger.TitleString:='Ошибка';                              // Сообщение оператору об ошибке
    MyMessenger.MessageString:='При попытке записать данные в базу возникла проблема.';
    MyMessenger.Buttons:=[mbOK];
    MyMessenger.ShowMessage;
  end;

  DBGridEh1.Enabled:=True;                                          // Переключение грида в режим доступности
  Panel3.Visible:=False;                                            // Скрытие верней панели

end;

Не забудьте для кнопки "OK" указать Action.

Удачи.
А.В.





среда, 24 августа 2011 г.

Урок 17. Что должна "уметь" программа "Расходы" или ТЗ на разработку



На одном из предыдущих уроков я уже затрагивал вопрос о подготовке технического задания на разработку программы.
- Но, о каком техническом задании может идти речь, если разрабатывается программа для собственного использования? - справедливо возмутятся нетерпеливые, к числу которых я отнесу и Вашего покорного слугу ;-)  Собственно, мы не конструкторское бюро, что захотим, то и наворотим. В принципе - правильно. Вся будущая прелесть (или гадость?) нашей разработки целиком и полностью в наших собственных руках.
И все же, чтобы мой уважаемый читатель имел представление о том, что его ждет впереди, я предлагаю своеобразный способ постановки технического задания - скриншоты меню с учетом изложенной ранее формулы.
Напомню, что о том, как создать и наполнить пунктами главное меню приложения, я уже рассказывал в уроке №2.
Итак, как и любая другая программа, работающая с цифрами, программа "Расходы" должна позволять оператору выполнять стандартный набор функций:
  • ввод данных,
  • изменение данных,
  • получение отчетности (вывод результатов на печать или экспорт в общепринятый формат электронной таблицы).
Кроме того, программа должна предоставлять оператору возможность наполнения и поддержания в актуальном состоянии различных кодификаторов (справочников), к примеру: плана счетов, списка мемориальных ордеров и перечня валют.
И было бы совсем не плохо, если ли бы программа поддерживала многоязыковый интерфейс и имела бы контекстно зависимую справочную систему.






Если воспринимать данный рисунок как техническое задание на разработку программы, то становится примерно понятно: как много нужно всего сделать, чтобы программа стала полноценным инструментом.
Я уверен, что, используя навыки, полученные на уроке 4, Вы легко создадите ActionList и оформите пункт меню "Файл - Выход" :-)
На этом можно было бы и закончить, предоставив Вам время на создание заготовки будущего приложения.
Но! На самом первом уроке! я рассказывал о том, как исключить запуск второй копии программы. Здесь уместно будет добавить пару  проверок в код проекта.
Первая из новых функций будет предназначена для проверки формата системной даты. Обусловлено это тем, что хранилищем для данных, с которыми будет работать программа, я выбрал базу данных Access, о создании которой мы поговорим чуть позже. Access - самая подходящая для подобных разработок среда. Имея ввиду простоту ее использования, ее даже называют "средой для домашних хозяек". Однако, многолетняя практика использования СУБД Access дает мне все основания утверждать, что встроенные возможности SQL, путаясь в неоднозначностях форматов даты заокеанского и прочих, использующих в качестве разделителя точку, нередко приводят к ошибкам при обращении к таблицам базы данных посредством SQL запросов, содержащих поля типа "дата". Я нашел "средство борьбы" с особенностями национальных настроек. Access перестает пугать корявыми результатами запросов, если в системной дате вместо разделителя "." использовать допустимый разделитель "/". Новая функция как раз и будет отвечать на вопрос: "Является ли разделителем разрядов в системной дате "/"?"
Вторая функция будет пытаться определить наличие файла настроек программы, т.е. файла с расширением ini, без которого работа программы также невозможна.
Итак. Вы создали новый проект, сохранили его как Rashod.bdsproj, а единственную форму в нем - как Main.pas.
Используйте меню Project - View Source:
program Rashod;
uses  Forms,  Windows,  iniFiles,  ...; // По мере создания программы список будет пополняться
{$R *.res}
// Несколько необходимых переменных
var  HM: THandle;
ini: TIniFile;                                     // Переменная, позволяющая обратиться
// к файлу ini
ConnectionString :string;          // Переменная, в которую в будущем
// будет записана строка подключения к базе данных
// Эту функцию мы уже рассматривали ранее
function Check: boolean;  {проверка на запуск второй копии программы}
begin
HM := OpenMutex(MUTEX_ALL_ACCESS, false, 'MyOwnMutex');
Result := (HM <> 0);
if HM = 0  then    HM := CreateMutex(nil, false, 'MyOwnMutex');
end;
// Функция проверки формата даты
function CheckDate: boolean;  {проверка на Правильность системной даты (/)}
var     fStr: String;
begin
Result:=false;
fStr:=DateToStr(Date());                                        // Получение системной даты, преобразование ее в строку
If Pos('/',fStr)=0  Then    ShowMessage('Формат системной даты не верен, работа программы невозможна. ')  else  Result:=True;   // Поиск символа "/" в строке
end;

// Функция проверки наличия ini файла
Function Check_No_INI: boolean;
begin    // попытка считывания из ini файла, находящегося в текущем каталоге
ini:=TiniFile.Create(GetCurrentDir + '\Rashod.ini');
ConnectionString:=Ini.ReadString('General','ConnectionString','');
if ConnectionString='' then
begin      Result:=true;      MessageDlg('Файл Rashod.ini не определён. Обратитесь к разработчику.',mtError, [mbOk], 0);    end
else    Result:=false
end;
// Использование всех имеющихся функций перед стартом приложения
begin
if CheckDate  then
if Check    then      exit
else
if  Check_No_INI      then        exit
else
begin
Application.Initialize;
Application.Title := 'Учет доходов и расходов';
Application.HelpFile := '';
Application.CreateForm(TMainFrm, MainFrm);
Application.Run;
end;
end.


Что же дальше?
Наверное, кто-то этого ждал уже давно: в следующем уроке я буду рассказывать о создании базы данных.