Коллеги, день добрый...
Решил в DBGrid вшить DateTimePicker в поля, которые являются датой.
В общем что делаю. Создаю компонент как родительский от грида. Далее, вешаю обработку изменений DateTimePicker для записи в БД. Следующим моим шагом была обработка очистки при нажатии на Del или Backspace. И заключительным итогом было добиться, чтобы компонент работал как стандартный компонент редактирования сетки (при нажатии на таб или шифт таб производилась навигация по ячейкам, при ctrl+del было удаление и т.д.) в общем не было бы проблем, если бы в событии keypressed отлавливался TAB. вот тут и начались проблемы. Нашел на одном из ресурсов рекомендацию по замене события приложения OnMessage. Все хорошо и замечательно начало получаться, однако возникла другая проблема: в случае, когда DateTimePicker в фокусе, не получается мышью переключиться на другие элементы формы (становится просто невозможно изменить фокус). По клику мыши на кнопки, фокус без нажатия на кнопку тут же возвращается обратно к DateTimePicker. Доступно только переключение PageControl и переключение в сетке. Gри этом навигация кнопками по сетке работает, ctrl+del работает.
Собственно, как я только не извращался, но проблемы не решило и хоть убей не понимаю как отлаживать эту процедуру... В общем прошу помощи, у кого какой опыт решения проблемы был. Сразу скажу, что хочу принципиально понять как решить проблему, поэтому другие компоненты не предлагать.
Сам код:
Обработчик Application.OnMessage
procedure ThotelCrDBGrid.AppMessage(var Msg: TMsg; var Handled: Boolean);
var a : integer;
begin
if (Msg.Message = WM_KEYDOWN) and (Msg.hwnd = DateTimePicker.Handle) then
if (Msg.wParam = VK_BACK) or ((Msg.wParam = VK_DELETE) and
not ((GetKeyState (VK_LCONTROL) <= 0) or (GetKeyState (VK_RCONTROL) <= 0))) then
begin
DateTimePicker.Format := '''''''' '''''''';
fCurrentDateColumn.Field.DataSet.Edit;
fCurrentDateColumn.Field.Value := Null;
end
else if (Msg.wParam = VK_UP) or (Msg.wParam = VK_DOWN)
or (Msg.wParam = VK_LEFT) or (Msg.wParam = VK_RIGHT) then
begin
DefWindowProc(Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam);
end
else
begin
SendMessage (Handle, Msg.message, Msg.wParam, Msg.lParam);
SetFocus;
Msg.message := 0;
Handled := True;
end
else
Handled := False;
end;
Остальные обработчики для понимания
constructor ThotelCrDBGrid.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DateTimePicker := TDateTimePicker.Create (AOwner);
DateTimePicker.Visible := False;
DateTimePicker.OnChange := DTPOnChange;
DateTimePicker.OnKeyDown := DTPKeyDown;
DateTimePicker.Parent := Self;
DateTimePicker.TabStop := False;
DateTimePicker.TabOrder := -1;
DateTimePicker.OnExit := DTPExit;
OnDrawColumnCell := CRDBGDrawColumnCell;
Application.OnMessage := AppMessage;
end;
procedure ThotelCrDBGrid.DTPOnChange (Sender: TObject);
var
vCounter : integer;
begin
DateTimePicker.Format := ''''''''dd.MM.yyyy'''''''';
fCurrentDateColumn.Field.DataSet.Edit;
fCurrentDateColumn.Field.Value := DateTimePicker.Date;
end;
procedure ThotelCrDBGrid.CRDBGDrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
if (gdSelected in State) and ((Column.Field.DataType = ftDate) or (Column.Field.DataType = ftDateTime)) and
(dgEditing in Options) then
begin
DateTimePicker.Top := Rect.Top - 1;
DateTimePicker.Left := Rect.Left;
DateTimePicker.Height := Rect.Bottom - Rect.Top + 2;
DateTimePicker.Width := Rect.Right - Rect.Left;
if VarIsNull (Column.Field.Value) then
DateTimePicker.Format := '''''''' ''''''''
else
begin
DateTimePicker.Format := ''''''''dd.MM.yyyy'''''''';
DateTimePicker.Date := Column.Field.Value;
end;
DateTimePicker.Visible := True;
DateTimePicker.SetFocus;
fCurrentDateColumn := Column;
end;
end;
procedure ThotelCrDBGrid.DTPExit(Sender: TObject);
begin
DateTimePicker.Visible := False;
fCurrentDateColumn := nil;
end;