Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lek7.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
267.32 Кб
Скачать

1 /*&YtttnjMSt Onpalnt обработки сообщения wm_paint*/

void OnPaint(HWND hwnd){

RECT г; //Структура^ овпсывахщая координаты прямоугольники PAINTSTRUCT ps;11 Структура с характеристиками рабочей области HDC hdc=BeginPaint(hwnd,&ps);//Получение контекста устройства GetClientRecCthwnd,&r];//Получение координат рабочей области int i=0;//Номер читаемого слова в буфере и х-координата на экране wbilelti<500)bbDataOK) //Берем из буфера по одному слову до конца SetPixel(hdc,i,r.bottom-5-nBuf[i + + ],RGB(0, 0, 255)) ; //Вывод точки EndPaint (hwnd. Sips) ; }

/*#уяши» обработхн сообявняя W4_DE£TROY*/

void OnDestroy(HWNDI( Pos tQuitMessage(0); )

Исходные тексты приложения включают стандартный набор: заголовочный файл 6-6.Н с объявлениями символических констант и прототипов функций, файл ресурсов 6-6.RC с описанием простой линейки меню (единственное меню "Файл" с командами "Открыть" и "Выход") и, наконец, файл 6-6.СРР с исходным текстом программы.

Программа 6-4 выводит на экран содержимое указанного ей файла данных в виде то­чечного графика, в котором каждое данное отображается синей точкой, расстояние кото­рой от низа окна равно значению конкретного данного (рис. 6.31). Файл данных должен содержать набор из 500 целых коротких (двухбайтовых) чисел, не превышающих высоты главного окна в пикселах, чтобы график не вышел за пределы экрана. Для упрощения программы в ней не предусмотрено никаких средств анализа размера файла данных или

210 Win32. Основы программирования

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

ж 11 l i i_i i рлммя В ^

Файл

Рис. 6.31. Вывод точечного графика

При выборе пользователем пункта "Открыть" вызывается стандартный диалог Windows "Открытие файла" (рис. 6.32), обеспечивающий поиск требуемых файлов по всем дискам и каталогам. Предполагается, что пользователь заранее подготовил файлы с данными, подлежащими выводу на экран. После выбора файла он открывается, его со­держимое (500 коротких целых чисел) считывается в буфер программы и вызовом функ­ции InvalidateRectQ инициируется посылка в главное окно приложения сообщения Windows WM PAINT.

Открытие файла

Папка

И мя Файла: |Sp5.dat Тип Файлов: |фай™ данных!" DAT] Г" Только чтение

Р ис. 6.32. Стандартный диалог Windows "Открытие файла"

В функции обработки сообщения WMPAINT в цикле из 500 шагов просматривается содержимое буфера с данными и каждое данное выводится на экран в виде точки, обра­зуя графическое представление массива данных.

Г лава 6 Ресурсы: меню и диалоги

211

При повторном вызове стандартного диалога "Открытие файла" на экран выводится содержимое вновь выбранного файла; старый график при этом стирается.

Общая структура программы вполне очевидна. В оконной функции обрабатываются 3 сообщения Windows: WMCOMMAND, WMPAINT и WM DESTROY. Сообщение WMCOMMAND поступает в приложение при выборе пользователем одной из двух имеющихся команд меню. При выборе команды "Открыть" выполняются все необходи­мые действия по работе со стандартным диалогом "Открытие файла" и с самим файлом данных. При выборе команды "Выход" приложение закрывается обычным образом, вы­зовом функции Destroy Window(). Функция обработки сообщения WMPAINT обеспечи­вает вывод графика на экран.

Некоторое отличие от предыдущих примеров заключается в указании элемента стиля класса окна

we. з tyI e=CS_VREDRAW ;

Указание этой константы приводит к тому, что при каждом изменении размеров окна по вертикали Windows посылает в окно сообщение WMPAINT, которое приводит к пол­ной перерисовке всего окна (а не только области вырезки). Такой режим необходим в тех случаях, когда изображение в окне рисуется относительно его нижней границы, т. е, тре­буется, чтобы при перемещении по экрану нижней границы окна все изображение пере­мещалось вместе с ней. Если изображение рисуется относительно правой границы окна, то необходимо включать в стиль окна константу CS_HREDRAW; в этом случае окно бу­дет перерисовываться целиком при каждом изменении его размеров по горизонтали.

Для проверки работоспособности программы 6-4 необходимо подготовить файлы данных с разумным содержимым. Ниже приводится текст программы, позволяющей это сделать. В ней вычисляются значения функции у = ft», представляющей собой сумму спадающей экспоненциальной кривой d*ехр{-*/с2) и нормальной кривой Гаусса сЗ*ехр(-с4(х-с5)2). Подбором констант с!...с5 можно в широких пределах изменять фор­му получающейся кривой.

Разумеется, читатель может написать свою программу для вычисления значений лю­бой другой функции. Нужно только, чтобы в файле содержалось ровно 500 чисел и чтобы их значения не превышали размера нашего окна по вертикали.

/*флйл apectrs.cpp. Создание тестовых файлов данных*/

# incIude «windows,h>

#include <math.h>y / Ради ехр()

char fnamel]="spl.datг;//Имя создаваемого файла

short nBuftSO];//Массив с тестовыми данными для записи в файл

lilt WINAPI WinMairHHINSTANGE hlnst, HINSTANCE, LPSTR, inc) {

/*3аполиин массив тестовыми данными*/

Int Cl,c2,C3,c5;

tloat c4,x;

cl=200; C2=15O; c3=250r c4=0.01; C5=35O;

Eorfint i=0;i<500;i++){

x=i;/JПреобразуем счетчик цикла в число с плавающей точкой nBuf[il=cl*exp[-х/с2)+сЗ*ехр(-с4*(х-с5)*(х-с5)) ; //Вычисляем значения ) /•Создали» новий файл к запишем в него тестовой массив*/

HANDLE hFiIe=CreateFile(fname,GENERIC_WRITE,0,0,CREATE_ALWAYS,0,NULL >;

DWORD nCnt,- //Счетчик записанного

WriteFile(hFile,nBuf,2*500,bnCnt,NULL|,//Запись в файл

return О,-

)

2 12 Win32. Основы программирования

Стандартный диалог "Открытие файла"

Вывод на экран стандартного диалога Windows "Открытие файла" осуществляется вызовом функции GetOpenFileName(), для успешного выполнения которой необходимо подготовить структуру типа OPENF1LENAME (переменная ofn в программе). Эта струк­турная переменная объявлена в начале функции OnCommand() обработки сообщения WMCOMMAND от команд меню. Там же объявлена символьная строка-фильтр szFilter, в которую в определенном формате записываются строки, которые будут выведены в ок­но "Тип файлов" стандартного диалога, вместе с шаблонами спецификаций отбираемых файлов. В программе предусмотрена возможность показа файлов с расширением .DAT (шаблон *.dat), а также всех файлов (шаблон +.*). При желании список возможных типов имен файлов можно расширить. Элементы строки-фильтра разделяются двоичными ну­лями, которые в символьной строке обозначаются как \0. Двоичный нуль помешается также и в конец строки (которая, таким образом, завершается двумя нулями).

Структура ofn обнуляется, после чего некоторые элементы получают инициализи­рующие значения. Назначение большинства элементов структуры должно быть ясно из текста программы. В элемент ofti.lpstrFile записывается адрес буфера, куда функция GetOpenFileNameQ вернет полную спецификацию выбранного пользователем файла; принятое нами значение элемента ofn.Flags указывает, что при вводе пользователем не­правильного имени каталога или файла на экран будет выведено предупреждающее со­общение вида "Такого пути нет" или "Невозможно найти файл1*.

Функция GetOpenFileNameQ вызывается в операторе if, условный блок которого вы­полняется, только если функция GetOpenFileName() отработала успешно и в буфере szFile появилась законная спецификация выбранного файла. Это дает возможность пра­вильно завершить этот фрагмент программы и в том случае, когда пользователь, открыв стандартный диалог, затем закрыл его, так и не выбрав в нем файл,

Внутри условного блока выбранный файл открывается 32-разрядной функцией Сге-ateFileQ (это не опечатка - обобщенная функция CreateFileQ служит и для создания и для открытия файла) только для чтения {параметр GENERIC_READ). Эта функция требует в качестве параметров указатель на адрес буфера с именем файла и в случае успешного выполнения возвращает дескриптор файла типа HANDLE, который в дальнейшем будет служить для нас идентификатором данного файла (работа с файлами в 32-разрядных приложениях Windows будет подробнее описана в гл.] I). Если файл открыть не удалось, функция CreateFile() возвращает значение INVALID_HANDLE_VALUE, поэтому пред­ложение

if(hFile==INVALID_HANDLE_VALUE)break;

позволяет обойти все последующие строки, если по какой-то причине файл не был открыт.

Тридцатидвухразрядная функция ReadFtleQ читает из файла в буфер nBuf заданное количество байтов (500 данных по 2 байта), после чего файл закрывается функцией CloseHandlef).

После выполнения всех операций с файлом предложением

bDataOK=TRUE;

устанавливается флаг bDataOK, который говорит о том, что буфер nBuf заполнен данны­ми и, следовательно, есть что выводить на экран. В дальнейшем, в функции OnPaint(). вывод содержимого nBuf будет осуществляться, только если этот флаг установлен. Это полезная предосторожность, которая предотвратит вывод на экран "мусора" в ответ на первое сообщение WMPA1NT, которое поступает в приложение при открытии главного окна, когда буфер nBuf еще не заполнен. Правда, мы объявили nBuf глобальной пере-

Г лава 6. Ресурсы: меню и диалоги 213

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

Итак, буфер nBufзаполнен данными, которые надо вывести на экран. Однако, как было показано в гл. 5, вывод в окно любых изображении допустим только в ответ на со­общение WMPAINT, так как лишь в тгом случае при всяких естественных для Windows манипуляциях с окном (изменение размеров окна, свертывание его в пиктограмму и об­ратное развертывание, "вытаскивание" окна из-под других окон и т. д.) изображение в окне будет перерисовываться правильно. Если изображение в окне носит статический, неизменяемый характер, как это было в предыдущих примерах, то никаких проблем не возникает, так как при появлении на переднем плане закрытой ранее части окна Windovvs сама посылает в приложение сообщение WM_PAINT и приложение перерисовывает за­крытое ранее окно. Если же изображение должно формироваться динамически, например в ответ на выбор команды меню, как это имеет место в рассматриваемой программе, то мы должны иметь возможность, подготовив данные для вывода изображения, сами ини­циировать сообщение WM^PAINT, в функции обработки которого изображение и будет построено. Для этой важнейшей операции в Windows предусмотрено несколько функций, самой распространенной из которых является invalidateRectQ.

Инициирование сообщения WM_PAINT

Функция InvalidateRect(), с использованием которой мы уже столкнулись при рас­смотрении программы 6-1, объявляет указанную в ней прямоугольную область опреде­ленного окна поврежденной (invalid - недействительный, не имеющий законной силы), что заставляет Windows послать в это окно сообщение WMPAINT, которое приводит к перерисовке содержимого окна. Таким образом, в Windows предусмотрены два механиз­ма инициирования сообщения WMPAINT. Сама Windows посылает в приложение это сообщение каждый раз, когда скрытое ранее окно или его часть появляется на экране и, соответственно, требует перерисовки; кроме того, программа в любой момент может вы­зовом функции lnvalidateR.ect() объявить окно поврежденным, что также приведет к по­сылке в приложения сообщения WMPAINT.

Функиия lnvatidateRect() имеет следующий прототип:

BOOL InvalidateRect(HWND hWnd,CONST RECT* lpRect,B0OL bErase!;

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

Второй параметр дает возможность указать координаты прямоугольной области, которая добавляется к так называемой области обновления, требующей перерисовки. Windows накап­ливает информацию обо всех областях, входящих в область обновления, и, когда приложение вызывает функцию BeginPaintQ, Windows передает в программу координаты этой области. Практически, однако, вызов функции [rival idateRect() сразу приводит к посылке в окно сооб­щения WMPAINT и о накапливании недействительных областей в области обновления го­ворить не приходится.

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

214 Win32. Основы программирования

Третий параметр является флагом перерисовки фона. Если его значение равно TRUE, фон окна перерисовывается, что приводит к стиранию прежнего изображения. Если флаг равен FALSE, новое изображение рисуется поверх старого. В нашем случае, когда на эк­ран выводятся отдельные точки в произвольных местах, перерисовывать весь фон, т. е. стирать точки старого графика, необходимо. В тех случаях, однако, когда на экран выво­дятся прямоугольные элементы изображения, которые целиком перекрывают старое изо­бражение (например, знакоместа с буквами или цифрами), можно обойтись без перери­совывания фона, что сэкономит процессорное время и, главное, предотвратит мерцание изображения, возникающее при перерисовке окна.

Вывод па i a/hi a графика

Вывод в главное окно приложения точечного графика осуществляется в функции OnPmnt() обработки сообщения WM_PAINT. Здесь после получения с помощью функции BeginPainlO дескриптора контекста устройства вызывается функция GetClienlRectO, ко­торая возвращает в структурную переменную г типа RECT координаты рабочей области главного окна, точнее говоря, ее размеры, так как координаты начала рабочей области всегда считаются равными нулю. Размер рабочей области по вертикали нам нужен для того, чтобы выводимый на экран график строился относительно нижней границы окна (значения r.bottorn), независимо от текущего размера окна.

Вывод графика осуществляется в цикле из 500 шагов при условии наличия прочи­танных из файла данных (переменная bDataOK=TRUE) функцией отображения точек SetPi\e!(). В качестве параметров этой функции указывается дескриптор контекста уст­ройства, х- и у-координаты выводимой точки и ее цвет (с помощью макроса RGB()). Ор­дината точки с х-координатой i вычисляется как разность между нижней текущей грани­цей окна г.bottom и высотой выводимой кривой в этой точке nBuffi]. Из полученного значения вычитается 5, чтобы поднять график на 5 пикселов над нижней границей окна.

Немодальный диалог

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

  • масштабирование выводимого графика;

  • переключение вида графика - отдельные точки или точки, соединенные линиями (огибающая).

/*Программа €-7. Немодяльяый ляалог с -элемеитами управления*/

/*Фанл 6-7.Ь*/

/*Констан ят */

♦define MI_OPEN 101

#define MI_EXIT 102

#define MI_SETTINGS 103

#de£ine ID_DOTS 2D1

tdefine ID_CURVE 202

♦define ID_SCALE 203

/'^Определение нового типа GraphModes*/

emm G raphModes(DOTS=ID_D0TS,CURVE■ID_CURVE};

/*Лрототипи функций для главного окна*/

LRESULT CALLBACK WndProc [HWKD, UINT, WPARAM, LPAHAM) ;

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]