unit ExtProc;
  { пример, как в DBGrid работает раскраска строк/ячеек,
    перезагрузка строк (в случае изменения значений DataSet в другом месте)
    без смещения этих строк  }
interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Grids, DBGrids, DB, DBTables, ComCtrls, ShellAPI,
  DBCtrls, ExtCtrls, Buttons;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    QueryMain: TQuery;
    StatusBar1: TStatusBar;
    Panel1: TPanel;
    DataSource1: TDataSource;
    DBNavigator1: TDBNavigator;
    BtnEdit: TBitBtn;
    BtnAdd: TBitBtn;
    BtnDel: TBitBtn;
    BtnHelp: TBitBtn;
    procedure FormShow(Sender: TObject);
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure MnHelpClick(Sender: TObject);
    procedure BtnEditClick(Sender: TObject);
    procedure BtnAddClick(Sender: TObject);
    procedure BtnDelClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
  public
    procedure UpdateDBGrid1(ID,NRow:integer; Stat:byte);
  end;

  function ActiveRow(DBGrid:TDBGrid):integer;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses EditForm;

type
  TXDBGrid = class(TDBGrid);  // чтобы глубже залезть в DBGrid

var WorkPath: string;

procedure TForm1.FormShow(Sender: TObject);
var s:string;
begin
    // можно внутри программы использовать свой формат даты
  DateSeparator:= '.';
  ShortDateFormat:= 'dd/mm/yyyy';
    // если готовить Panels, то здесь - в FormActivate это делать уже нельзя -
    // могут быть повторные вызовы Activate
  StatusBar1.Panels.Add;
  StatusBar1.Panels.Add;
  StatusBar1.Panels[0].Width:= 100;
  Application.OnMessage:= AppMessage; // чтобы задействовать колесико мышки
  WorkPath:= ExtractFilePath(Application.ExeName);
  s:= WorkPath + 'Primer.db';
  if not FileExists(s) then begin
    with TTable.Create(nil) do begin
      TableName:= s;
      with FieldDefs do begin
        Clear;
        Add('ID', ftAutoInc,0);
        Add('NAME', ftString,50);
        Add('SALDO', ftCurrency, 0); // сальдо
      end;
      CreateTable;
      Free
    end; { with TTable }
  end;
  QueryMain.Close;
  QueryMain.SQL.Clear;
  QueryMain.SQL.Add('SELECT * FROM "' + s + '" ORDER BY NAME');
  QueryMain.Open;
  StatusBar1.Panels[0].Text:= ' Primer.db';
  StatusBar1.Panels[1].Text:=
    ' Всего записей - ' + IntToStr(QueryMain.RecordCount);
  Form2.Table1.TableName:= s;
end;

    { ---- Раскраска строки (с отрицательным сальдо) ---- }

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  s: string; k: integer; ColumnSaldo, NeedDraw: boolean;
begin
    // раскраска ячеек с отрицательным сальдо
  if not QueryMain.Active then exit;  // на в.с.
  with DBGrid1.Canvas do begin
    NeedDraw:= false;  // пока раскрашивать не надо
    ColumnSaldo:= Column.Field.FieldName = 'SALDO';
    if ColumnSaldo then
      NeedDraw:= Column.Field.AsCurrency < 0;
    if not NeedDraw and not(gdSelected in State) then
      exit;  // - ничего раскрашивать не надо
    if gdSelected in State then begin
       // выделенную строку раскрашиваем сами, но можно и пропустить -
       // тогда - выйти, если NeedDraw = false
      Brush.Color := clBlue; // цвет ячейки
      FillRect(Rect); // - если ячейку закрашивать
    end;
    if NeedDraw then begin
      Font.Color:= $0050C8;  // red
      Font.Style := Font.Style + [fsBold];
    end;
        // цвет есть, теперь - текст
    s:= Column.Field.DisplayText;
        // положение
    case Column.Alignment of
       taLeftJustify: k:= Rect.Left + 2;
      taRightJustify: k:= Rect.Right - TextWidth(s) - 3;
                else  // taCenter
           k:= Rect.Left + (Rect.Right - Rect.Left) shr 1
           - (TextWidth(s) shr 1);
    end;
    TextRect(Rect, k, Rect.Top + 2, s);
  end;
end;

  { ----- № строки в DBGrid с текущей записью (нач. с 0) ------ }
     // если есть строка Title, то реальная строка в DBGrid на 1 больше
function ActiveRow(DBGrid:TDBGrid):integer;
begin
  Result:= TXDBGrid(DBGrid).DataLink.ActiveRecord
end;

            { ----  Обновление DBGrid1  ---- }

procedure TForm1.UpdateDBGrid1(ID,NRow:integer; Stat:byte);
  // Stat = 0 - Add, 1 - Edit, 2 - Delete;
  // ID - куда курсор ставить (in DataSet); при Delete значение ID не важно
var
  k0,r0, R, RCount: integer; FindRec:boolean;
  // поскольку рассм. R <> NRow, то dgTitles не влияет
begin
  DBGrid1.DataSource.DataSet.DisableControls;
  RCount:= TXDBGrid(DBGrid1).VisibleRowCount; // ! кол-во рабочих строк в DBGrid
  QueryMain.Next;                        { выясняем ближ. номер на случай }
  if QueryMain.Eof then QueryMain.Prior; { исчезновения записи из SELECT }
  k0:= QueryMain.Fields[0].AsInteger;    // ключ ID
   // перезагрузка данных
  QueryMain.Close; QueryMain.Open;
  if QueryMain.RecordCount > 0 then begin
    if Stat = 2 then FindRec:= false
    else FindRec:= QueryMain.Locate('ID', ID, []);
    if not FindRec then
      FindRec:= QueryMain.Locate('ID', k0, []);
    if FindRec then
      if Stat > 0 then begin
        R:= ActiveRow(DBGrid1); // обычно это середина списка
        if R <> NRow then begin
          if NRow < R then dec(NRow, RCount - 1); // верхняя половина списка
          r0:= QueryMain.MoveBy(-NRow);  // туда
          QueryMain.MoveBy(-r0);      // обратно
        end;
      end;
  end;
  DBGrid1.DataSource.DataSet.EnableControls;
  StatusBar1.Panels[1].Text:=
      ' Всего записей - ' + IntToStr(QueryMain.RecordCount);
end; { UpdateDBGrid1 }

{ -- Задействовать полностью колесико мышки (MouseWheel) -- }

procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
var
  i: SmallInt;
begin
  if Msg.message = WM_MOUSEWHEEL then
  begin
     Msg.message:= WM_KEYDOWN;
     Msg.lParam:= 0;
     i:= HiWord(Msg.wParam);
     if i > 0 then
       Msg.wParam:= VK_UP
     else
       Msg.wParam:= VK_DOWN;
     Handled:= False;
  end;
{ в теле программы:
  Application.OnMessage:= AppMessage; }
end;

      { ---- Изменить запись ---- }

procedure TForm1.BtnEditClick(Sender: TObject);
begin
  if QueryMain.RecordCount = 0 then
    Form2.Tag:= 0  // переведем на ввод новой записи
  else Form2.Tag:= 1; // признак редактирования - для Form2
  Form2.ShowModal;
end;

      { ---- Добавить новую запись ---- }

procedure TForm1.BtnAddClick(Sender: TObject);
begin
  Form2.Tag:= 0;
  Form2.ShowModal;
end;

      { ---- Удаление записи ---- }

procedure TForm1.BtnDelClick(Sender: TObject);
var NRow:integer;
begin
  if QueryMain.RecordCount = 0 then exit;
  if Application.MessageBox('Удалить выделенную запись?', PChar(Caption),
     MB_ICONQUESTION + MB_YESNO) = mrNO then exit;
  NRow:= ActiveRow(DBGrid1);
  with TQuery.Create(nil) do begin
    SQL.Clear;
    SQL.Add('DELETE FROM "' + WorkPath + 'Primer.db"');
    SQL.Add('WHERE ID=' + QueryMain.Fields[0].AsString);
    ExecSQL;
    Free;
  end;
  UpdateDBGrid1(0,NRow,2);
end;

      { ---- Вызов справочника-инструкции ---- }

procedure TForm1.MnHelpClick(Sender: TObject);
var h:hWnd; HelpF:string;
begin
  HelpF:= ExtractFilePath(ParamStr(0)) + 'Manual.hlp';
  if not FileExists(HelpF) then begin
    Application.MessageBox('Нет соответствующего help-файла',
     ' Ошибка открытия файла', MB_ICONSTOP);
    exit
  end;
  h:=0;
  ShellExecute(h, 'open', PChar(HelpF), nil, nil, SW_SHOW)
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  QueryMain.Close;
end;

end.
Hosted by uCoz