Rabu, 03 Februari 2010

DateTimePicker inside a DBGrid

http://delphi.about.com/od/usedbvcl/l/aa121503a.htm

DateTimePicker inside a DBGrid

Here's how to place a TDateTimePicker into a DBGrid. Create visually more attractive user interfaces for editing date/time fields inside a DBGrid - place a drop down calendar into a cell of a DBGrid.







Yes! More controls are being added to a DBGrid! What a great idea! Let's see how to create the best data editing grid ever!

This is the fourth article, in the series of articles named "Adding components to a DBGrid". The idea is to show how to place just about any Delphi control (visual component) into a cell of a DGBrid. If you are unfamiliar with the idea, please first read the "Adding components to a DBGrid" article.

DateTimePicker in a DBGrid?
Why not! If you have a database table containing a date (time) field you could/should be tempted to provide a calendar-like drop down selection for a user to select the date time value. Of course, Delphi has all you need, just take the pieces (components and code) and of you go. The TDateTimePicker (on "Win32" component palette tab) is a visual component designed specifically for entering dates or times.
Since Delphi does not provide a DB-aware version of the TDateTimePicker component, we'll need to use some tricks to make our date picker appear inside a DBGrid - in this article you'll see the fastest way of implementing an "in-dbgrid" drop down date (time) calendar picker.

DateTimePicker in a DBGrid!
Let's start by creating a sample application ... Note: be sure to check this link in order to see what we are "dealing" with. Our sample MS Access database, quickiescontest.mdb, has a table named "Articles" and this table has one date/time field called "DateAdded".
Once you set up a DBGrid displaying records from the Authors table, Delphi will add a TDateTimeField field object that represents the DateAdded field in the database table. Note that if you use the Fields editor at design time to create a persistent field component for the date-time field, you can access it by name at runtime - in our case the field is called "DateAdded", and the TDateTimeField variable is "AdoTable1DateAdded".

Now, since we've already discussed the theory of adding controls to a DBGrid, I'll just list the necessary steps here, along with the code...

Naturally, we first need to place a TDateTimePicker on a form, so drop one. Using the Object Inspector, change the name of the TDateTime component to "DateTimePicker". Next, set its Visible property to False. As stated above, the TDateTime picker is not db-aware so there are no DB related properties to set.

Magic...
What's left for us to do, is to actually make a drop down calendar hover over a cell (when in edit mode) displaying the DateAdded field's value. We've already talked theory - I'll show you only the code here (you'll have the option to download the entire project later):
First, we need to make sure the DateTimePicker is moved (and sized) over the cell in which the DateAdded field is displayed.

procedure TForm1.DBGrid1DrawColumnCell
(Sender: TObject;
const Rect: TRect;
DataCol: Integer;
Column: TColumn;
State: TGridDrawState);
begin
if (gdFocused in State) then
begin
if (Column.Field.FieldName = 'DateAdded') then
with DateTimePicker do
begin
Left := Rect.Left + DBGrid1.Left + 1;
Top := Rect.Top + DBGrid1.Top + 1;
Width := Rect.Right - Rect.Left + 2;
Width := Rect.Right - Rect.Left + 2;
Height := Rect.Bottom - Rect.Top + 2;

Visible := True;
end;
end
end;




Next, when we leave the cell, we have to hide the date time picker:

procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
if DBGrid1.SelectedField.FieldName = 'DateAdded' then
DateTimePicker.Visible := False
end;




Next, note that when in editing mode, all keystrokes are going to the DBGrid's cell, we have to make sure they are sent to the DateTimePicker. We are primarily interested in the [Tab] key - [Tab] should move the input focus to the next cell.

procedure TForm1.DBGrid1KeyPress
(Sender: TObject; var Key: Char);
begin
if (key = Chr(9)) then Exit;

if (DBGrid1.SelectedField.FieldName = 'DateAdded') then
begin
DateTimePicker.SetFocus;
SendMessage(DateTimePicker.Handle, WM_Char, word(Key), 0);
end
end;




We are not finished yet. Just two more events to handle! What we need to do is to place the dataset into edit mode when the user opens the drop-down calendar, and we have to assign the value of the date that is marked on the calendar to the DateAdded field. Just handle the OnDropDown and the OnChange events:

procedure TForm1.DateTimePickerChange(Sender: TObject);
begin
if DBGrid1.DataSource.State in [dsEdit, dsInsert] then
ADOTable1DateAdded.Value := DateTimePicker.DateTime;
end;

procedure TForm1.DateTimePickerDropDown(Sender: TObject);
begin
DBGrid1.DataSource.Edit;
end;




That's it. Run the project and voila ... one nicely looking drop down calendar enabling you to change the value of DateAdded field's column.





Note: TDateTimePicker formats date and time values according to the date and time settings in the Regional Settings of the Control panel on the user's system - this is why you see Croatian date-time formatting.
If you need any help, after you download and explore the full source code for this project, I encourage you to post any questions on the Delphi Programming Forum.

Ok, ok.. you'll be even more happy with a "real" db-aware TDateTimePicker ... let's say we'll build one in the near future.

Need more DBGrid related articles?
Be sure to check the "Adding components to a DBGrid" article and the rest of the articles dealing with the DBGrid (and other db-aware) components; of course don't miss the "DBGrid to the Max" article collection!

5 komentar:

INGIN KERJA DARI RUMAH?