Любой бухгалтер скажет: "Мне это зачем? Мне Журнал хозяйственных операций дай и Главную книгу".
Но, во-первых, мы пишем не бухгалтерскую, а очень очень похожую программу.
Во-вторых, у нас уже есть нечто, отдаленно напоминающее ЖХО. Не хватает отчета в удобной форме - сделаем. У нас есть замечательная оборотка, из которой только ленивый не построит Главную книгу.
В-третьих, графическое представление информации удобно в тех случаях, когда нужно быстро проанализировать огромный массив данных, чтобы принять какое-то конструктивное решение.
В-четвертых, интереснее рассказывать о чем-то, о чем еще не рассказывал...
Надеюсь, что я привел убедительные доводы в поддержку своих же намерений :-)
Добавляем в проект новую форму (имя формы AnalizFrm), проделывая все те необходимые действия, которые описаны в предыдущем уроке.
Немного слов о том, какие компоненты должны присутствовать на форме:
- TPopupMenu - понадобится как минимум экспортировать данные,
- TActionList - коллекция действий (в основном - нажатия кнопок),
- TPrDOkButton - кнопка из коллекции Pro-Delphi Lib,
- TPageControl с двумя вкладками, изображенными на рисунках выше,
- Два элемента управления для ввода дат начала и окончания периода из библиотеки EhLib,
- TButton - вычислить и показать результат,
- TADOQuery - обратиться к базе данных с запросом (:-)),
- TDataSource - связать запрос и отображающий его результат элемент управления на форме, которым является:
- TDBGridEh - сетка,
- и наконец - TChart (с вкладки Additional) - компонент, способный отображать графики.
Для подготовки TChart к работе, нужно щелкнуть по нему два раза:
и нажать кнопку "Add", чтобы добавить новую серию. Я выбрал обычную столбчатую диаграмму. Обратите внимание, что отметка 3D снята (ОК).
Заголовок - title - задайте на одноименной вкладке.
На этом, собственно, предварительная настройка закончена.
Приступим к наполнению кода формы.
Первое, что нам понадобится - массив с константами цветов
var
AnalizFrm: TAnalizFrm;
MyColor: array[1..16] of TColor = (
clMaroon
,clGreen
,clYellow
,clOlive
,clNavy
,clPurple
,clTeal
,clLime
,ClGray
,clRed
,clSilver
,clBlue
,ClFuchsia
,clAqua
,clMoneyGreen
,clSkyBlue
);
implementation
Я уже говорил раньше о массивах, но здесь я объявляю его иначе, используя возможность его инициализации при объявлении (т.е. присваиваю значения элементам массива, зная их заранее).
При старте формы логично сделать следующие действия:
procedure TAnalizFrm.FormCreate(Sender: TObject);
begin
// При создании формы задать значения датам
Date_N.Value:=Now()-365; // На год назад
Date_K.Value:=Now()+1; // По сегодня включительно
// Назначить запросу способ подключения
ADOQuery1.Connection:=MainFrm.ADOConnection1;
end;
При выключении формы - почистить за собой памятийку:
procedure TAnalizFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:= caFree;
end;
Нажатие кнопок (в частности Escape) обработаем следующими двумя процедурами (это - стандартный подход):
procedure TAnalizFrm.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
case Key of // Start Case
VK_ESCAPE:
begin
MyClose;
end;
else
End; // End case
end;
procedure TAnalizFrm.MyClose();
Begin
Close;
end;
Экшен, подложенный под кнопку "OK":
procedure TAnalizFrm.ButtonClickExecuteExecute(Sender: TObject);
begin
if (ModalResult=1) OR (ModalResult=2)
then
Begin
MyClose;
end;
end;
А теперь - самое главное - обработчик нажатия кнопки "Показать"
procedure TAnalizFrm.Button1Click(Sender: TObject);
Var MyStr: String;
j: Integer;
begin
// Подготовка запроса
ADOQuery1.Active:=False;
ADOQuery1.SQL.Clear;
MyStr:='SELECT Accounts.ID, Accounts.Name, Sum(Main.Summa) AS MySum ';
MyStr:=MyStr + 'FROM Accounts INNER JOIN Main ON Accounts.ID = Main.D ';
MyStr:=MyStr + 'WHERE (((Accounts.Val)='+IntToStr(MySelect.MySel_IDVal)+') AND ((Accounts.Analiz)=True) ';
MyStr:=MyStr + 'AND ((Main.MyDate)>=#'+FormatDateTime('mm/dd/yyyy',Date_N.Value)+'# And (Main.MyDate)<#'+FormatDateTime('mm/dd/yyyy',Date_K.Value)+'#)) ';
MyStr:=MyStr + 'GROUP BY Accounts.ID, Accounts.Name ';
MyStr:=MyStr + 'ORDER BY Sum(Main.Summa) DESC';
ADOQuery1.SQL.Add(MyStr);
ADOQuery1.Active:=True;
// Настройка графика
j:=1;
With Series1 do
begin
Clear;
while (Not ADOQuery1.Eof) do
Begin
if j>16 // Если количество столбцов в графике больше 16, то цвета будут повторяться
then
j:=1
else
j:=j+1;
// Следующей строкой задается отображение очередного столбца
// Сумма и название (счета) - из запроса
// Цвет - из массива
Add(ADOQuery1.FieldByName('MySum').Value, ADOQuery1.FieldByName('Name').Text, MyColor[j]);
ADOQuery1.Next;
end;
Active:=True;
end;
end;
если Вы думаете, что я написал все, что вталкивается в переменную MyStr, своими ручками от начала и до конца, то Вы оооооччччееееннньььь ошибаетесь.
Откройте оболочку Access и создайте запрос в режиме конструктора
примерно такой, какой Вам понадобится в программе
Мне понадобится групповая функция (суммирование), выборка из двух связанных таблиц (таблица Accounts даст названия вместо ID), графики я буду строить только по счетам, которые отмечены ИСТИНА в поле Analiz (действительно, зачем мне анализировать затраты, например по перекладываю денег из кошелька в чулок или кубышку?!) и ориентировочно я указал даты (примерно за год).
Если все сделано правильно, то запрос при выполнении отобразит набор записей:
(цифры здесь учебные, не имеющие отношения к реальной жизни :-) )
А теперь - переведите запрос в режим SQL, нажатием кнопки слева вверху:
- вот он текст нужного запроса! Теперь простым копированием и вставкой (Ctrl-C и Ctrl-V) размещаем его текст в модуле формы, добавляем MyStr, немного функций, которые преобразуют значения из элементов управления (даты) и переменной (MySelect.MySel_IDVal - код валюты) в удобоваримые для Delphi и все.
Обращаю Ваше внимание на то, как я обошелся с датами в запросе:
Access "любит" дату в запросе вот в таком виде
#mm/dd/yyyy#
Если Вы будете использовать базу данных на основе SQL Server, то диезы Вам точно не понадобятся. Но, поскольку я здесь использую БД Access, нужно привыкнуть к этому формату. Кроме того, настоятельно рекомендую изменить системные настройки, указав в качестве разделителя в дате "/" вместо установленной по умолчанию точки. Мой многолетний опыт общения с оболочкой Access настаивает на том, что не все и не всегда запросы к базе данных в среде Access возвращают корректный (правильный) набор данных при использовании в качестве разделителя даты точки!
procedure TAnalizFrm.N_ExportClick(Sender: TObject);
begin
// Для вывода в Excel используется имеющаяся в модуле главной формы процедура
MainFrm.ExportTo(PChar('Лист 1'), DBGridEh1, MainFrm.XLApp, PChar('Затраты'), PChar('Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value)));
end;
В главной форме необходимо реализовать вывод формы "Анализ затрат" на экран по выбору пункта Меню - Отчетные формы - Анализ затрат (все)
procedure TMainFrm.N_AnalizClick(Sender: TObject);
begin
// Анализ затрат
Application.CreateForm(TAnalizFrm, AnalizFrm);
AnalizFrm.ShowModal;
AnalizFrm.Free;
end;
чтобы получить в итоге вот такую картинку:
* * *
Пункт выпадающего меню "Экспорт". Прежде нужно назначить компоненту TChart свойство PopupMenu=PopupMenu1, а затем написать обработчик выбора пункта меню:
begin
// Для вывода в Excel используется имеющаяся в модуле главной формы процедура
MainFrm.ExportTo(PChar('Лист 1'), DBGridEh1, MainFrm.XLApp, PChar('Затраты'), PChar('Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value)));
end;
В результате работы получим вот такую табличку:
* * *
В главной форме необходимо реализовать вывод формы "Анализ затрат" на экран по выбору пункта Меню - Отчетные формы - Анализ затрат (все)
procedure TMainFrm.N_AnalizClick(Sender: TObject);
begin
// Анализ затрат
Application.CreateForm(TAnalizFrm, AnalizFrm);
AnalizFrm.ShowModal;
AnalizFrm.Free;
end;
глянув на которую, можно впасть в кому... :-)
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.