Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
92
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

Special Pointers and Their Use

return(0);

}

void PullDown(

char * szMenu[],

int

nColumn,

void (__cdecl *pFunctions[])(void))

{

 

int

i;

int

nMenuItem = -1;

char

chEntered;

for (i = 0; szMenu[i]; i++)

{

printf(MOVE_CURSOR, i + 1, nColumn); printf(szMenu[i]);

}

while (nMenuItem < 0)

{

chEntered = (char)getch();

if (chEntered == '\0' || chEntered == '\xE0')

{// PC Extended character (function key etc.) chEntered = (char)getch();

}

chEntered = (char)_toupper((int)chEntered);

/* find the correct menu item index */

if (isalnum((int)chEntered))

{

for (i = 0; szMenu[i]; i++)

{

C C C

C4C C

C C C

continues

125

Part I • Honing Your C Skills

Listing 4.4. continued

if (strchr(szMenu[i], chEntered))

{

nMenuItem = i; break;

}

}

}

 

if (nMenuItem >= 0)

 

{

 

pFunctions[nMenuItem]();

 

}

 

}

}

 

void

DoFilesNew()

{

printf(MOVE_CURSOR, 20, 10);

printf("Files, new");

printf(MOVE_CURSOR, 24, 10);

printf("Any key to continue");

(void)getch();

}

 

void

DoFilesOpen()

{

 

/*

Presents to the user a simple get a filename dialog box,

*

enabling character string to be

entered. Basic editing supported.

*/

 

 

int

i;

 

/*

These hard-coded constants, for

placement of dialog box,

*

normally would be passed.

 

126

Special Pointers and Their Use

*/

 

 

int

nColumn = 15;

 

int

nRow = 15;

 

int

nInputColumn = 2;

 

int

nInputRow = 4;

 

char

szFileName[132];

 

char

*szFilesOpen[] = {

 

"ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¿",

"3

 

3",

"3Enter the name of the file to open:

3",

"3

 

3",

"3

........................................

3",

"3 3", "АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ", NULL};

for (i = 0; szFilesOpen[i]; i++)

{

printf(MOVE_CURSOR, i + nRow, nColumn); printf(szFilesOpen[i]);

}

printf(MOVE_CURSOR, nInputRow + nRow, nInputColumn + nColumn);

scanf("%s", szFileName);

printf(MOVE_CURSOR, 24, 10);

printf("NAME: '%s' Any key to continue", szFileName);

(void)getch();

}

void DoFilesClose()

{

printf(MOVE_CURSOR, 20, 10);

printf("Files, close selected");

C C C

C4C C

C C C

continues

127

Part I • Honing Your C Skills

Listing 4.4. continued

printf(MOVE_CURSOR, 24, 10);

printf("Any key to continue");

(void)getch();

}

void DoFilesSave()

{

printf(MOVE_CURSOR, 20, 10);

printf("Files, save selected");

printf(MOVE_CURSOR, 24, 10);

printf("Any key to continue");

(void)getch();

}

void DoFilesSaveAs()

{

printf(MOVE_CURSOR, 20, 10);

printf("Files, save as selected");

printf(MOVE_CURSOR, 24, 10);

printf("Any key to continue");

(void)getch();

}

void DoFilesPrint()

{

printf(MOVE_CURSOR, 20, 10);

128

Special Pointers and Their Use

C C C

 

C4C

 

C C C

 

C

printf("Files, print selected");

printf(MOVE_CURSOR, 24, 10);

printf("Any key to continue");

(void)getch();

}

void DoFilesEXit()

{

printf(MOVE_CURSOR, 20, 10);

printf("Files, exit selected");

exit(0);

}

void MenuBar()

{

/* This function is never called! */

}

MENU1.C is the most complex program this book has discussed. It shows several important features, including passing an array of function pointers and using screen control and—of course—menus.

One of the first things you do in MENU1 is define some string identifiers. These identifiers are used to format the menu items, position the cursor, and perform other screen-management functions:

/* ANSI.SYS screen control #define's below: */

#define BOLD

"\x1B[1m"

#define NORMAL

"\x1B[0m"

#define

RED

"\x1B[31m"

#define

BLACK

"\x1B[30m"

129

Part I • Honing Your C Skills

#define GREEN

"\x1B[32m"

#define

CLEAR_SCREEN "\x1B[2J"

#define

CLEAR_EOL

"\x1B[K"

#define MOVE_CURSOR "\x1B[%d;%df"

Notice the identifier MOVE_CURSOR. Used with printf() and a set of integer parameters specifying cursor row and column, you can position the cursor using the following statement:

printf(MOVE_CURSOR, 10, 20);

The definition of the program’s top menu bar makes heavy use of string constant concatenation and ANSI screen control.

char szTopBar[] = {/* Must be 80 characters long MAX. */ CLEAR_SCREEN

BOLD"F"NORMAL"iles "

BOLD"E"NORMAL"dit "

BOLD"V"NORMAL"iew "

BOLD"P"NORMAL"roject "

BOLD"R"NORMAL"un "

BOLD"D"NORMAL"ebug " CLEAR_EOL

};

The maximum true length of the screen’s title bar is equal to the screen’s width. Counting these characters can be difficult; if you remove the ANSI screen-control identifiers and the string concatenation quotes, however, you can see the length of the menu bar more easily.

After the top menu-bar string definition, you define for the Files menu a pulldown that offers a number of common operations:

char

 

 

*szFiles[] = {

 

 

"ЪДДДДДДДДДДДДДДД¿",

 

 

"

 

3"BOLD"N"NORMAL"ew

3",

 

 

 

"

 

3"BOLD"O"NORMAL"pen

3",

 

"

 

3"BOLD"C"NORMAL"lose

3",

 

"

 

3"BOLD"S"NORMAL"ave

3",

 

"

 

3save "BOLD"A"NORMAL"s

3",

 

 

 

"ГДДДДДДДДДДДДДДД´",

 

130

 

Special Pointers and Their Use

C C C

 

 

C4C

 

 

C C C

" "BOLD"P"NORMAL"rint

",

C

 

ДДДДДДДДДДДДДДД´",

 

 

" e"BOLD"X"NORMAL"it

",

 

ДДДДДДДДДДДДДДДÙ",

 

 

NULL};

 

 

After you know what the Files pull-down menu will contain, you then build the function pointer array. You first define the functions, and then the array, and then initialize it with the functions that perform each task.

void

DoFilesNew();

void

DoFilesOpen();

void

DoFilesClose();

void

DoFilesSave();

void

DoFilesSaveAs();

void

DoFilesPrint();

void

DoFilesEXit();

void

(*FilesFunctions[])(void) = {

 

MenuBar,

 

DoFilesNew,

 

DoFilesOpen,

 

DoFilesClose,

 

DoFilesSave,

 

DoFilesSaveAs,

 

MenuBar,

 

DoFilesPrint,

 

MenuBar,

 

DoFilesEXit,

 

MenuBar,

 

NULL

 

};

Notice that you have allowed the number of initializers to define how many elements are found in this array, and that you have set the final member to NULL so that you can test for the end of the array if necessary. Setting the last element of an array of pointers to NULL is a good idea because you don’t have to pass the length of the array to functions that use it.

Finally, just before you start the main() function, you define the function that controls the pull-down menus. This function’s prototype is

void PullDown(char **, int, void (__cdecl **)(void));

131

Part I • Honing Your C Skills

Notice how an array of pointers (usually written as *array[]) is described as an array of pointers to pointers (type **). This description is necessary because you don’t specify the name of the actual array in this prototype. The array of function pointers must be specified with both the return values and parameters. In this program, both are simply void.

The main program has just a large loop that reads the keyboard and processes the characters. This program uses getch() to get a character (without echoing it to the screen); because this program runs on a PC, you test (and process) special keypresses, such as the function keys. Other computers with different keyboards may require some other changes to this part of the program.

while (1)

{

printf(szTopBar);

chEntered = (char)getch();

if (chEntered == '\0' || chEntered == '\xE0')

{// PC Extended character (function key etc.) chEntered = (char)getch();

}

After a character is read in, it is converted to uppercase (so that it can be tested), and then you use a case statement to find which of the top bar menu items has been selected.

switch (_toupper((int)chEntered))

{

case 'F':

PullDown(szFiles, 1, FilesFunctions); break;

case 'E':

printf("Edit submenu called" CLEAR_EOL); break;

case 'V':

printf("View submenu called" CLEAR_EOL); break;

132

Special Pointers and Their Use

C C C

 

C4C

 

C C C

 

C

case 'P':

printf("Project submenu called" CLEAR_EOL); break;

case 'R':

printf("Run submenu called" CLEAR_EOL); break;

case 'D':

printf("Debug submenu called" CLEAR_EOL); break;

default:

printf("Invalid key!" CLEAR_EOL); break;

}

When a top bar menu item is selected (Files in this example), the PullDown() function is called. This generic function is provided with the starting column for the pull-down menu (the starting row is always 2), an array of char pointers pointing to each menu item, and an array of function pointers pointing to the functions that will be called when a specific menu item is called. Except for Files, none of the top menu items are implemented.

PullDown() has the code to display the pull-down menu. A better program would save the screen at the location where the pull-down menu is displayed and restore it when the function returns; this simple program, however, doesn’t “clean up” after itself well:

for (i = 0; szMenu[i]; i++)

{

printf(MOVE_CURSOR, i + 2, nColumn); printf(szMenu[i]);

}

The menu items are printed, one to a line, until the end of the list (signified by the NULL pointer) is encountered. After the pull-down menu is displayed, you read the keyboard until a valid key is pressed, and then perform the requested action. Because this is a simple program, you again require the user to select a menu item before you let the user return to the main menu.

133

Part I • Honing Your C Skills

while (nMenuItem < 0)

{

chEntered = (char)getch();

if (chEntered == '\0' || chEntered == '\xE0')

{// PC Extended character (function key etc.) chEntered = (char)getch();

}

chEntered = (char)_toupper((int)chEntered);

/* find the correct menu item index */

if (isalnum((int)chEntered))

{

for (i = 0; szMenu[i]; i++)

{

if (strchr(szMenu[i], chEntered))

{

nMenuItem = i; break;

}

}

}

To check the keys pressed by the user, you get the character pressed, convert it to uppercase, and then scan each menu item for the key character. Because each menu item is allowed only one capitalized character (the desired character for this action), you can use strchr() to look at each of the menu lines. If no match is found, you wait for the user to press a new key; if a match is found, you call the appropriate function:

if (nMenuItem >= 0)

{

pFunctions[nMenuItem]();

}

}

Calling the correct function is as easy as indexing the array of function pointers.

MENU1 is a relatively crude program, yet it exceeds 300 lines of source code and doesn’t do anything. Remember my comments about reinventing the wheel at the beginning of the chapter? Now you can see why. I could write this program (and make

134