• No se han encontrado resultados

The crosstalk between CYB5R3 overexpression and caloric restriction in transgenic mice

Whilst we cannot here discuss all the aspects of Delphi OOP and visual program-ming, we can at least cover those features that will be of most relevance to us as far as DSP is concerned. In other words, we will adopt a pragmatic rather than a strictly scientific approach to the subject. Now some computing purists might frown at this, but let us not worry too much about that; we only have limited space to discuss high-level programming in a meaningful way, so we need to arrive at the core of the matter as quickly as possible. If you look on the CD that accompanies this book, there is a folder called Applications for Chapter 3\Tutorial Program\

where you will find a project called Tutorial_project.dpr, and its accom-panying application, Tutorial_project.exe. This is the main application to which we will refer throughout most of the rest of this chapter, because it includes many key features and functions that DSP programmers will have recourse to at some stage.

Figure 3.5 The main user interface of the application Tutorial_project.exe When running, Tutorial_project.exe might typically appear as shown in Figure 3.5.

Now this program can do many things – for example, it can calculate trigonometric functions, generate random numbers, save and open files in various formats, process binary values, generate program objects, and even graph simple functions and produce animated displays. Some of these things it does well, and some it does inefficiently – deliberately so. In programming, there are usually many possible ways of accom-plishing a given task, but not that many efficient ones, so it is good to be able to spot the difference. All of the program’s functions we will learn in due course, but before we go on, it is a good idea at this stage to think a little about the subject of project planning.

3.6.1 Project planning

When planning a program, it is good practice to spend some time thinking about the global nature of the application, how the routines or modules will perform their various tasks and how they will interact with both themselves and the user. This stage is always done best as far away as possible from a computer, perhaps using a pencil and paper to sketch out your ideas. Some exponents of programming also believe the visual user interface should be designed last, but this author does not agree with this;

in visual programming, the appearance of the program is inextricably linked with the functionality. What many programmers find is that the logical structure of a program is greatly facilitated if the general visual appearance of the program is established at an early stage of the development cycle; in other words, the logic of the program

Figure 3.6 The main form of Tutorial_project, called Tutorial Project, shown in design view

framework is a natural consequence of the logic of the appearance. Again, you should have a fairly well-structured idea of this even before you approach the computer. If you look again at Figure 3.5, you will see that the design is reasonably coherent and tidy, with close attention paid to the alignment of controls and other features. This may seem unimportant, but it is far from that. The effort you expend on this part of the project will, in general, be reflected in the effort you devote to the logical structure of the algorithms and code.

If Delphi is installed on your computer, you can open the project, Tutorial_project.dpr. The main form, entitled Tutorial Project, is shown in Figure 3.6 in design view.

The code for this main form is given in its entirety at the end of this chapter, as Listing 3.17. The line numbers that accompany the code are not produced by Delphi, but have been added here for ease of referencing.

3.6.2 Designing the user interface

As we saw in Section 3.5, components are added to a project by selecting them from the component palette with the mouse and placing them at their desired location on the form. Exact positioning of most components can be also be effected by altering the values of their left and top properties in the object inspector, or by using the

| Edit | Align…| menu. When a component is placed on the form, Delphi declares it automatically in the type declaration of that form. The main form of the program we are dealing with here, Tutorial Project, has many components, and so

the corresponding list in the form’s type declaration is equally long; if you study Listing 3.17, all the components we have added for the main form are declared between lines 18 and 102. Each component is given a name by Delphi with a numerical suffix according to its order of placement; standard buttons for example, are called Button1, Button2 and so on. It is a very good idea to change key component names using the object inspector to something meaningful, because it aids significantly in the understanding of your code when you revisit it in the future.

Each component is also associated with one or more methods, which are invoked by user or program events in relation to the object; as we have already said, these are also called event handlers. With buttons, the most common event is the OnClick type, that is, when the user clicks the button. With radio groups, which comprise a number of radio-style buttons, only one of which can be selected at any one time, the most common event is also OnClick (for examples of radio groups in Figure 3.5, see the areas designated as Data Generation, Processing and Record Tester). For scroll bars, it is the OnChange event. To produce code that will respond to the most commonly encountered event, simply double-click the component at design-time.

Immediately, Delphi generates the skeleton code for the event handler (method), and also declares this method in the form’s type declaration. All the programmer now has to do is to put code within the skeleton of the method to take appropriate action. Hence, when an event occurs associated with that component, corresponding method code will be executed in response. Again, looking at Listing 3.17, the various event-driven methods belonging to the components are declared between lines 103 and 130.

One event handler of special significance is the formcreate method, here commencing on line 318. The shell of this method is created automatically if the form itself is double-clicked. The method is only ever invoked once, when the program starts executing and the form is created. Hence, it is often used to initialise certain key variables that must be in a pre-defined state from the moment the program commences.

There is another way of generating the event handlers, other than by double-clicking the component (which only ever generates code for the most common handler). Select a component already located on the form by clicking it once. Now using the object inspector, select the Events tab. Here, you will see all the events associated with that component – for example, with buttons, the OnClick event is listed at the top. Double-click the entry cell for the event you want to handle. Imme-diately, Delphi creates the skeleton code of the event handler and also declares it in the form’s type declaration section, as we have seen. Once an event handler has been generated, its name appears in the object inspector’s event list. Figure 3.7, for example, shows the two events associated with a button called test_button. The first is for the standard OnClick event, but there is also one for the OnEnter event.

An OnEnter event occurs for a component when it becomes active (or receives the focus), for example, when it is selected by using the tab key.

If you look at Figure 3.5, or run Tutorial_project.exe, you will also see that the program has a menu. It is very easy to incorporate this facility into a Delphi application, by selecting the MainMenu component from the standard tab of the component toolbar. This component may be placed anywhere on the form that uses the menu (in this case the main form). Double-click the menu component to open the

Figure 3.7 Events for a typical button component

menu editor, and use the caption property of the object inspector in conjunction with the arrow keys to produce a menu comprising major headings with the various option lists as required. When this is complete, close the menu editor. A menu now appears on the form as you designed. To generate methods in response to events that occur when the user selects a menu item, simply double-click any of the items in the menu. Delphi again generates a skeleton method as it does for the other visual components, wherein you enter your code as required.

3.6.3 Major code modules of a Delphi application

In Section 3.4 we learned how a Delphi application always comprises the main program or project code, in this case Tutorial_project.exe, which is created by Delphi;

in general this should never be changed by the programmer. We also discovered that the application will also include a main form, that is, the visual interface with which the user of the application interacts. The code for the main form is called the main unit. Each additional form that the application may include (such as a dialog box), will also possess an associated unit. To repeat the point made earlier: all forms are accompanied by a unit, but a unit need not be accompanied by a form, since a unit is simply a code module. Figure 3.8 shows some possible combinations of these relationships.

In Figure 3.8 we see that in addition to the main form, secondary forms and their associated units, there are also present other non-visual units that are used,

Other unit Unit for main form

Main form

Unit for form 3 form 3

Other unit Delphi main project

Other unit Unit for form 2

form 2

Figure 3.8 Possible relationships between the project (main program), forms and units of a Delphi application. Each form is associated with a unit, but other units need not have forms, and may be associated with any other program modules

in turn, by form-units and themselves. The shell of a unit is created by using the Delphi main menu and selecting| File | New | Unit |. The unit called blank_form given in Listing 3.2 has, on close inspection, a standard structure. It comprises an interfacesection and an implementation section (both reserved words). All the action associated with procedures and functions appears in the implementation section, but unit, variable and type declarations may appear in either. This is important, because where they are declared has a bearing on how they behave and their visibility to other program modules associated with the project. One question we have not answered yet is: apart from the units associated with the various forms, why do we need other units? In other words, could we not simply include the code in the form-units? Strictly speaking, we could, but there is an important concept in programming called modularity. By partitioning a large program into a series of modular units, it not only makes the code more manageable, it also allows these units to be used by other programs if required, without rewriting the code. Below, we shall look in detail at the appropriate creation and use of units.

3.6.4 Global and local variables, arrays and constants

Before looking in detail at program structures and OOP, we need to think about how Delphi acts upon and stores data. We saw in Listing 3.4 how to declare some integer variables, but Delphi has many more data structures than these, which are used under different circumstances.

Variables, types and constants that are available only to the procedures and func-tions within a program unit are said to be local to that unit, and are declared towards the top of the unit in the implementation (line 141) section of the unit, outside any procedures, methods or functions. For example, in Listing 3.17, the variables are

Table 3.2 Some common Delphi Pascal variable types

Type Range Storage format

Integer −2,147,483,648..2,147,483,647 Signed 32-bit Cardinal 0..4,294,967,295 Unsigned 32-bit

Shortint −128..127 Signed 8-bit

Smallint −32,768..32,767 Signed 16-bit

Longint −2,147,483,648..2,147,483,647 Signed 32-bit

Int64 −263..263− 1 Signed 64-bit

Byte 0..255 Unsigned 8-bit

Word 0..65,535 Unsigned 16-bit

Longword 0..4,294,967,295 Unsigned 32-bit Real 5.0× 10−324..1.7× 10308 8 bytes Real48 2.9× 10−39..1.7× 1038 6 bytes Single 1.5× 10−45..3.4× 1038 4 bytes Double 5.0× 10−324..1.7× 10308 8 bytes Extended 3.6× 10−4951..1.1× 104932 10 bytes

Boolean True/false 1 byte

Char Single character 1 byte

String Character strings Variable bytes

declared between lines 157 and 168, and are preceded by the var reserved word.

So for example, the integer variable my_counter (line 165) may be used by any of the procedure and functions within this unit, but not any other units linked to this main unit. If you wish to make a variable global to a unit and all other units associated with it, the variable must be declared within the interface (line 9) section of the program, that is, here between lines 10 and 140.

In addition, we may also declare variables to be local to a procedure and function.

So, for example, on line 176 we declare the variable radians, which will be available only to the method called TForm1.data_genClick. To summarise, a variable may be declared as having one of three levels of access, that is, it may be:

1. local to a procedure or a function;

2. local to a unit, but globally available to the procedures and functions within that unit;

3. global to the unit and other units associated with the unit in which it is declared.

The most commonly encountered variables are reals, integers, strings and bytes.

Each requires a different number of bytes for storage; in addition, the programmer should be aware that there are rules governing the manner in which they may be used, both individually and in combination with one another. Table 3.2 provides a more complete list of the major variable types, together with their storage requirements.

It is also possible to process vector and matrices in Delphi by declaring single or multidimensional arrays of variables. On line 158 of Listing 3.17 for instance, we declare a multidimensional array called my_data comprising 3× 91 real elements.

Similarly, on line 167 we declare a one-dimensional array called my_labels comprising four elements of type tlablel (do not worry about the meaning of this type at the moment – we shall see how it is used later).

Sometimes, it is desirable to declare a constant, whose value does not change once assigned. This is performed using the const reserved word, an example of which is given on line 147, where, in this case, rad is set equal to 57.29577951.

It is also possible to declare other kinds of constants, such as array record, pointer and procedural constants. Array constants might typically look as shown in Listing 3.5:

const

bin : array[0..9] of word = (1,2,4,8,16,32,64,

128,256,512);

factorial: array[1..20] of real =(1,2,6,24,120,720, 5040,40320,362880,3628800,39916800, 4.790016e8,6.2270208e9,8.71782912e10, 1.307674368e12,2.092278989e13,

3.556874281e14,6.402373706e15, 1.216451004e17,2.432902008e18);

Listing 3.5

3.6.5 Types

One of the most powerful features of Delphi Pascal is that, even though it has a wide repertoire of variable types, we are not limited to these alone: we can create new, custom-designed variables, using the type statement. Take a look at Listing 3.18, lines 13–18. On line 13, we use the type reserved word to declare two new data types, bin_arrayand logic_type. Dealing with the latter type first, logic_type, we state that this may only take one of four possible values: anding, oring, leftingand righting. On line 18, we declare a variable called logic, of type logic_type. Thus, logic may only take one of these four values. In fact, this kind of variable is said to be an ordinal type. Formally, an ordinal type defines an ordered set of values in which each but the first has a unique predecessor and each but the last has a unique successor. Further, each value has an ordinality which determines its order. A value with ordinality n has a predecessor of ordinality n − 1 and a successor of ordinality n + 1.

Now consider bin_array. It does not appear in the variable declaration list of line 17, but instead is used within the procedural argument list on lines 23 and 24.

Here, bin_x and bin_y are both declared as variables of type bin_array. As we shall see later, variables declared in this way allow data to be exchanged between procedures (or functions) and the external code that invokes them.

3.6.6 Simple input and output

In general, a Delphi program interprets data entered by a user as strings of characters, not numbers. We have already seen an example of this in Section 3.5, when we produced the code for adder_form.pas. Here, components called edit boxes were used to both accept string data from the user and display it for output. To convert string data into equivalent numerical form (in order that it can be processed), we use the functions strtoint and strtofloat for integer and real values, respectively.

Conversely, to convert integer or real values into strings, we employ the functions inttostrand floattostr or floattostrf (floattostrf is similar to floattostrbut allows for more flexibility in the formatting).

The main form of Tutorial Project has a component called a string grid in the upper left corner. It is included in a group box entitled Array processing using real.

Figure 3.9(a) shows what it looks like at design-time, and Figure 3.9(b) shows the same component at run-time. (Note: the little icons covering part of the string grid in design view have got nothing to do with this component. They are also components belonging to the main form but have only been placed there for the sake of convenience. We will discuss these later.) If, when the program is running, you click on the radio button named Angles (0–90), the first two columns of the string grid are populated

a

b

Figure 3.9 (a) String grid at design-time. (b) String grid at run-time

with 91 angles expressed in degrees and radians, respectively. If instead, you select Random numbers, the first two columns are populated with 91 random numbers ranging between±0.5. Once either angles or random numbers have been generated, you can proceed to apply some basic processing on them, by selecting any option from the radio group entitled Processing. The first option, Clear all, simply wipes the contents of the string grid. The next three options, Sine, Cosine and Tangent, instruct the program to calculate the appropriate trigonometric identity of the second column, and place the result in the third. The final two options from the Processing group box allow either the vector sum or the product to be calculated, using the first two columns, again placing the result in the third. In order to discover how the program does all this, we need to understand how Delphi handles control and loop structures.

3.6.7 Radio groups, control and loops structures

The radio group entitled Data Generation: is here named data_gen. You can verify this by opening Tutorial_project.dpr, clicking on this radio group

The radio group entitled Data Generation: is here named data_gen. You can verify this by opening Tutorial_project.dpr, clicking on this radio group