Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

385

Описатель окна диалога, который является возвращаемым значением функции CreateDialog, хранится в глобальной переменной hDlgModeless и проверяется в цикле обработки сообщений так, как описано выше. Однако, в данной программе нет необходимости хранить описатель в глобальной переменной и проверять его значение перед вызовом функции IsDialogMessage. При этом цикл обработки сообщений мог бы быть написан так:

while(GetMessage(&msg, NULL, 0, 0))

{

if(!IsDialogMessage(hDlgModeless, &msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

Поскольку окно диалога создается до того, как в программе вводится цикл обработки сообщений, и окно диалога не закрывается до тех пор пока не завершится программа, значение hDlgModeless всегда будет корректным. Ниже приведен код, который может быть вставлен в оконную процедуру диалога, если вам захочется добавить возможность закрытия окна диалога:

case WM_CLOSE: DestroyWindow(hDlg); hDlgModeless = 0; break;

В программе COLORS1 функция SetWindowText отображала в текстовом виде значения трех целых, преобразованных в текст с помощью функции itoa. Это выглядело так:

SetWindowText(hwndValue[i], itoa(color[i]), szBuffer, 10));

Величина i соответствовала идентификатору обрабатываемой в данный момент полосы прокрутки, а массив hwndValue содержал описатели трех (по числу цветов) статических дочерних окон управления.

В новой версии, чтобы задать выводимое на экран число для каждого текстового поля каждого окна управления используется функция SetDlgItemInt:

SetDlgItemInt(hDlg, iCtrlID + 3, iColor[iIndex], FALSE);

(Хотя функция SetDlgItemInt и соответствующая ей функция GetDlgItemInt чаще всего используются в окнах редактирования, они также могут применяться для задания текстового поля и в других окнах элементов управления, например статических.) Переменная iCtrlID определяет идентификатор полосы прокрутки, а добавление 3 к этому числу превращает его в идентификатор соответствующей числовой метки. Третий параметр задает цвет. Обычно четвертый параметр устанавливается в TRUE, чтобы показать, что числа большие 32767 должны отображаться как отрицательные. Однако, в нашей программы диапазон значений от 0 до 255, поэтому величина четвертого параметра значения не имеет.

В процессе превращения программы COLORS1 в COLORS2 мы передаем Windows все больше и больше задач. В первой версии функция CreateWindow вызывалась десять раз; в новой версии по одному разу вызываются функции CreateWindow и CreateDialog. Но если вам кажется, что количество вызовов функции CreateWindow сведено к минимуму, загрузите с диска следующую программу.

Программа HEXCALC: обычное окно или окно диалога?

Возможно, вершиной программистской лени является программа HEXCALC, приведенная на рис. 11.9. В этой программе функция CreateWindow вообще не вызывается, нигде не обрабатываются сообщения WM_PAINT, нигде не получают контекста устройства и нигде не обрабатываются сообщения мыши. Несмотря на это, программа работает, представляя собой менее 150 строк исходного текста, и являясь шестнадцатеричным калькулятором, реализующим 10 функций, и имеющим законченный интерфейс клавиатуры и мыши. Окно программы калькулятора показано на рис. 11.10.

HEXCALC.MAK

#-----------------------

# HEXCALC.MAK make file

#-----------------------

hexcalc.exe : hexcalc.obj hexcalc.res

$(LINKER) $(GUIFLAGS) -OUT:hexcalc.exe hexcalc.obj hexcalc.res $(GUILIBS)

hexcalc.obj : hexcalc.c

$(CC) $(CFLAGS) hexcalc.c

386

hexcalc.res : hexcalc.rc hexcalc.ico $(RC) $(RCVARS) hexcalc.rc

HEXCALC.C

/*----------------------------------------

HEXCALC.C -- Hexadecimal Calculator

(c) Charles Petzold, 1996

----------------------------------------*/

#include <windows.h> #include <limits.h> #include <stdlib.h> #include <string.h> #include <ctype.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

 

static char

szAppName[] = "HexCalc";

HWND

hwnd;

MSG

msg;

WNDCLASSEX

wndclass;

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= DLGWINDOWEXTRA;

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(hInstance, szAppName);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH)(COLOR_WINDOW + 1);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szAppName;

wndclass.hIconSm

= LoadIcon(hInstance, szAppName);

RegisterClassEx(&wndclass);

hwnd = CreateDialog(hInstance, szAppName, 0, NULL);

ShowWindow(hwnd, iCmdShow);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

void ShowNumber(HWND hwnd, UINT iNumber)

{

char szBuffer[20];

SetDlgItemText(hwnd, VK_ESCAPE, strupr(ltoa(iNumber, szBuffer, 16)));

}

DWORD CalcIt(UINT iFirstNum, int iOperation, UINT iNum)

{

switch(iOperation)

{

case '=' : return iNum;

387

case '+' : return iFirstNum + iNum; case '-' : return iFirstNum - iNum; case '*' : return iFirstNum * iNum; case '&' : return iFirstNum & iNum; case '|' : return iFirstNum | iNum; case '^' : return iFirstNum ^ iNum; case '<' : return iFirstNum << iNum; case '>' : return iFirstNum >> iNum;

case '/' : return iNum ? iFirstNum / iNum : UINT_MAX; case '%' : return iNum ? iFirstNum % iNum : UINT_MAX; default : return 0;

}

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

 

static BOOL

bNewNumber = TRUE;

static int

iOperation = '=';

static UINT

iNumber, iFirstNum;

HWND

hButton;

switch(iMsg)

{

case WM_KEYDOWN : // left arrow --> backspace if(wParam != VK_LEFT)

break; wParam = VK_BACK;

// fall through

case WM_CHAR :

if((wParam = toupper(wParam)) == VK_RETURN) wParam = '=';

hButton = GetDlgItem(hwnd, wParam);

if(hButton != NULL)

{

SendMessage(hButton, BM_SETSTATE, 1, 0);

SendMessage(hButton, BM_SETSTATE, 0, 0);

}

else

{

MessageBeep(0);

break;

}

// fall through

case WM_COMMAND : SetFocus(hwnd);

if(LOWORD(wParam) == VK_BACK)

// backspace

ShowNumber(hwnd, iNumber /= 16);

else if(LOWORD(wParam) == VK_ESCAPE)

// escape

ShowNumber(hwnd, iNumber = 0);

 

else if(isxdigit(LOWORD(wParam)))

// hex digit

{

if(bNewNumber)

{

iFirstNum = iNumber; iNumber = 0;

}

bNewNumber = FALSE;

if(iNumber <= UINT_MAX >> 4)

388

ShowNumber(hwnd, iNumber = 16 * iNumber + wParam -

(isdigit(wParam) ? '0' : 'A' - 10));

else

MessageBeep(0);

}

else

// operation

{

if(!bNewNumber) ShowNumber(hwnd, iNumber =

CalcIt(iFirstNum, iOperation, iNumber));

bNewNumber = TRUE;

iOperation = LOWORD(wParam);

}

return 0;

case WM_DESTROY : PostQuitMessage(0); return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

HEXCALC.RC

/*----------------------------

HEXCALC.RC resource script

----------------------------*/

#include <windows.h>

HexCalc ICON hexcalc.ico

HexCalc DIALOG 32768, 0, 102, 122

STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX

CLASS "HexCalc"

 

 

 

CAPTION "Hex Calculator"

 

 

{

 

 

 

PUSHBUTTON "D",

68,

8,

24, 14, 14

PUSHBUTTON "A",

65,

8,

40, 14, 14

PUSHBUTTON "7",

55,

8,

56, 14, 14

PUSHBUTTON "4",

52,

8,

72, 14, 14

PUSHBUTTON "1",

49,

8,

88, 14, 14

PUSHBUTTON "0",

48,

8, 104, 14, 14

PUSHBUTTON "0",

27,

26,

4, 50, 14

PUSHBUTTON "E",

69,

26,

24, 14, 14

PUSHBUTTON "B",

66,

26,

40, 14, 14

PUSHBUTTON "8",

56,

26,

56, 14, 14

PUSHBUTTON "5",

53,

26,

72, 14, 14

PUSHBUTTON "2",

50,

26,

88, 14, 14

PUSHBUTTON "Back",

8,

26, 104, 32, 14

PUSHBUTTON "C",

67,

44,

40, 14, 14

PUSHBUTTON "F",

70,

44,

24, 14, 14

PUSHBUTTON "9",

57,

44,

56, 14, 14

PUSHBUTTON "6",

54,

44,

72, 14, 14

PUSHBUTTON "3",

51,

44,

88, 14, 14

PUSHBUTTON "+",

43,

62,

24, 14, 14

PUSHBUTTON "-",

45,

62,

40, 14, 14

PUSHBUTTON "*",

42,

62,

56, 14, 14

PUSHBUTTON "/",

47,

62,

72, 14, 14

PUSHBUTTON "%",

37,

62,

88, 14, 14

PUSHBUTTON "Equals",

61,

62, 104, 32, 14

PUSHBUTTON "&&",

38,

80,

24, 14, 14

PUSHBUTTON "|",

124,

80,

40, 14, 14

PUSHBUTTON "^",

94,

80,

56, 14, 14

PUSHBUTTON "<",

60,

80,

72, 14, 14

389

PUSHBUTTON ">",

62, 80, 88, 14, 14

}

HEXCALC.ICO

Рис. 11.9 Программа HEXCALC

Рис. 11.10 Окно программы HEXCALC

Программа HEXCALC — это обычный калькулятор с нефиксированной записью, использующий обозначение языка C для записи операций. Он работает с беззнаковыми 32-разрядными целыми и может выполнять сложение, вычитание, умножение, деление и определять остаток от деления; осуществлять поразрядные операции AND, OR и исключающее OR; сдвигать числа влево или вправо на один разряд. Деление на 0 приводит к результату

FFFFFFFF.

Для работы с калькулятором в программе HEXCALC можно использовать как мышь, так и клавиатуру. Начинать надо с ввода первого числа, щелкнув мышью над ним или набрав его на клавиатуре (до восьми шестнадцатеричных цифр), затем вводится знак операции и второе число. Вывести результат можно либо щелкнув мышью на кнопке Equals, либо нажав клавиши <Equals> или <Enter>. Для исправления ввода используется кнопка Back, либо клавиши <Backspace> или "Стрелка влево". Щелчок в окошке с результатом или нажатие клавиши <Esc> полностью стирает текущий результат.

Необычность программы HEXCALC состоит в том, что выводимое на экран окно кажется гибридом обычного перекрывающегося окна и немодального окна диалога. С одной стороны, все сообщения в программе HEXCALC обрабатываются в функции WndProc, которая, как кажется, является обычной оконной процедурой. Функция возвращает длинное целое число и обрабатывает сообщение WM_DESTROY и, как обычная оконная процедура, вызывает DefWindowProc. С другой стороны, окно создается в функции WinMain с помощью вызова функции CreateDialog, использующей шаблон окна диалога из файла HEXCALC.RC. Итак, что же представляет из себя программа HEXCALC, обычное перекрывающееся окно или немодальное окно диалога?

Ответ прост, он состоит в том, что окно диалога — это тоже окно. Обычно Windows использует свою собственную внутреннюю оконную процедуру для обработки сообщений всплывающего окна диалога. Затем Windows передает эти сообщения процедуре окна диалога внутри программы, создавшей окно диалога. В программе HEXCALC мы заставляем Windows для образования всплывающего окна применять шаблон окна диалога, но сообщения для этого окна мы обрабатываем сами.

Внимательное изучение файла HEXCALC.RC позволит обнаружить, как это делается. Начало шаблона окна диалога выглядит так:

HexCalc DIALOG 32768, 0, 102, 122

STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX

CLASS "HexCalc"

CAPTION "Hex Calculator"

Обратите внимание на использование идентификаторов, таких как WS_OVERLAPPED и WS_MINIMIZEBOX, которые можно было бы использовать и для создания обычного окна с помощью функции CreateWindow. Решающее отличие между нашим окном диалога и всем тем, что мы создавали до сих пор, заключено в

Соседние файлы в предмете Операционные системы