Правильная ссылка на эту страницу
http://az-design.ru/Projects/AzBook/AZMicro/AZMicroC3.shtml

Справочник "План счетов"

       Справочник "План счетов" разместим в меню "Edit" и в целом он очень похож на такой же в программе AZMicro. Разница только в том, что он теперь выделен в отдельную форму, в которой древовидное отображение совмещено с редактированием основных полей.
       Проектирование формы начинаем с расскладыванием основных элементов.
       На простую форму кладем панель Panel1, на которой располагаем кнопки навигатора nvgChartAcc. Устанавливаем параметр Align=alTop.
       Затем кладем компонент TreeView, называем его tvChartAcc.
       Потом опять панель Panel2, на которой расположены поля для редактирования.
       И, наконец, поле для редактирования описания счета edAcDescrpt типа TDBMemo.
       Устанавливаем для него параметр Align=alBottom.
       Устанавливаем параметр Align=alBottom для Panel2.
       И устанавливаем параметр Align=alClient для tvChartAcc.
       И на этом дизайн можно закончить.
       Для работы с базой данных нужно добавить два комплекта Dataset-ов — один для построения дерева, другой для редактирования отдельных полей. Кроме того, потребуется набор компонентов для выполнения процедур и запросов. Для этого используется компонент TIBSql соединенный со своим компонентом TIBTransaction.
       Для выполнения отдельных операций с деревом добавим всплывающее меню pmnChartAcc, которое указываем в параметре PopupMenu компонента tvChartAcc.
       Подготовительные операции закончены и можно наполнять форму процедурами.
       При создании формы в процедуре FormCreate нужно настроить Dataset для редактирования отдельных полей таблицы dstChartAcc:

  dstChartAcc.Close;  dstChartAcc.SelectSQL.Clear;
  dstChartAcc.SelectSQL.Add('Select AccntNum,AccTitle,ACDESCRP from ChartAcc');
  dstChartAcc.SelectSQL.Add('where AccntNum=:SelAccnt');
  dstChartAcc.ParamByName('SelAccnt').AsString := '01-00';
  dstChartAcc.RefreshSQL.Clear;
  dstChartAcc.RefreshSQL.Add('Select AccntNum,AccTitle,ACDESCRP from ChartAcc');
  dstChartAcc.RefreshSQL.Add(' where AccntNum=:OLD_AccntNum');
  dstChartAcc.ModifySQL.Clear;
  dstChartAcc.ModifySQL.Add('Update ChartAcc set');
  dstChartAcc.ModifySQL.Add(' AccntNum = :AccntNum,');
  dstChartAcc.ModifySQL.Add(' AccTitle = :AccTitle,');
  dstChartAcc.ModifySQL.Add(' ACDESCRP = :ACDESCRP');
  dstChartAcc.ModifySQL.Add(' where ');
  dstChartAcc.ModifySQL.Add('  AccntNum=:OLD_AccntNum');
  dstChartAcc.Open;

       В параметре SelectSQL записываем запрос, который выбирает соответствующие поля из таблицы ChartAcc при условии, что значение AccntNum равно параметру :SelAccnt. Начальное значение этого параметра устанавливается в '01-00' и в дальнейшем оно будет меняться.
       В параметр RefreshSQL записываем запрос, который обновляет текущую запись после изменения.
       И, наконец, в запрос ModifySQL записываем запрос для изменения отдельных полей. После чего dstChartAcc можно открыть.
       После настройки этого Dataset вызывается процедура TreeDatasetOpen(), которая строит начальное состояние дерева плана счетов.
       Процедура построена также как и предыдущем случае, но выбирается только основной план счетов, а остальные значения игнорируются.

        tvChartAcc.Items.BeginUpdate;
        tvChartAcc.Visible := False;   tvChartAcc.Items.Clear;    tvChartAcc.Visible := True;
        dstTree.Close;   dstTree.SelectSQL.Clear;
        dstTree.SelectSQL.Add('Select * from ChartAcc');
        dstTree.SelectSQL.Add('where AccParnt=''AccBase'' order by AccOrder');
        dstTree.Open;     dstTree.First;

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

        While not dstTree.EOF do
          begin
             RowChild := 0;
             sFld := dstTree.FieldValues['AccntNum'];  sFld := acText8(sFld);
             sFld := sFld+' - '+dstTree.FieldValues['AccTitle'];
             NewNode := tvChartAcc.Items.Add(tvChartAcc.TopItem,sFld);
             RowChild := dstTree.FieldValues['AccCount'];
             If RowChild>0 then ChildNode := tvChartAcc.Items.AddChild(NewNode,IntToStr(RowChild));
             dstTree.Next;
          end; // While not qrTVChartAcc.EOF do

       Для раскрытия содержимого узлов используется процедура tvChartAccExpanding, которая вызывается при нажатии курсором на знак "Плюс" около узла, либо при использовании клавиши "->" для открытия узла. Ее структура очень похожа на TreeDatasetOpen, с той лишь только разницей, что значение родительского узла берётся из текущего узла и новый узел строится не в корне дерева, а как дочерний к текущему узлу:

procedure TfmChartAcc.tvChartAccExpanding(Sender: TObject; Node: TTreeNode;
                                          var AllowExpansion: Boolean);
Var
   RowChild : Integer;
   sFld : String;
   ChildNode,NewNode : TTreeNode;
begin
  inherited;
{$IFDEF AZDEBUG} MainForm.WriteReprtText('TfmChartAcc.tvChartAccExpanding >>>>'); {$ENDIF}
     If Node.HasChildren then begin
        Node.DeleteChildren;
        dstTree.Close;   dstTree.SelectSQL.Clear;
        sFld := Copy(Node.Text,0,8);
        dstTree.SelectSQL.Add('Select * from ChartAcc');
        dstTree.SelectSQL.Add('where AccParnt='''+sFld+''' order by AccOrder');
        dstTree.Open;     dstTree.First;
        While not dstTree.EOF do
          begin
             RowChild := 0;
             sFld := dstTree.FieldValues['AccntNum'];  sFld := acText8(sFld);
             sFld := sFld+' - '+dstTree.FieldValues['AccTitle'];
             NewNode := tvChartAcc.Items.AddChild(Node,sFld);
             RowChild := dstTree.FieldValues['AccCount'];
             If RowChild>0 then ChildNode := tvChartAcc.Items.AddChild(NewNode,IntToStr(RowChild));
             dstTree.Next;
          end; // While not qrTVChartAcc.EOF do
           tvChartAcc.Items.EndUpdate;
     end;// Node.HasChildren
     tvChartAcc.Update;
end;

       А вот дальнейшие процедуры новые для этого проекта.
       При изменении текущего узла вызывается процедура tvChartAccChange, которая привязана к событию onChange. Она используется для настройки dstChartAcc, который используется для редактирования отдельных полей плана счетов.

procedure TfmChartAcc.tvChartAccChange(Sender: TObject; Node: TTreeNode);
begin
{$IFDEF AZDEBUG} MainForm.WriteReprtText('TfmChartAcc.tvChartAccChange >>>>'); {$ENDIF}
  dstChartAcc.Close;
  dstChartAcc.ParamByName('SelAccnt').AsString := Copy(Node.Text,0,8);
  dstChartAcc.Open;
end;

       Группа процедур tvChartAccStartDrag, tvChartAccDragDrop, tvChartAccDragOver и tvChartAccEndDrag предназначены для изменения структуры дерева путем перетаскивания узлов. Основной код расположен в процедуре tvChartAccEndDrag:

procedure TfmChartAcc.tvChartAccEndDrag(Sender, Target: TObject; X, Y: Integer);
Var
   sSRC,sTRG : String;
begin
{$IFDEF AZDEBUG} MainForm.WriteReprtText('TfmChartAcc.tvChartAccEndDrag >>>>'); {$ENDIF}
  sTRG := Copy(TRGNode.Text,0,8);   sSRC := Copy(SRCNode.Text,0,8);
  If sTRG<>sSRC then begin
     sqlProc.Close;
     sqlProc.SQL.Clear;
     sqlProc.SQL.Add('Update ChartAcc set AccParnt='''+sTRG+'''');
     sqlProc.SQL.Add(' where AccntNum='''+sSRC+'''');
     trProc.StartTransaction;
     sqlProc.ExecQuery;
     trProc.Commit;
     sqlProc.Close;
     TRGNode.Parent.Collapse(True);
     SRCNode.Parent.Collapse(True);
  end;
end;

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

procedure TfmChartAcc.mnAccntCreateClick(Sender: TObject);
Var
  PrntNode,SelNode  : TTreeNode;
  sPrnt,sSel : String;
begin
   SelNode := tvChartAcc.Selected;
   PrntNode := SelNode.Parent;
   sPrnt := Trim(Copy(PrntNode.Text,0,8));
   sSel := Copy(sPrnt,0,3)+'New';
   sqlProc.Close;
   sqlProc.SQL.Clear;
   sqlProc.SQL.Add('Insert into ChartAcc(AccntNum,AccParnt,AccBalns,AccProft,AccTitle)');
   sqlProc.SQL.Add(' values('''+sSel+''','''+sPrnt+''',''.'',''.'',''Новый счет'');');
   trProc.StartTransaction;
   sqlProc.ExecQuery;
   trProc.Commit;
   sqlProc.Close;
   PrntNode.Parent.Collapse((True));
end;

       Из родительского узла получаются первые три символа счета, к которым добавляется слово new, а в название счета записывается "Новый счет". В запросе на вставку также указывается родительский счет. После выполнения запроса родительский узел сворачивается, чтобы при открытии данные обновились. И уже новые данные можно отредактировать и написать нужное название счета.
       Для удаления записи используется процедура:

procedure TfmChartAcc.mnAccntDeleteClick(Sender: TObject);
Var
  PrntNode,SelNode  : TTreeNode;
  sSel : String;
begin
   SelNode := tvChartAcc.Selected;
   PrntNode := SelNode.Parent;
   sSel :=  Trim(Copy(SelNode.Text,0,8));
   if SelNode.Count>0 then ShowMessage('Счет содержит субсчета!'+
+'Удалите сначала субсчета')
      else begin
        sqlProc.Close;
        sqlProc.SQL.Clear;
        sqlProc.SQL.Add('Delete from ChartAcc');
        sqlProc.SQL.Add(' where AccntNum='''+sSel+''';');
        trProc.StartTransaction;
        sqlProc.ExecQuery;
        trProc.Commit;
        sqlProc.Close;
      end;
   PrntNode.Parent.Collapse((True));
end;

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

Архангельский Андрей




<<< Пред. Оглавление
Начало раздела
След. >>>

Дата последнего изменения:
Thursday, 21-Aug-2014 09:10:56 MSK


Постоянный адрес статьи:
http://az-design.ru/Projects/AzBook/AZMicro/AZMicroC3.shtml