After a relatively unexciting look at Delphi database architecture, you can move on to the more interesting task of building a database application. The first step in that task is to learn how to create database forms, so that's today's subject.
You'll learn how to create database forms using the Delphi Database Form Wizard. You'll also learn how to build database forms from scratch. Toward the end of the day, you will learn about the data components of Delphi. These are the components that display the data from a database and enable you to edit that data--you can find them on the Data Controls tab of the Component palette. They are often referred to as data-aware components. I'll just call them data components in this chapter. Let's get to it.
The Delphi Database Form Wizard provides a way of creating database forms quickly and easily. Using this wizard, you can create a database form from start to finish. You don't have to place any database components on the form. You just start the wizard and let the wizard take it from there.
NOTE: No automated process is good enough to be all things to all people. I won't pretend that the forms created by the Database Form Wizard will be everything you want or that the Database Form Wizard will do all your work for you. What the Database Form Wizard can do, though, is the initial work of setting up a database form. After the initial work is done, you can go to work customizing the form to make it look the way you want.
The Database Form Wizard enables you to create both simple forms and master/detail forms. It enables you to choose whether your dataset will be a TTable or a TQuery. The wizard enables you to select a database table and to select the fields from that table that you want displayed on the form. It gives you a choice of layout options as well. After you supply the Database Form Wizard with all the information it needs, it creates the new form for you.
To start the Database Form Wizard, choose Database | Form Wizard... from the Delphi main menu. Alternatively, you can start the Database Form Wizard from the Business page of the Object Repository.
First I'll show you how to create a simple form, and then I'll talk about master/detail forms.
When the Database Form Wizard starts, it displays the page shown in Figure 17.1.
FIGURE 17.1. Page one of the Database Form Wizard.
This page of the Database Form Wizard asks you to choose the type of database you want to create and the dataset type you would like to use. The Form Options section gives you the choice of creating a simple form (with a single dataset) or a master/detail form.
I talked briefly about master/detail tables yesterday in the section "Master/Detail Tables." I'll talk more about master/detail forms later today in the section "Creating a Master/Detail Form." The first page of the Database Form Wizard also enables you to select from either a TTable-based dataset or a TQuery-based dataset. For this exercise, the default settings for creating a simple form using a TTable dataset are what you want, so you can click the Next button to move on to the next page.
TIP: In some cases, you might want to implement data from more than one table on a single form but not use a master/detail relationship. The Database Form Wizard enables you to choose only from one table. What you can do, though, is run the Database Form Wizard and select the first table. Your form will be created. Change the names of the Table and DataSource components to something meaningful. Now run the Database Form Wizard again and choose the second table. When the form is displayed, select all the database components on the form and copy them to the Clipboard. Switch back to the first form, make some room on the form for the new components, and paste them from the Clipboard onto the form. Now remove the second form from the project, and you're all set.
The next page asks you to choose a table from which to obtain the data. The Drive or Alias name combo box enables you to choose a database name just as you do when setting the DatabaseName property for a dataset component at design time. It also enables you to choose a directory from which to select a table. For this example, choose the DBDEMOS alias. The tables available in the database will show up in the Table Name list box. Select the ANIMALS.DBF table. The Database Form Wizard now looks like the one in Figure 17.2. Click the Next button to go to the next page.
FIGURE 17.2. Selecting a table with the Database Form Wizard.
The third page of the Database Form Wizard asks you to choose the fields from the table that you want to include on the form. The Available Fields list box on the left shows the fields that are in the table you have selected. The Ordered Selected Fields list box on the right contains the fields that you want on your new form. Between the two list boxes are four buttons for adding or removing fields from the Ordered Selected Fields list box.
To add a field, click the field name in the Available Fields list box and click the > button. Add any fields you want with this method. You can select multiple fields and click the > button to add the selected fields. To add all fields in the table at one time, click the >> button.
TIP: You can double-click a field name to add that field to the Ordered Selected Fields list box or double-click it again to remove it from the list box.
After the fields have been added to the Ordered Selected Fields list box, you can change the order of the fields by drag and drop or by clicking the up and down arrow buttons below the list box. Figure 17.3 shows this page of the wizard. For now, add all the fields to the Ordered Selected Fields list box and click the Next button to move to the next page.
FIGURE 17.3. Page three of the Database Form Wizard, adding fields.
The next page of the Database Form Wizard dialog asks you how you want the components for each field arranged on the form. You have three layout choices:
Click each of the three radio buttons and watch the image to the left of the wizard as you select different options. The image changes to show you the layout for each choice. Select the radio button labeled Vertically and click the Next button to continue. Figure 17.4 shows this page of the wizard.
FIGURE 17.4. Selecting a layout style with the Database Form Wizard.
NOTE: When Delphi creates the database form, it chooses the component type that most closely matches the data type of the field that component represents. For example, a regular text field is represented by a DBEdit component, a memo field by a DBMemo component, and a BLOB image field by a DBImage component. Delphi makes a best guess as to the component type to place on the form for a given data type. You might have to edit the form to get exactly the component you want for a given field.
The next page asks where you want to place the labels for the fields relative to each data component. You can put the labels on top of the components or to the left. Notice that here, too, the image on the Database Form Wizard changes depending on which of the two options is currently selected. For now, choose the second option in order to place the labels on top of the components. Figure 17.5 shows this page of the Database Form Wizard.
FIGURE 17.5. This page enables you to place the labels.
NOTE: The page shown in Figure 17.5 appears only if you select the option for vertical component layout on the previous page of the Database Form Wizard.
The final page of the Database Form Wizard asks you to make two choices:
NOTE: If you choose to have Delphi create the new database form as the main form of the application, be aware that the existing main form will still be part of the application's project. You need to remove the old main form from the project if you don't want it anymore. To remove the old main form, click the Remove from Project button and remove the main form's unit (Unit1.pas for a default project).
I'll talk more about data modules tomorrow in the section "Working with Data Modules." For now, make certain that the Generate a Main Form check box is checked and that the Form Generation option is set to Form Only. Figure 17.6 shows the last page of the Database Form Wizard.
FIGURE 17.6. The last page of the Database Form Wizard.
Click the Finish button and the form will be created. The finished form looks like the one shown in Figure 17.7.
FIGURE 17.7. The finished form.
Notice in Figure 17.7 that the form contains a data component for each field that was selected and a label for each component. The label is capitalized because that's the way the field names are stored in this particular table. Notice that the top of the form contains a DBNavigator component so that you can browse the records of the table.
Now you are ready to click the Run button and see how the form works. When the application starts, the first record in the dataset is displayed. Use the buttons of the DBNavigator to move through the dataset. Keep in mind that you are working with live data at this point. You can edit a record by changing a value in one of the edit components. To save the changes to the database, click the Post button on the DBNavigator (the check mark). To cancel any changes to the record, click the Cancel button on the DBNavigator (the X button). When you post a record or move to another record, the changes are saved to the database.
Close the application and return to the Delphi IDE. Spend some time examining the components on the form and the components' properties. Later I am going to go over some of the data components, but for now just experiment a little.
NOTE: If you find yourself re-creating a database form over and over again, consider adding the form to the Object Repository. Forms in the Object Repository can be reused with just a few mouse clicks.
Next, you create a master/detail form using the Database Form Wizard. When creating a master/detail form, the first few pages of the wizard are nearly the same as when creating a simple form. Only the labels that describe your options are different. First, perform the following steps. After that, I explain the specifics of the Database Form Wizard that pertain to master/detail forms. Here goes:
Now you are presented with a page you haven't seen before in the Database Form Wizard. This page asks you to select the fields that will join the two tables:
NOTE: If you are paying attention, you might notice that this page of the Database Form Wizard looks almost identical to the Field Link Designer you saw on Day 16, "Delphi Database Architecture," when you set up a master/detail form by hand. Both perform the same task.
Figure 17.8 shows the Database Form Wizard after joining the two tables.
FIGURE 17.8. The two tables joined on the CustNo field.
NOTE: The page illustrated in Figure 17.8 is slightly different if you are using TQuery--instead of TTable--components for the datasets. Specifically, the Available Indexes combo box isn't present when using TQuery components. The reason this combo box isn't displayed when using TQuery components is that the join is created using SQL statements, and indexes are not used in the same way they are with TTable components.
Now Delphi creates the form, and you are ready to try your new creation. Click the Run button to run the program. Use the DBNavigator to move from record to record. You will notice that the customer name is displayed in the top part of the form and that all the orders for that customer are displayed in the table in the bottom part of the form. Figure 17.9 shows the master/detail application running.
FIGURE 17.9. Your new master/detail form in action.
TIP: If you want to see the SQL statements for a master/detail relationship, run the Database Form Wizard again, but this time choose TQuery components for the datasets. After the form has been created, click on each Query component and examine its SQL property.
The Database Form Wizard is a good tool for quickly laying out a form; it is particularly convenient for quick test programs. It will not be long, though, before you will need to custom-design your database forms. After you gain experience creating database forms, you might actually prefer to create your forms by hand rather than use the Database Form Wizard.
There isn't a lot to know about creating database forms by hand. You drop one or more datasets (Tables or Queries) on the form and a DataSource component for each dataset, and then place a component on the form for each field in the dataset that you want to view. Sounds easy enough, and it is.
Let's build a new form that approximates the form you created earlier in the section "Creating a Simple Form Using the Database Form Wizard." First, you lay the groundwork and start adding the data components. Perform these steps:
TIP: You can set the DataSource property quickly by double-clicking the value column next to the property in the Object Inspector. Delphi will cycle through the available DataSource components each time you double-click.
Your form now looks like Figure 17.10.
FIGURE 17.10. The form in the initial stages.
Now you need to add some data components to display the table's data. As you work through this exercise, you might want to refer to Figure 17.7 to see the result. Do the following:
Now your form looks like the one shown in Figure 17.11.
FIGURE 17.11. The form with the data components in place.
Now you need to set the size of the DBImage component. Although you can't always be sure that each image will be the same size in every database, you can be certain in this case. You might guess at the size of the bitmap, but a better solution would be to set the size with a live image in the component. That's easy enough to fix. Click on the Table component and set its Active property to True. The image for the first record in the table is displayed. Now you can size the DBImage as needed to match the bitmap size.
You have nearly completed the form, but there's one more thing you should do. To imitate the form that the Database Form Wizard created, you need to open the table when the form is created:
Table1.Open;
That's it. Your new form is finished. Click the Run button to test your new creation. It will behave exactly like the first form you created with the Database Form Wizard.
At this point, a quick look at the data components is in order. I'll give a brief overview of each component and highlight each one's key properties and methods. Most of the data components are derived from a standard component and have many of the properties associated with that type of component. I will discuss only the properties that are specific to the data version of each component.
All the data components have properties in common. For example, all the components have a DataSource property. This property is used to link a data component with a data source, which is itself linked to a dataset. You have been using the DataSource property a lot in the past couple of days, so you should have a good idea of how it works.
Most data components also have a DataField property. You use this property to hook the data component to a particular field in the dataset. You saw how the DataField property is used when you built a database form from scratch. When you hook a data component to a field in the dataset, the contents of that field are directly displayed in the data component. In the case of Tables (and Queries if the RequestLive property is True), this means that editing the data in the data control will result in changes to the data in the database.
Most data components also have a Field property. You use the Field property to gain access to a component's contents programmatically. For example, to change the contents of a DBEdit component, you can do the following:
NameEdit.Field.AsString := `Clown Fish';
You can also change the field's display characteristics or other TField properties through the Field property.
You can use the ReadOnly property to prevent the user from editing the data in a data component that enables editing (DBGrid and DBEdit, for example).
The DBGrid component displays a dataset in tabular, or spreadsheet, format. One of the most important properties of the DBGrid is the Columns property. This property enables you to change the number and order of the columns that appear in the grid. You can add, remove, and order columns using the Columns Editor.
To invoke the Columns Editor, right-click on the grid and choose Columns Editor from the context menu. You can also click the ellipsis button next to the Columns property in the Object Inspector. Using the Columns Editor, you can add columns, remove columns, and arrange the order of columns. For example, a dataset might contain a dozen fields, but you might want to view only half those fields in the DBGrid. Using the Columns Editor, you can hide the fields that you don't want to see.
NOTE: Don't confuse the DBGrid Columns property (modified with the Columns Editor) with the Table component's FieldDefs property (modified with the Fields Editor). The FieldDefs property of the Table component controls which columns are actually contained in the dataset. The Columns property only affects which fields are visible in the grid.
The DefaultDrawing property indicates whether VCL draws the cells in the grid or the grid cells are owner-drawn. If DefaultDrawing is False, you must respond to the OnDrawColumnCell and OnDrawDataCell events to provide drawing for the cells.
The Options property enables you to set the display and behavior options for the grid. Using this property, you can turn off column titles, allow or disallow column sizing, turn row and column lines on or off, and so on.
The TitleFont property enables you to set the font for the column titles. You use the Font property to set the font for the grid cells.
The DBGrid has only two public methods. When using an owner-drawn grid, you can call the DefaultDrawColumnCell and DefaultDrawDataCell methods to ask VCL to draw the cell for you. This is useful if you are owner-drawing particular columns but you want default drawing behavior for the rest of the columns.
The DBGrid component has several events, most of which pertain to cell editing and data navigation. I won't list the events here because it is obvious from their names what functions they perform.
The DBNavigator component enables the user to browse a dataset record by record. The navigator provides buttons for first record, next record, previous record, last record, insert record, delete record, edit record, cancel edits, post edits, and refresh. This component is nearly automatic in that most of the time all you have to do is drop it on the form, hook it to a DataSource, and forget about it.
The ConfirmDelete property, when set to True, causes a dialog box to be displayed whenever the user clicks the Delete button. You set the Hints property to True to enable fly-over hints for each button on the navigator. The VisibleButtons property is a set that enables you to control which buttons show up on the navigator. You can add or remove buttons at design time or runtime.
The DBNavigator has only one method of interest and one event. You can use the BtnClick method to simulate a button click on the navigator. You can use the OnClick event to detect a click on the navigator. You rarely have to use OnClick, however, because the navigator already knows what to do when its buttons are clicked.
The DBText component is the data-aware version of the standard Label component. It provides a way of displaying data from a field without enabling the user to modify the data. This component provides no database-specific properties, methods, or events other than those common to all data components.
The DBEdit component provides an edit control that is linked to a field in a dataset. You used a DBEdit earlier today when you created a database form from scratch. The DBEdit component, like the DBText component, doesn't have any database-specific properties, methods, or events other than those common to all data components.
The DBMemo is the data version of the standard Memo component. You can use this component to display data contained in database fields that contain large amounts of text. The AutoDisplay property controls whether the data in the dataset field is automatically displayed when the cursor changes to a new record.
When AutoDisplay is True, the data is automatically displayed. When AutoDisplay is False, the user must double-click the DBMemo to display the data (or press Enter when the control has focus). To force the memo to display its contents through code, you use a related method called LoadMemo. This method is appropriate only when AutoDisplay is False.
The DBImage component is used to display binary large object (BLOB) data that is stored in image format. DBImage isn't necessarily a read-only component. You can change an image by pasting an image from the Clipboard or by using the Picture property to load a file from disk. The following code will change the image at runtime:
DBImage1.Picture.LoadFromFile(`peregrine.bmp');
The main DBImage properties control how the image is displayed. They are described as follows:
Methods of the DBImage component include CutToClipboard, CopyToClipboard, and PasteFromClipboard. These methods do exactly what their names indicate.
The DBListBox component is, for the most part, a standard list box. What distinguishes it is that when the user selects an item in the list box, the selected item is written to the corresponding field in the dataset (set by the DataField property). To provide the strings the user can select from, you add strings to the Items property just as you do for a regular ListBox component. It is important to realize that the strings for the list box don't come from the database (that's what the DBLookupListBox is for).
The DBComboBox works in exactly the same way as the DBListBox except for the obvious differences between a list box and a combo box.
You use the DBCheckBox primarily to display the contents of a database field containing logical data (True/False, Yes/No, On/Off). Set the ValueChecked property to a string that should be used to check for a match against the contents of the field. For example:
In this case, if the associated field contains the value On, the DBCheckBox will be checked. If the field contains a value other than the one specified, the check box will not be checked. You can supply more than one value to check in the ValueChecked property. For example:
DBCheckBox1.ValueChecked := `On;Yes;True';
If the value of the associated field contains any one of these values, the check box will be checked. The ValueUnchecked property works in exactly the same way except that any values matching the contents of ValueUnchecked will cause the check box to be cleared (unchecked). When specifying values for both ValueChecked and ValueUnchecked, the check box state will be indeterminate (grayed check mark) for field values that don't match.
The DBRadioGroup component works much like the DBListBox and DBComboBox components. You supply the items for the radio group and when an item is selected, the value (text) associated with that radio button is written to the associated field in the database.
The Values property holds the current value of the field in the database. You can use the Values property to substitute the display string in the radio group box with a different string. For example, you might have a radio group box with radio buttons labeled Yearly, Quarterly, and Monthly. Your database, however, might store codes such as Y, Q, and M instead of the full names. Given that scenario, you could set the Values property (a string list) like so:
Y Q M
Now, when a radio button is selected, the one-letter code will be written to the database field instead of the display string of the selected radio button. If the Values property is empty, the display string of the radio button will be written to the database when a radio button is clicked.
The DBLookupListBox component enables you to display a list of field values from a lookup field. Unlike the DBComboBox component, the list isn't provided by you; it is provided by a separate dataset. Set the DataSource and DataField properties to the dataset and field where the selection will be written. Set the ListSource and ListField properties to the lookup field from which the list should be populated.
The DBLookupComboBox works just like the DBLookupListBox. In addition, the DropDownAlign, DropDownRows, and DropDownWidth properties control how the drop-down list appears.
The DBRichEdit component enables you to display and edit a rich text memo field in a dataset. The AutoDisplay property and LoadMemo methods of this component work exactly as they do for the DBMemo component.
DBCtrlGrid is a component that enables you to create custom scrollable grid components. You can place any data components you want on the first cell of the DBCtrlGrid (or any other components for that matter), and Delphi will duplicate those components for each record in the dataset.
An illustration helps this explanation make more sense. Figure 17.12 shows a form containing a DBCtrlGrid component that has been aligned so that it fills the form's client area. The DBCtrlGrid contains a DBEdit, a DBMemo, and a DBImage. All the data components are placed on the first cell of the grid. The second cell contains a hatch pattern to tell you that you can't place components on that cell. Figure 17.13 shows the same form when the application is running.
FIGURE 17.12. A form at design time containing a DBCtrlGrid component.
FIGURE 17.13. The same form at runtime.
The DBCtrlGrid has a few properties worth mentioning. You use the Orientation property to determine where the scrollbar is to be placed and how the component acts when the scrollbar is clicked (the DBCtrlGrid in Figures 17.12 and 17.13 has the Orientation set to goHorizontal). You use the PanelWidth and PanelHeight properties to set the width and height of a cell in the grid. The RowCount property determines how many records to show at one time.
The DBCtrlGrid component has one event, OnPaintPanel. This event is fired each time a grid cell needs painting. You can respond to this event in order to draw on the background of the panel. This pertains only to the panel's background. Any controls on the grid will be painted automatically, so you don't have to worry about them.
DBChart is a charting component included with the Professional and Client/Server versions of Delphi. This component is not only powerful, but also complex. I can't begin to explain everything the DBChart component does, so you'll have to experiment with it to discover all that it is capable of.
The Client/Server version of Delphi includes a tab named Decision Cube that contains six additional components. These components enable you to do complex data analysis such as cross tabulation of tables and graphs, drill down, pivot, and aggregation. A discussion of these components wouldn't be productive here, but I want you to be aware that these components exist in the Client/Server version of Delphi.
Well, that about sums up the art of building database forms. (Actually, I'm being facetious because I've just scratched the surface of database form creation and design.) Use the Database Form Wizard for quick and easy database forms. Create database forms from scratch for more flexibility. Either way you go, building good database forms takes time and experience to master. It isn't something that you can be great at overnight. On the other hand, it isn't terribly difficult, either. Keep working at it and you'll be a database whiz in no time. The important thing is knowing the data components available to you as you build your forms.
The Workshop contains quiz questions to help you solidify your understanding of the material covered and exercises to provide you with experience using what you have learned. You can find the answers to the quiz questions in Appendix A, "Answers to the Quiz Questions."
Q My database contains a number of large images in BLOB fields, and it seems to take a long time to display the images. Is there something I can do to make the images draw faster?
© Copyright, Macmillan Computer Publishing. All rights reserved.