unit Un_frmDBGridEditNum;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Buttons,db,Grids, DBGrids, ExtCtrls;

type
  TfrmDBGridEditNum = class(TForm)
    btn7: TSpeedButton;
    btn8: TSpeedButton;
    btn9: TSpeedButton;
    btnBack: TSpeedButton;
    btnClear: TSpeedButton;
    btnRevers: TSpeedButton;
    btnSetValue: TSpeedButton;
    btnSeparator: TSpeedButton;
    btnSign: TSpeedButton;
    btn0: TSpeedButton;
    btn1: TSpeedButton;
    btn4: TSpeedButton;
    btn5: TSpeedButton;
    btn6: TSpeedButton;
    btn3: TSpeedButton;
    btn2: TSpeedButton;
    shLeftLine: TShape;
    shTopLine: TShape;
    shRightLine: TShape;
    shBottomLine: TShape;
    sh7: TShape;
    sh8: TShape;
    sh9: TShape;
    sh4: TShape;
    sh5: TShape;
    sh6: TShape;
    sh1: TShape;
    sh2: TShape;
    sh3: TShape;
    sh0: TShape;
    shSign: TShape;
    shSeparator: TShape;
    shBack: TShape;
    shClear: TShape;
    shRevers: TShape;
    shSetValue: TShape;
    tmrActivateGrid: TTimer;
    procedure AddChar(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ChangeSign(Sender: TObject);
    procedure AddSeparator(Sender: TObject);
    procedure ClearValue(Sender: TObject);
    procedure DeleteChar(Sender: TObject);
    procedure ReversValue(Sender: TObject);
    procedure SetValue(Sender: TObject);
    procedure ActivateGrid(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
     FControlHandle: HWND;
     FControl: TDBGrid;
     FOnChangeField:TFieldNotifyEvent;
     FOnStateChange:TNotifyEvent;
     property ControlHandle:HWND read FControlHandle write FControlHandle;
     procedure SetControl(const Value: TDBGrid);
     procedure OnChangeField(Sender: TField);
     procedure OnStateChange(Sender:TObject);
     procedure RestoreEvents;
     procedure RebuildWindowRgn;
  protected
     procedure Resize; override;
  public
     constructor Create(AOwner: TComponent);override;
     property Control:TDBGrid read FControl write SetControl;
     procedure Show;
  end;

procedure ShowCalc(AGrid:TDBGrid);

implementation

uses Mask;

var
   Hook:HHOOK;
   AForm:TfrmDBGridEditNum;

function KeyboardProc(Code:Integer;_WParam:WParam;_LParam:LParam):LResult;stdcall;
begin
   if _WParam=VK_ESCAPE then
      AForm.Close;
   Result:=CallNextHookEx(Hook,Code,_wParam,_LParam);
end;
   
procedure ShowCalc(AGrid:TDBGrid);
begin
   if Assigned(AForm) then begin
      Beep;
      Exit;
      //Raise Exception.Create('ShowCalc:Модуль уже используется');
   end;
   AForm:=TfrmDBGridEditNum.Create(AGrid);
   with AForm do begin
      Control:=AGrid;
      Show;
   end;
end;

{$R *.DFM}

{ TForm3 }

procedure TfrmDBGridEditNum.Show;
var
   R:TRect;
begin
   GetWindowRect(FControlHandle,R);
   if (R.Bottom+Height+2<=Screen.Height) then
     Top:=R.Bottom+1
   else Top:=R.Top-Height-1;
   if (R.Left+Width+2<=Screen.Width) then
    begin
       Left:=R.Left+1;
       if (Left<0) then
          Left:=1;
    end
   else Left:=Screen.Width-Width;
   inherited Show;
end;

procedure TfrmDBGridEditNum.AddChar(Sender: TObject);
begin
   SendMessage(FControlHandle,WM_CHAR,Ord((Sender as TSpeedButton).Caption[1]),0);
   Windows.SetFocus(FControlHandle);
end;

procedure TfrmDBGridEditNum.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   Action:=caFree;
   RestoreEvents;
   UnhookWindowsHookEx(Hook);
   AForm:=nil;
end;

procedure TfrmDBGridEditNum.SetControl(const Value: TDBGrid);
begin
  FControl := Value;
  if FControl<>nil then
   begin
      FControlHandle:=GetTopWindow(FControl.Handle);
      if FControlHandle=0 then
         Raise Exception.Create('Grid не в режиме редактирования');
      if Assigned(FControl.DataSource)and Assigned(FControl.DataSource.DataSet) then begin
         if (FControl.SelectedField.DataType in [ftSmallint,ftInteger,ftLargeInt]) then begin
            btnSeparator.Enabled:=False;
            btnRevers.Enabled:=False;
         end;
         //Заменяем события для того,чтобы калькулятор убирался при вводе с клавиатуры
         FOnChangeField:=FControl.SelectedField.OnChange;
         FControl.SelectedField.OnChange:=OnChangeField;
         //Надо установить режим редактирования,чтобы калькулятор закрылся по Esc
         if not(FControl.DataSource.DataSet.State in [dsEdit,dsInsert]) then
            FControl.DataSource.DataSet.Edit;
         FOnStateChange:=FControl.DataSource.OnStateChange;
         FControl.DataSource.OnStateChange:=OnStateChange;
         //Надо изменить содержимое,чтобы при переходе в другое место закрылась форма
         SendMessage(FControlHandle,WM_CHAR,Ord('0'),0);
         SendMessage(FControlHandle,WM_CHAR,8,0);
      end;
   end
  else Raise Exception.Create('Должна быть ссылка на объект');
end;

procedure TfrmDBGridEditNum.OnChangeField(Sender: TField);
begin
   if Assigned(FOnChangeField) then
      FOnChangeField(FControl.SelectedField);
   Close;
end;

procedure TfrmDBGridEditNum.ChangeSign(Sender: TObject);
var
   AText:string;
   ALength:Integer;
begin
   ALength:=GetWindowTextLength(FControlHandle);
   SetLength(AText,ALength+1);
   try
      GetWindowText(FControlHandle,PChar(AText),ALength+1);
      if (AText='')or(AText[1]<>'-') then
       begin //Добавляем минус
          SendMessage(FControlHandle, EM_SETSEL, 0, 0);
          SendMessage(FControlHandle, WM_CHAR, Ord('-'), 0);
          SendMessage(FControlHandle, EM_SETSEL, ALength+1, ALength+1);
       end
      else if (AText<>'') then
       begin //Удаляем минус
          SendMessage(FControlHandle, EM_SETSEL, 1, 1);
          SendMessage(FControlHandle, WM_CHAR, 8, 0);
          SendMessage(FControlHandle, EM_SETSEL, ALength, ALength);
       end;
   finally
      Windows.SetFocus(FControlHandle);
   end;
end;

procedure TfrmDBGridEditNum.AddSeparator(Sender: TObject);
var
   AText:string;
   ALength:Integer;
begin
   ALength:=GetWindowTextLength(FControlHandle);
   SetLength(AText,ALength+1);
   try
      GetWindowText(FControlHandle,PChar(AText),ALength+1);
      if Pos(Decimalseparator,AText)=0 then
       begin //Добавляем разделитель
          SendMessage(FControlHandle, WM_CHAR, Ord(DecimalSeparator), 0);
       end;
   finally
      Windows.SetFocus(FControlHandle);
   end;
end;

procedure TfrmDBGridEditNum.ClearValue(Sender: TObject);
var
   ALength:Integer;
begin
   ALength:=GetWindowTextLength(FControlHandle);
   SendMessage(FControlHandle, EM_SETSEL, 0, ALength);
   SendMessage(FControlHandle, WM_CHAR, 8, 0);
   Windows.SetFocus(FControlHandle);
end;

procedure TfrmDBGridEditNum.DeleteChar(Sender: TObject);
begin
   SendMessage(FControlHandle, WM_CHAR, 8, 0);
   Windows.SetFocus(FControlHandle);
end;

procedure TfrmDBGridEditNum.ReversValue(Sender: TObject);
var
   AText:string;
   ALength,I:Integer;
begin
   ALength:=GetWindowTextLength(FControlHandle);
   SetLength(AText,ALength+1);
   try
      GetWindowText(FControlHandle,PChar(AText),ALength+1);
      if (AText<>'')and(StrToFloat(AText)<>0) then begin
          SendMessage(FControlHandle, EM_SETSEL, 0, ALength+1);
          SendMessage(FControlHandle, WM_CHAR, 8, 0);
          AText:=FloatToStr(1/StrToFloat(AText));
          for I:=1 to Length(AText) do
             SendMessage(FControlHandle, WM_CHAR, Ord(AText[I]), 0);
      end;
   finally
      Windows.SetFocus(FControlHandle);
   end;
end;

procedure TfrmDBGridEditNum.SetValue(Sender: TObject);
begin
   RestoreEvents;
   Hide;
   SendMessage(FControlHandle, WM_CHAR, 13, 0);
   Close;
end;

procedure TfrmDBGridEditNum.RebuildWindowRgn;
var
  FullRgn, Rgn: THandle;
  ClientX, ClientY, I: Integer;
begin
  // определяем относительные координаты клиентской части
  ClientX:= (Width - ClientWidth) div 2;
  ClientY:= Height - ClientHeight - ClientX;
  FullRgn:= CreateRectRgn(0, 0, Width, Height); // создаем регион для всей формы
  // создаем регион для клиентской части формы и вычитаем его из FullRgn
  Rgn:= CreateRectRgn(ClientX, ClientY, ClientX + ClientWidth, ClientY +ClientHeight);
  CombineRgn(FullRgn, FullRgn, Rgn, rgn_Diff);
  // теперь добавляем к FullRgn регионы каждого контрольного элемента
  for I:= 0 to ControlCount -1 do
   with Controls[I] do begin
     Rgn:= CreateRectRgn(ClientX + Left, ClientY + Top, ClientX + Left +Width, ClientY + Top + Height);
     CombineRgn(FullRgn, FullRgn, Rgn, rgn_Or);
   end;
  SetWindowRgn(Handle, FullRgn, True); // устанавливаем новый регион окна
end;

procedure TfrmDBGridEditNum.Resize;
begin
  inherited;
  RebuildWindowRgn; // строим новый регион
end;

constructor TfrmDBGridEditNum.Create(AOwner: TComponent);
begin
  inherited;
  HorzScrollBar.Visible:= False; // убираем сколлбары, чтобы не мешались
  VertScrollBar.Visible:= False; // при изменении размеров формы
  RebuildWindowRgn; // строим новый регион
end;

procedure TfrmDBGridEditNum.OnStateChange(Sender: TObject);
begin
   if Assigned(FOnStateChange) then
      FOnStateChange(FControl.DataSource);
   Close;
end;

procedure TfrmDBGridEditNum.RestoreEvents;
begin
   FControl.SelectedField.OnChange:=FOnChangeField;
   FControl.DataSource.OnStateChange:=FOnStateChange;
end;

procedure TfrmDBGridEditNum.ActivateGrid(Sender: TObject);
var
   ALength:Integer;
begin
   //Это событие должно сработать один раз при создании формы
   tmrActivateGrid.Enabled:=False;
   Windows.SetFocus(FControlHandle);
   ALength:=GetWindowTextLength(FControlHandle);
   SendMessage(FControlHandle, EM_SETSEL, 0, ALength);
end;

procedure TfrmDBGridEditNum.FormShow(Sender: TObject);
begin
   //Устанавливаем ловушку
   Hook:=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,0,GetCurrentThreadID);
   if Hook=0 then
      ShowMessage('Ловушка не установлена');
end;

end.


Сайт управляется системой uCoz