Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Професиональное программирование


Информационный Канал Subscribe.Ru

Здравствуйте уважаемые подписчики.

Мы продолжаем знакомить вас, пока не регулярно, с нашими  статьями.

Как и было обещано на сайте начато обсуждение издания совместной книги на базе
сайта.
Прочесть по этой теме можно здесь http://www.shelek.com/club/modules.php?op=modload&name=phpBB_14&file=index&action=viewforum&forum=25
Тут же можно высказать свою идею за или против или подключится к авторству. Естественно
все тексты будут оплачены.

Сегодня продолжение темы

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

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

Код WndProc:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        int wmId, wmEvent;
        PAINTSTRUCT ps;
        HDC hdc;
        TCHAR szHello[MAX_LOADSTRING];
        LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

        switch (message)
        {
                case WM_COMMAND:
                        wmId    = LOWORD(wParam);
                        wmEvent = HIWORD(wParam);
                        // Parse the menu selections:
                        switch (wmId)
                        {
                                case IDM_ABOUT:
                                   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
                                   break;
                                case IDM_EXIT:
                                   DestroyWindow(hWnd);
                                   break;
                                default:
                                   return DefWindowProc(hWnd, message, wParam, lParam);
                        }
                        break;
                case WM_PAINT:
                        hdc = BeginPaint(hWnd, &ps);
                        // TODO: Add any drawing code here...
                        RECT rt;
                        GetClientRect(hWnd, &rt);
                        DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
                        EndPaint(hWnd, &ps);
                        break;
                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;
                default:
                        return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

Давайте теперь разберем ее по косточкам.
Эта функция, по сути, и есть основная часть рабочего приложения. Система Windows
предоставляя программе ресурсы должна общаться с ним через какой-либо интерфейс.
Этот интерфейс базируется на сообщениях, которые необходимо обрабатывать и которые
можно и нужно отсылать в систему для сообщения ей о необходимых действиях.
Естественно, посылать можно с любого места программы. А вот для обработки системных
сообщений выделяется отдельная функция.
Именно о ней мы и говорим.
Не будем пока говорить о том, как попадают системные сообщения в нашу программу.
Они попадают и именно в функцию WndProc.
Вместе с сообщением Windows передает два абстрактных параметра LPARAM WPARAM.

Таким образом, вместе с сообщением идут данные по необходимости.
Скажем при нажатии кнопочки мы получим сообщение WM_CHAR а в параметрах код нажатой
клавиши и кучу других полезных данных.

Давайте посмотрим, что делает в стартовом минимально необходимом состоянии функция
WndProc.

switch (message)
        {
Это основной разборщик наших сообщений.

case WM_DESTROY:
Самый простой пример обработки сообщения.
WM_DESTROY - идет без параметров, говорит оно о том, что пользователь или какая
либо программа (крайне редкая ситуация - иногда система при перезагрузке) послала
приказ закрыться. Нажимая на крестик в правом верхнем углу, мы посылаем в программу
именно это сообщение.

Обработка очень проста.

PostQuitMessage(0);
break;

PostQuitMessage(0); посылает в саму программу сообщение для закрытия программы
с кодом возврата 0, что говорит о нормальном безошибочном завершении работы.


case WM_PAINT:
Это сообщение сложнее и интересней.
Для понимания сути происходящего мы должны обратится к системным правилам Windows.

Каждый раз, когда система отображает что-либо, например окно аппликации, оно
посылает в программу сообщение WM_PAINT для обновления контекста окна.

После обработки контекст окна показывается на экране.
Естественно, если мы проигнорируем сообщение, то вместо своего окна увидим пустоту.
Для обработки сообщения нам нужно следующее:
hdc = BeginPaint(hWnd, &ps);
Возьмем HANDLE окна hWnd, присланный вместе с сообщением, и с  помощью данной
функции получим HANDLE на отображаемую часть окна DeviceContent иначе DC.

Параллельно в структуру PAINTSTRUCT загрузятся необходимые данные о нем.

RECT rt;
GetClientRect(hWnd, &rt);

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

DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);

В данном примере просто напишем текст Hello World
EndPaint(hWnd, &ps);
Закончим  процесс обновления экрана. Функция EndPaint занесет в систему все сделанные
нами изменения, кроме того, обозначит для Windows, что теперь уже можно выводить
наши данные на экран.

Для дальнейшего рассмотрения отвлечемся немного на работу с элементами окна.

Такие элементы как дочернии ( child) внутренние окна, элементы типа меню и т.д.
посылают в главное окно свои события вместе с командным сообщением WM_COMMAND.

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

Для обработки такого сообщения мы должны раскрыть его данные.
wmId    = LOWORD(wParam);
wmEvent = HIWORD(wParam);

В верхней части HIWORD два старших  байта WPARAM содержат информацию о типе события,
в нижней части LOWORD двух младших байтах, ID того элемента, которое послало
данное сообщение.

Так как тип события известен - клик на пункте меню мы обработаем только ID.
// Parse the menu selections:
switch (wmId)
{
        case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
        break;

Это нажат пункт "О программе" (About)  реакция на который, вызов обычного дочернего
диалогового окна с тескстом из ресурсов программы по его ID.
DialogBox(hInst // Инстанс основной программы
IDD_ABOUTBOX // ID Диалога из ресурсов
, hWnd // HANDLE на основное окно для указания чье диалоговое окно выводится
About Процедура WndProc - для обработки сообщений диалогом. В коде она есть и
мы рассмотрим ее в следующий раз.


case IDM_EXIT:
Нажат пункт меню Выход!
DestroyWindow(hWnd);
Эта функция пошлет сообщение WM_DESTROY всей программе, его мы описали чуть ранее.

return DefWindowProc(hWnd, message, wParam, lParam);
И вот напоследок обязательное завершение любой функции WndProc!

Это вызов главного обработчика Windows, который и проделает все остальные действия.
Ведь мы всего лишь петля, часть той структуры обработки сообщения Windows, которая
отвечает за наши действия.
Все дальнейшие действия по правильному выводу на экран содержимого контекста
- закрытие или открытие окон - движение мышки и т.д. должна обрабатывать сама
система.
Вызовом DefWindowProc - мы отдаем и данные текущего сообщения и наши парамтры
в систему для дальнейшей обработки.

Если этого не сделать, то сообщение не будет иметь эффекта.
Например, если в case WM_DESTROY написать не  PostQuitMessage; break; , а просто
return 0 то программа будет работать но вы не сможете ее закрыть обычным путем.

Продолжение следует.

Спасибо за внимание
http://club.shelek.com/
club@shelek.com


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное