Delphi Programming Guide
Delphi Programmer 

Menu  Table of contents
Bookmark and Share

Part I - Foundations
  Chapter 1 Delphi 7 and Its IDE
  Chapter 2 The Delphi Programming Language
  Chapter 3 The Run-Time Library
  Chapter 4 Core Library classes
  Chapter 5 Visual Controls
  Chapter 6 Building the User Interface
  Chapter 7 Working with Forms
Part II - Delphi Object-Oriented Architectures
  Chapter 8 The Architecture of Delphi Applications
  Chapter 9 Writing Delphi Components
  Chapter 10 Libraries and Packages
  Chapter 11 Modeling and OOP Programming (with ModelMaker)
  Chapter 12 From COM to COM+
Part III - Delphi Database-Oriented Architectures
  Chapter 13 Delphi's Database Architecture
  Chapter 14 Client/Server with dbExpress
  Chapter 15 Working with ADO
  Chapter 16 Multitier DataSnap Applications
  Chapter 17 Writing Database Components
  Chapter 18 Reporting with Rave
Part IV - Delphi, the Internet, and a .NET Preview
  Chapter 19 Internet Programming: Sockets and Indy
  Chapter 20 Web Programming with WebBroker and WebSnap
  Chapter 21 Web Programming with IntraWeb
  Chapter 22 Using XML Technologies
  Chapter 23 Web Services and SOAP
  Chapter 24 The Microsoft .NET Architecture from the Delphi Perspective
  Chapter 25 Delphi for .NET Preview: The Language and the RTL
       
  Appendix A Extra Delphi Tools by the Author
  Appendix B Extra Delphi Tools from Other Sources
  Appendix C Free Companion Books on Delphi
       
  Index    
  List of Figures    
  List of tables    
  List of Listings    
  List of Sidebars  

 
Previous Section Next Section

Database Applications with Standard Controls

Although it is generally faster to write Delphi applications based on data-aware controls, this approach is not required. When you need precise control over the user interface of a database application, you might want to customize the transfer of the data from the field objects to the visual controls. My view is that doing so is necessary only in specific cases, because you can customize the data-aware controls extensively by setting the properties and handling the events of the field objects. However, trying to work without the data-aware controls should help you better understand Delphi's default behavior.

The development of an application not based on data-aware controls can follow two different approaches: You can mimic the standard Delphi behavior in code, possibly departing from it in specific cases, or you can go for a more customized approach. I'll demonstrate the first technique in the NonAware example and the latter in the SendToDb example.

Mimicking Delphi Data-Aware Controls

To build an application that doesn't use data-aware controls but behaves like a standard Delphi application, you can write event handlers for the operations that would be performed automatically by data-aware controls. Basically, you need to place the dataset in edit mode as the user changes the content of the visual controls and update the field objects of the dataset as the user exits from the controls, moving the focus to another element.

Tip 

This approach can be handy for integrating a control that's not data aware into a standard application.

The other element of the NonAware example is a list of buttons corresponding to some of the buttons in the DBNavigator control; these buttons are connected to five custom actions. I could not use the standard dataset actions for this example because they automatically hook to the data source associated with the control having the focus—a mechanism that fails with the example's non-data-aware edit boxes. In general, you could also hook a data Source with each of the actions' DataSource property, but in this specific case we don't have a data source in the example.

The program has several event handlers I haven't used for past applications using data-aware controls. First, you have to show the current record's data in the visual controls (as in Figure 13.14) by handling the OnAfterScroll event of the dataset component:

procedure TForm1.cdsAfterScroll(DataSet: TDataSet);
begin
  EditName.Text := cdsName.AsString;
  EditCapital.Text := cdsCapital.AsString;
  ComboContinent.Text := cdsContinent.AsString;
  EditArea.Text := cdsArea.AsString;
  EditPopulation.Text := cdsPopulation.AsString;
end;
Click To expand
Figure 13.14:  The output of the NonAware example in Browse mode.The program manu-ally fetches the data every time the current record changes.

The control's OnStateChange event handler displays the table's status in a status bar control. As the user begins typing in one of the edit boxes or drops down the combo box list, the program sets the table to edit mode:

procedure TForm1.EditKeyPress(Sender: TObject; var Key: Char);
begin
  if not (cds.State in [dsEdit, dsInsert]) then
    cds.Edit;
end;

This method is connected to the OnKeyPress event of the five components and is similar to the OnDropDown event handler of the combo box. As the user leaves one of the visual controls, the OnExit event handler copies the data to the corresponding field, as in this case:

procedure TForm1.EditCapitalExit(Sender: TObject);
begin
  if (cds.State in [dsEdit, dsInsert]) then
    cdsCapital.AsString := EditCapital.Text;
end;

The operation takes place only if the table is in edit mode—that is, only if the user has typed in this or another control. This behavior is not ideal, because extra operations are done even if the edit box's text didn't change; however, the extra steps happen fast enough that they aren't a concern. For the first edit box, you check the text before copying it, raising an exception if the edit box is empty:

procedure TForm1.EditNameExit(Sender: TObject);
begin
  if (cds.State in [dsEdit, dsInsert]) then
    if EditName.Text <> '' then
      cdsName.AsString := EditName.Text
    else
    begin
      EditName.SetFocus;
      raise Exception.Create ('Undefined Country');
    end;
end;

An alternative approach for testing the value of a field is to handle the dataset's BeforePost event. Keep in mind that in this example, the posting operation is not handled by a specific button but takes place as soon as a user moves to a new record or inserts a new one:

procedure TForm1.cdsBeforePost(DataSet: TDataSet);
begin
  if cdsArea.Value < 100 then
    raise Exception.Create ('Area too small');
end;

In each case, an alternative to raising an exception is to set a default value. However, if a field has a default value, it is better to set it up front, so a user can see which value will be sent to the database. To accomplish this, you can handle the dataset's AfterInsert event, which is fired immediately after a new record has been created (I could have used the OnNewRecord event, as well):

procedure TForm1.cdsAfterInsert(DataSet: TDataSet);
begin
  cdsContinent.Value := 'Asia';
end;

Sending Requests to the Database

You can further customize your application's user interface if you decide not to handle the same sequence of editing operations as in standard Delphi data-aware controls. This approach allows you complete freedom, although it might cause some side effects (such as limited ability to handle concurrency, which I'll discuss in Chapter 14).

For this new example, I replaced the first edit box with another combo box and replaced all the buttons related to table operations (which corresponded to DBNavigator buttons) with two custom buttons that get the data from the database and send an update to it. Again, this example has no DataSource component.

The GetData method, connected to the corresponding button, gets the fields corresponding to the record indicated in the first combo box:

procedure TForm1.GetData;
begin
  cds.Locate ('Name', ComboName.Text, [loCaseInsensitive]);
  ComboName.Text := cdsName.AsString;
  EditCapital.Text := cdsCapital.AsString;
  ComboContinent.Text := cdsContinent.AsString;
  EditArea.Text := cdsArea.AsString;
  EditPopulation.Text := cdsPopulation.AsString;
end;

This method is called whenever the user clicks the button, selects an item in the combo box, or presses the Enter key while in the combo box:

procedure TForm1.ComboNameClick(Sender: TObject);
begin
  GetData;
end;
   
procedure TForm1.ComboNameKeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then
    GetData;
end;

To make this example work smoothly, at startup the combo box is filled with the names of all the countries in the table:

procedure TForm1.FormCreate(Sender: TObject);
begin
  // fill the list of names
  cds.Open;
  while not cds.Eof do
  begin
    ComboName.Items.Add (cdsName.AsString);
    cds.Next;
  end;
end;

With this approach, the combo box becomes a sort of selector for the record, as you can see in Figure 13.15. Thanks to this selection, the program doesn't need navigational buttons.

Click To expand
Figure 13.15:  In the SendToDb example, you can use a combo box to select the record you want to see.

The user can also change the values of the controls and click the Send button. The code to be executed depends on whether the operation is an update or an insert. You can determine this by looking at the name (although with this code, a wrong name can no longer be modified):

procedure TForm1.SendData;
begin
  // raise an exception if there is no name
  if ComboName.Text = '' then
    raise Exception.Create ('Insert the name');
   
  // check if the record is already in the table
  if cds.Locate ('Name', ComboName.Text, [loCaseInsensitive]) then
  begin
    // modify found record
    cds.Edit;
    cdsCapital.AsString := EditCapital.Text;
    cdsContinent.AsString := ComboContinent.Text;
    cdsArea.AsString := EditArea.Text;
    cdsPopulation.AsString := EditPopulation.Text;
    cds.Post;
  end
  else
  begin
    // insert new record
    cds.InsertRecord ([ComboName.Text, EditCapital.Text,
      ComboContinent.Text, EditArea.Text, EditPopulation.Text]);
    // add to list
    ComboName.Items.Add (ComboName.Text)
  end;

Before sending the data to the table, you can do any sort of validation test on the values. In this case, it doesn't make sense to handle the events of the database components, because you have full control over when the update or insert operation is performed.


 
Previous Section Next Section


 


 

.  |


Copyright © 2004-2016 "Delphi Sources". Delphi Programming Guide
     Twitter     Facebook