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

ООП_Лабораторный практикум

.pdf
Скачиваний:
79
Добавлен:
11.05.2015
Размер:
1.5 Mб
Скачать

3.Создаем простейшую программу под Windows.

Итак, создайте в любой IDE (Visual C++, C++ Builder) для C++ пустой проект типа Win32. В Visual C++, например, для этого нажимаем Ctrl+N, выбираем тип проекта Win32 Application, после чего нажимаем на Finish и OK (не меняя параметры по умолчанию), потом добавляем в проект *.cpp-файл. В файле введите следующий текст:

#include <windows.h>

LONG WINAPI WndProc(HWND, UINT, WPARAM,LPARAM); int WINAPI WinMain( HINSTANCE hInstance,

HINSTANCE hPrevInstance, LPSTR lpCmdLine,

int nCmdShow)

{

HWND hwnd; MSG msg; WNDCLASS w;

memset(&w, 0, sizeof(WNDCLASS)); w.style = CS_HREDRAW | CS_VREDRAW; w.lpfnWndProc = WndProc;

w.hInstance = hInstance;

w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); w.lpszClassName = "My Class";

RegisterClass(&w);

hwnd = CreateWindow("My Class", "My title", WS_OVERLAPPEDWINDOW, 300, 200, 200, 180, NULL, NULL, hInstance, NULL);

ShowWindow(hwnd,nCmdShow);

UpdateWindow(hwnd);

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

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)

{

switch (Message){ case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwnd, Message, wparam, lparam);

}

return 0;

}

Скомпилируйте и запустите программу

Рассмотрим функцию WinMain.

WinMain - это главная функция в Windows-приложениях. Именно с нее и начинается выполнение программы. Аналогичной функцией в консольных приложениях является функция main. Разумеется, функция WinMain должна быть ровно одна - не больше и не меньше.

71

ВWinMain передается 4 параметра. Первые два из них имеют тип HINSTANCE. Этот тип - это Windows-тип который означает экземпляр приложения. Первый параметр при этом содержит указатель (в смысле handle) на текущий экземпляр приложения, второй - всегда равен NULL. Ранее (в Windows 3.1) второй параметр содержал handle предыдущего запущенного экземпляра этого же приложения (например, если вы запускали второй экземпляр блокнота). Третий параметр представляет из себя указатель на строку, заканчивающуюся нуль-символом (стандартное представление строк в C/C++). Эта строка - это параметры командной строки, передаваемой в приложение. Параметры командной строки включают и имя программы. И, наконец, четвертый параметр определяет способ показа главного окна нашего приложения - т. е. показывать ли его развернутым на целый экран, или в нормальном виде, или в сложенном и др.

Втеле функции WinMain последовательно осуществляется несколько шагов. Сначала создается класс окна, потом его необходимо зарегистрировать в Windows, после чего создать на основе этого класса окно и отобразить его. На последнем этапе запускается цикл обработки сообщений (так называемый message pump).

Создание класса окна начинается с объявления переменной типа WNDCLASS:

...

WNDCLASS w;

...

Далее заполняются поля этой переменной (она имеет структурный тип). Так как большинство из них можно поставить в ноль, то сначала обнуляются все:

...

memset(&w, 0, sizeof(WNDCLASS));

...

апотом задаются остальные подходящие значения:

w.style = CS_HREDRAW | CS_VREDRAW; w.lpfnWndProc = WndProc;

w.hInstance = hInstance;

w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); w.lpszClassName = "My Class";

В этом блоке последовательно задается стиль окна, устанавливается, что переменная hInstance нашей структуры должна содержать handle на текущий экземпляр приложения (это первый параметр функции WinMain), установливается цвет фона и задали имя класса окна.

Далее класс регистрируется в системе Windows:

...

RegisterClass(&w);

...

После этого создается окно с помощью функции CreateWindow:

...

hwnd = CreateWindow("My Class", "My title", WS_OVERLAPPEDWINDOW, 300, 200, 200, 180, NULL, NULL, hInstance, NULL);

...

Параметры этой функции задают внешний вид окна. Она возвращает в качестве значения handle на созданное окно. Далее все операции с окном осуществляются через переменную handle. В частности, окно отображается и обновляется:

...

ShowWindow(hwnd,nCmdShow);

UpdateWindow(hwnd);

...

После того, как окно создано и отображено, запускается цикл обработки сообщений:

...

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

72

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

...

Окнонная процедура называется WndProc - это название произвольное. Основное предназначение оконной процедуры - обработка сообщений Windows. Например, при нажатии левой кнопки мыши программа получает сообщение Windows WM_LBUTTONDOWN, при изменении размеров окна программа получает сообщение WM_SIZE. В оконной процедуре и обрабатываются сообщения Windows. В нашей программе обрабатывается только одно сообщение Windows - WM_DESTROY. Это сообщение окно получает при своем уничтожении. Обратите внимание на ветку default:

...

default:

return DefWindowProc(hwnd, Message, wparam, lparam);

...

Здесь вызывается API-функцию DefWindowProc. Основное предназначение этой APIфункции - это обработка сообщений Windows, которые не обрабатываются в нашей программе (т. е. тех, для которых нет своего case). Если в программе отсутствует обработчик по умолчанию, то сообщения, не обрабатываемые программой, переполняют очередь В оконную процедуру передаются 4 параметра:

LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)

{

...}

Первый из этих параметров - это окно, в которое мы передаем сообщение Windows. Второй - это само сообщение. Третий и четвертый параметры - это дополнительные параметры для конкретного сообщения. Эти параметры будут разными для разных сообщений (и для некоторых сообщений Windows могут вообще не использоваться).

4.Функция MessageBeep

Функция MessageBeep служит для издания одного из стандартных звуковых сигналов Windows. Что за сигнал будет звучать, определяется единственным параметром этой функции, который может принимать следующие значения:

Значение

Описание звука

-1 или 0xFFFFFFFF

Звуковой сигнал через встроенный динамик компьютера.

MB_ICONEXCLAMATION

Восклицание (системный)

MB_ICONHAND

Предупреждение (системный)

MB_ICONQUESTION

Вопрос (системный)

MB_OK

Стандартный (системный)

MB_ICONASTERISK

Звездочка (системный)

Функция возвращает значение типа BOOL - если функция вызвалась успешно, то возвращается ненулевое значение, в случае неуспеха возвращается ноль.

Вот пример использования этой функции:

...

MessageBeep(0xFFFFFFFF); //Обычный звуковой сигнал.

...

5.Обработчик для левой кнопки мыши

Схема действий для добавления обработчика любого сообщения Windows следующая - добавляется соответствующая ветка в case оконной процедуры. В частности, если мы хотим,

73

чтобы наша программа обрабатывала нажатие левой кнопки мыши, то добавляется строка "case WM_LBUTTONDOWN:":

...

switch (Message){

//Если нажали на левую кнопку мыши, case WM_LBUTTONDOWN:

//то раздается звуковой сигнал.

MessageBeep(0xFFFFFFFF);

break;

...

}

6.Работаем с таймером

Для создания таймера используется функция SetTimer, для удаления - KillTimer. Созданный таймер будет посылать в вашу программу сообщение WM_TIMER.

Напишем программу, которая будет раз в секунду издавать звуковой сигнал. Для сего внесем следующие изменения в функцию WinMain:

...

SetTimer(hwnd, 1, 1000, NULL); while(GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

KillTimer(hwnd, 1);

...

Сначала создается таймер функцией SetTimer. Параметры: первый - это HWND окна, к которому таймер относится. Таймер всегда должен относится к определеному окну. Второй параметр - это идентификатор таймера. Ели необходимо создать еще один таймер, то для него задается другой идентификатор (например, 2). Третий параметр определяет, как часто наш таймер будет посылать сообщение WM_TIMER. Эта величина задается в миллисекундах. Значение 1000 означает, что таймер будет посылать сообщение WM_TIMER раз в секунду. Четвертый параметр задает функцию, которая будет обрабатывать сообщение WM_TIMER. Если этот параметр установлен в NULL, то обрабатывать будет оконная процедура (вернее сообщение отправится в очередь сообщений приложения).

Обратите внимание, где мы создаем таймер - в WinMain. Это потому, что мы хотим, чтобы таймер запускался сразу с нашей программой. Но можно его заводить и в другом месте - в оконной процедуре, например.

Нам осталось добавить обработчик для WM_TIMER в оконную процедуру. Это делается

так:

switch (msg){ case WM_TIMER: MessageBeep(-1); break;

Запускаем программу. Раз в секунду должен раздаваться звуковой сигнал.

7.Сообщение WM_TIMER.

Сообщение WM_TIMER отправляется таймером и имеет следующие дополнительные параметры:

74

wParam - идентификатор таймера, отправившего сообщение WM_TIMER (второй параметр функции SetTimer). Именно с помощью wParam вы можете определить, что за таймер послал сообщение (а таймеров в программе может быть несколько).

lParam - это указатель на CALLBACK-функцию, которая обрабатывает сообщение WM_TIMER. Такая функция будет выполняться, если при создании таймера функцией SetTimer ее четвертый параметр отличен от NULL - в записывается указатель на эту функциюобработчик.

Программа с двумя таймерами

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

...

//1-й таймер

SetTimer(hwnd, 1, 1000, NULL);

// 2-й таймер

SetTimer(hwnd, 2, 667, NULL); while(GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

KillTimer(hwnd, 1);

KillTimer(hwnd, 2);

Меняем оконную процедуру:

...

static bool b; switch (msg){ case WM_TIMER:

if(wparam==1){

//Обрабатываем сообщение от первого таймера

MessageBeep(-1);

}

else{

//Обрабатываем сообщение от второго таймера if(b){

SetWindowText(hwnd, "Title 1");

}

else{

SetWindowText(hwnd, "Title 2");

}

b=!b;

}

break;

}

...

8.Распространенные сообщения Windows

WM_LBUTTONDOWN. Посылается при нажатии левой кнопки мыши WM_LBUTTONUP. Посылается при отпускании левой кнопки мыши WM_RBUTTONDOWN. Посылается при нажатии правой кнопки мыши

75

WM_RBUTTONUP. Посылается при отпускании правой кнопки мыши WM_MOUSEMOVE. Посылается при движении мыши

WM_CHAR. Посылается при нажатии алфавитно-цифровой кнопки на клавиатуре WM_KEYDOWN. Посылается при нажатии любой кнопки на клавиатуре WM_KEYUP. Посылается при отпускании любой кнопки на клавиатуре WM_TIMER. Посылается таймером

WM_CREATE. Посылается при создании окна

WM_CLOSE. Посылается при закрытии окна (например, по Alt+F4) WM_DESTROY. Посылается при уничтожении окна WM_COMMAND. Посылается при выборе пункта меню WM_PAINT. Посылается для перерисовки окна

WM_SIZE. Посылается при изменении размеров окна

9.Функция MessageBox

Функция MessageBox предназначена для вывода стандартного окна сообщений.

Эта функция имеет несколько параметров. Первый определает то, к какому окну принадлежит наш MessageBox. При этом доступ к этому окну будет закрыт до тех пор, пока мы не закроем MessageBox. Если первый параметр поставить в NULL, то MessageBox не будет принадлежать никакому окну (и мы сможем переключиться на любое окно нашей программы).

Второй параметр функции MesageBox определяет, что за надпись появится в нем, третий же параметр определяет заголовок MessageBox'а.

Последний, четвертый параметр определяет совокупность свойств. Например, этим параметром вы можете задать, что за кнопки будут в MessageBox'е, какая из них будет кнопкой по умолчанию, что за картинка будет слева от сообщения, модальность окна.

Вот несколько констант, которые определяют, что за кнопки будут в MessageBox'е: MB_OK - только кнопка OK, MB_OKCANCEL - кнопки OK и Cancel, MB_YESNOCANCEL -

кнопки Yes, No и Cancel. Разумеется, есть и другие константы.

Пример констант, определяющих значок в MessageBox'е: MB_ICONQUESTION - вопросительный знак, MB_ICONEXCLAMATION - восклицательный знак, MB_ICONERROR - красный круг с белым крестом.

Константы, задающие кнопку по умолчанию: MB_DEFBUTTON1 - первая кнопка, MB_DEFBUTTON2вторая кнопка, MB_DEFBUTTON3 - третья кнопка. Возвращаемые значения: IDOK - для кнопки OK, IDCANCEL - для кнопки Cancel, IDIGNORE - для кнопки Ignore. Вот так, например, можно проверить, что нажата кнопка NO:

if(IDNO==MessageBox( hwnd,"Сохранить изменения?", "",MB_YESNO|MB_ICONQUESTION ) )

Пример с MessageBox для закрытия программы

На этом уроке мы посмотрим, что мы должны добавить в нашу программу для того, чтобы при закрытии появлялось стандартное окно сообщений с вопросом, надо ли из программы выходить. Если пользователь ответит Да, то программа закроется, если Нет, то не закроется.

Вот код, который необходимо добавить в оконную процедуру:

...

switch (Message){ case WM_CLOSE:

if(IDOK==MessageBox(hwnd,"Выходим?","",MB_OKCANCEL|MB_ICONQUESTION)) SendMessage(hwnd, WM_DESTROY, NULL, NULL);

break;

...

76

Упражнение 1. Создать в помощью WinAPI программу согласно полученному варианту.

Варианты:

 

а)

простое окно Windows;

б)

программу, подающую звуковой сигнал при нажатии левой клавиши мыши;

в)

программу, подающую звуковой сигнал при нажатии левой клавиши мыши;

г)

программу, использующую один таймер;

д)

программу, использующую два таймера;

е)

программу, показывающую сообщение при нажатии левой кнопки мыши;

ж) программу, показывающую сообщение при нажатии правой кнопки мыши;

з)

программу, показывающую сообщение при закрытии окна.

Часть 2. Обработка исключительных ситуаций (C++).

Исключения - возникновение непредвиденных ошибочных условий в момент работы программы. В то же время исключение - это более общее чем ошибка понятие, так как может возникать и тогда, когда в программе нет ошибок (например, сбой выделения памяти при создании объекта класса). В общем, исключение обозначает особую ситуацию, когда требуется безвозвратно переключить выполнение программы на блок обработки такой ситуации. Выявление особой ситуации производится только программным путём при помощи проверки нормального хода выполнения программы.

Средства обработки ошибочных ситуаций позволяют передать обработку исключений из кода, в котором возникло исключение, некоторому другому программному блоку, который выполнит в данном случае некоторые определенные действия. Таким образом, основная идея данного механизма состоит в том, что функция проекта, которая обнаружила непредвиденную ошибочную ситуацию, которую она не знает, как решить, генерирует сообщение об этом (бросок исключения). А система вызывает по этому сообщению программный модуль, который перехватит исключение и отреагирует на возникшее нештатное событие. Такой программный модуль называют «обработчик» или перехватчик исключительных ситуаций. И в случае возникновения исключения в его обработчик передаётся произвольное количество информации с контролем ее типа. Эта информация и является характеристикой возникшей нештатной ситуации.

Обработка исключений в C++ - это обработка с завершением. Это означает, что исключается невозможность возобновления выполнения программы в точке возникновения исключения.

Для обеспечения работы такого механизма были введены следующие ключевые слова: try - проба испытания;

catch - перехватить (обработать); throw - бросать.

Кратко рассмотрим их назначение.

Ключевое слово try открывает блок кода, в котором может произойти ошибка; это обычный составной оператор: try {

код

};

Код содержит набор операций и операторов, который и будет контролироваться на возникновение ошибки. В него могут входить вызовы функции пользователя, которые компилятор также возьмет на контроль.

Среди данного набора операторов и операций обязательно указывают операцию броска исключения throw, которая имеет следующий формат:

throw выражение',

где выражение определяет тип информации, которая и описывает исключение (например конкретные типы данных).

Обработчик исключения catch перехватывает информацию:

77

catch ( тип и параметр) { код }

Через параметр обработчику передаются данные определенного типа, описывающие обрабатываемое исключение. Код определяет те действия, которые надо выполнить при возникновении данной конкретной ситуации. В C++ используют несколько форм обработчиков. Рассмотренный обработчик получил название параметризованный специализированный перехватчик.

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

Кроме того, запрещены переходы как извне в обработчик, так и между обработчиками. Можно воспользоваться универсальным или абсолютным обработчиком: catch (...){ код

}

где (...) - означают способность данного перехватчика обрабатывать информацию любого типа. Такой обработчик располагают последним в пакете специализированных обработчиков. Тогда, если исключение не будет перехвачено специализированными обработчиками, то будет выполнен последний - универсальный.

Если не возникнет исключение, набор обработчиков будет обойден, т.е. проигнорирован. Если же исключение было «брошено» при возникновении критической ситуации, то будет вызван конкретный перехватчик при совпадении его параметра с выражением в операторе броска, т.е. управление будет передано найденному обработчику. После выполнения кода вызванного обработчика управление передается оператору, который расположен за

последним перехватчиком, или проект корректно завершает работу.

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

Блоки try как составные блоки могут быть вложены друг в друга. В случае возникновения исключения в некотором текущем блоке, поиск обработчика последовательно продолжается в блоках, предшествующих уровней вложенности с продолжением вызова деструкторов.

Пример обработки исключительных ситуаций. Функция Divide() возвращает частное от деления чисел, принимаемых в качестве аргументов (а, b), если делитель равен нулю (Ь = 0), то возникает исключительная ситуация.

#include <iostream.h> #include <conio.h>

double Divide(double, double); void main(void) {

double a, b, result;

cout « " Input a, b : " « endl; cin » a » b;

try{

result = Divide(a, b);

cout « " Nonnal Work " « endl;

cout « " a = " « a « ", b = " « b « endl; cout « " Ansver : " « result « endl; getch();

}

catch(double z) {

cout « " Division by zero... " « endl; cout « " b = " « z « endl;

78

getch();

}

}

double Divide(double al, double bl) { if (bl==0) throw b1;

return a1/b1;

}

Результаты выполнения программы, введя значения 1 и 2, получим: Input a, b :

1 2

Normal Work а=1, b = 2 Ansver : 0.5

А при вводе значений 1 и 0, получим: Input a, b :

1 0

Division by zero...

b = 0

Оператор throw сигнализирует об исключительном событии (попытку деления на ноль) и генерирует объект исключительной ситуации. В данном случае он находится внутри функции Divide(). Объект перехватывается обработчиком catch. Этот процесс, как уже известно, и называется вызовом исключительной ситуации. В рассмотренном примере исключительная ситуация имеет форму вещественной переменной - делителя.

Упражнение 2.

Общая постановка. Даны два выражения Z1 и Z2. Написать функции для вычисления этих выражений с организацией обнаружения нештатной ситуации (например деление на ноль) и ее обработки. Передача аргументов в функции - по ссылкам.

В случае успеха значения Z1 и Z2 должны быть приблизительно одинаковыми.

Варианты.

а)

z

=

2b +2

b2 4

, z

2

=

1

b2

4

+b +2

b +2

 

1

 

 

 

б)

z

=

x2

+2x 3 +(x +1) x2 9

, z

 

=

 

x +3

 

 

 

 

 

x2

2x

3 +(x 1) x2

9

 

 

x 3

 

 

 

 

 

 

1

 

 

2

 

 

 

 

 

 

 

в)

z = (3m +2)2 24m , z

2

 

= − m

 

 

 

 

 

 

 

 

 

 

 

1

 

 

3

m

2 m

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

г)

z =

a +

2

 

 

a

 

 

 

+

 

 

 

2

 

 

 

 

 

 

a 2

, z

 

=

 

1

 

 

 

2a

 

2a +

 

 

 

 

 

 

 

 

 

 

 

 

a +

2

 

 

+ 2

 

1

 

 

 

 

 

 

2 a

 

 

2a

 

 

2

a

 

 

 

 

1

+a +a

2

 

 

1

a

+a

2

 

 

 

2

), z2 =

4 a

2

 

 

д)

z1

=

 

 

+2

 

 

 

 

2a

 

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

 

2a +a

 

 

 

2a

a

 

 

(5

 

2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

е) z = (m 1) m (n 1) n , z

2

 

= m n

 

 

 

 

 

 

 

1

 

 

 

m3n +nm +m2 m

 

 

 

 

 

 

 

m

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ж)

z

=

 

2m +2

 

m2 4

 

, z

2

=

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

m + m2 4 +2

 

 

 

 

 

 

 

 

m +2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

79

з)

z

=

(x +1)

x2

9 + x(x +2)3

, z

 

=

x +3

(x 1) x2

9 + x2 2x 3

2

x 3

 

1

 

 

 

Контрольные вопросы.

1)Структура простейшей WinAPI программы.

2)Опишите схему действия любого обработчика событий Windows при получении сообщения.

3)Сообщение WM_TIMER, установка и удаление таймера.

4)Перечислите самые распространенные сообщения Windows.

5)Функция WinAPI MessageBox(…), описание её параметров.

6)Что называют исключением?

7)Что такое «блок с контролем»?

8)Дайте характеристику обработчику исключений. Какие бывают виды обработчиков?

9)Какие правила налагаются на соотношения между блоком контроля и обработчиками?

10)Чем отличается вызов обработчика от вызова обычной функции?

Литература.

1.Шилд Г. Программирование на Borland C++ для профессионалов. – МН.: ООО

“Попурри”, 1998.

2.Пол И. Объектно-ориентированное программирование с использованием С++. - Киев: НПИФ "ДиаСофт", 1995.

3.Круглински Д.и др. Программирование на Visual C++ 6.0 для профессионалов. –

Питер, 2004.

80