Ресурсы в традиционном приложении Windows, страница 5

static HDC hmdc;   // Контекст устройства в памяти

static HBITMAP hbmp = LoadBitmap (GetModuleHandle(NULL),(char*)IDB_BITMAP);

static BITMAP bmp; // Структура, описывающая изображение

static RECT r;       // Прямоугольная область экрана для вывода bitmap

Все переменные объявлены статическими, так как мы хотим внести некоторую инерционность, то есть способность помнить предыдущие значения, несмотря на тот факт, что оконная процедура вызывается многократно в жизненном цикле приложения. Переменная hbmp — Windows-описатель объекта «точечное изображение» инициализируется ресурсом IDB_BITMAP, который ищется в модуле своего собственного приложения. Этот факт определяется значением (NULL) параметра функции (GetModuleHandle) поиска exe-модуля.

Те действия, которые следует выполнить однократно, удобно производить либо в теле функции WinMain, либо в оконной процедуре, но в тех ветвях обработки сообщений, которые выполняются один раз. Для этой цели подходит сообщение WM_CREATE, так как оно генерируется только однажды (при создании окна). Вставим в эту ветвь следующие операции:

¨  Создание контекста в памяти hmdc,

¨  Выбор в него инструмента рисования, на который ссылается описатель hbmp,

¨  Заполнение структуры bmp, которая должна описывать изображение.

case WM_CREATE:

hdc = GetDC(hWnd);   // Добываем описатель контекста, связанного с экраном

hmdc = CreateCompatibleDC(hdc);  // Создаем на его основе контекст в памяти

SelectObject(hmdc,hbmp);           // Выбираем в него описатель изображения

GetObject(hbmp, sizeof(bmp), &bmp);

break;

Функция GetObject, в частности, определяет размеры изображения. Для запоминания этих размеров вставим такой код в ветвь обработки WM_SIZE:

r.left = gnMaxPos/2;

r.right = r.left + bmp.bmWidth;

r.top = 50;

r.bottom = r.top + bmp.bmHeight;

InvalidateRect (hWnd, 0, TRUE);

Для непосредственного копирования изображения из контекста в контекст вставим в ветвь WM_PAINT вызов уже упоминавшейся функции блиттинга:

BitBlt(hdc, r.left, r.top, bmp.bmWidth, bmp.bmHeight, hmdc, 0, 0, SRCCOPY);

Реакция на манипуляции мышью

Манипулятор мыши генерирует несколько сообщений. Например, левая кнопка создает следующие события: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE. Для того, чтобы приложение смогло реагировать на сообщения об этих событиях, необходимо ввести в оконную процедуру соответствующие ветви блока switch. Покажем как ввести реакцию на нажатие левой кнопки. Будем при каждом ее нажатии над bitmap-изображением сдвигать выводимый в окно текст на определенное расстояние (вправо или влево). Введем вспомогательные переменные:

static int shift = 15; // Величина сдвига

POINT pt;                  // Структура для текущих координат позиции курсора мыши

Затем вставим ветвь реакции на сообщение о нажатии левой кнопки:

case WM_LBUTTONDOWN:

pt.x = LOWORD(lParam);  // Добываем текущие координаты позиции курсора

pt.y = HIWORD(lParam);

if (PtInRect(&r,pt))    // Анализируем факт попадания в прямоугольник bitmap

{

if (gnPos+5 > gnMaxPos || gnPos-5 < 0)

shift =  -shift;   // Определяем направление сдвига

InvalidateRect (hWnd, 0, TRUE);

}

gnPos += shift;           // Сдвигаем позицию вывода текста

break;

Сдвиг окна диалога

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

{

RECT r;

GetWindowRect(hDlg,&r);       // Определяем размеры окна диалога

int ws = GetSystemMetrics(SM_CXSCREEN),     // Определяем горизонтальный размер экрана

w = r.right - r.left,    // Вспомогательные вычисления

h = r.bottom - r.top,

left = (ws - w)/2;

MoveWindow (hDlg, left, 200, w, h,TRUE); // Перемещаем окно в желаемое место

}