Назад | Начало урока | Вперед
Содержание

Глава 4

О посылке и получении сообщений

Как известно функция OnLButtonDown() есть во всех окнах.
В окне-картинке класса CButWnd она такова:


void CButWnd::OnLButtonDown(UINT nFlags, CPoint point) {
int but;
switch(mode) {
case BT_SHIPS:
but = B_PLACEMENT;
LastPoint.x = LastPoint.y = -1;
break;
case BT_SINGLE:
but = B_SINGLE;
LastPoint.x = LastPoint.y = -1;
break;
}
::SendMessage(m_Parent->m_hWnd, WM_STATIC_TO_DLG, WM_LBT_DOWN, but);
Invalidate();
CWnd::OnLButtonDown(nFlags, point);
}

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

::SendMessage(m_Parent->m_hWnd, WM_STATIC_TO_DLG, WM_LBT_DOWN, but);

Предпоследним параметром этой функции является WM_LBT_DOWN. Это идентификатор сообщения.
В главном окне функция ReceiveMessage() перехватит это сообщение, будет анализировать
этот параметр, на предмет того, как на него реагировать.

Последним параметром этой функции является переменная but, которой может быть присвоено одно из двух значений - B_PLACEMENT или B_SINGLE, зависит от того, на какое из окон нажал пользователь.

Это посланное сообщение перехватывается в главном окне его функцией ReceiveMessage().
Эта функция с двумя параметрами.

Первый параметр - в него попадает как раз этот самый идентификатор сообщения WM_LBT_DOWN.
Второй параметр - как раз и содержит эту посланную функцией ::SendMessage() переменную but.

Функция ReceiveMessage() (получить сообщение) присутствует в главном окне приложения
и в классе CField(поле боя). Она имеет два параметра.

В главном окне приложения функция анализирует оба параметра. Первый параметр - какое именно сообщение (например клик кнопкой) - определяет ветвь программы, по которой она будет выполняться. Второй параметр передается в параметр функции SetBtDown().


HRESULT CSeaBattle02Dlg::ReceiveMessage(WPARAM wParam, LPARAM lParam) {
switch(wParam) {
case WM_LBT_DOWN:
SetBtDown((int)lParam);
break;
} return NULL;
}

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

В этой ветви функция ReceiveMessage() вызывает функцию SetBtDown() и передает ей свой второй аргумент. А вторым аргументом является как раз последний параметр функции
::SendMessage(), пославшей сообщение. Помним, что это может быть B_PLACEMENT или B_SINGLE. Получив аргумент, функция SetBtDown() анализирует его и на основе этого анализа выполняется одна из двух ветвей программы.


void CSeaBattle02Dlg::SetBtDown(int but) {
int code;
switch(but) {
case B_PLACEMENT:
m_OwnField.ReceiveMessage(WM_PLACEMENT, 0);
InvalidateRect(CRect(105, 300, 130, 345));
m_Process = PLACE;
break;
case B_SINGLE:
if(m_OwnField.ReceiveMessage(WM_IS_OK, 0)) {
m_Process = SINGLE_PLAY;
code = ::AfxMessageBox("Вы первым начнете???", MB_YESNO);
m_SingleWnd.IsFocus = false;
m_SingleWnd.Invalidate();
}
else {
::AfxMessageBox("Расставьте сначала свои корабли");
m_SingleWnd.IsFocus = false;
m_SingleWnd.Invalidate();
}
break;
}//end switch
}

В каждой из ветвей этой функции в свою очередь вызывается функция ReceiveMessage() класса Field. Этой функции в каждой из ветвей передается различный аргумент (WM_PLACEMENT или WM_IS_OK). Соответственно будет выполняться одна из ветвей функции, либо - Очистить поле от кораблей и инициализировать переменные начальными значениями, либо - Все корабли уже расставлены, в двойном цикле пройти по всем ячейкам матрицы и везде заменить CANNOT на EMPTY:


int CField::ReceiveMessage(int wParam, long lParam) {
int i, j;
switch(wParam) {
case WM_PLACEMENT://Очистить поле от кораблей.
//Инициализировать переменные начальными значениями
m_Operation = PLACEMENT;
m_Direction = RIGHT;
m_Decks = 4;
m_Position.x = m_Position.y = -1;
m_Draw = false;
for(i=0; i<10; i++)
for(j=0; j<10; j++)
m_Event[i][j] = EMPTY;
m_Count = 0;
Invalidate();
break;
case WM_IS_OK: //все корабли расставлены?
if(число палуб равно нулю)//все корабли расставлены! {
в двумерном цикле присвоить значение EMPTY всем полям,
у которых ранее было значение CANNOT. Это те поля, по которым
пользователь выстрелил, но не попал, и на них был крестик.

for(i=0; i<10; i++)
for(j=0; j<10; j++) {
if(m_Event[i][j] == CANNOT) m_Event[i][j] = EMPTY;
}
Invalidate();
return 1;
}
else return 0;//корабли не расставлены вернем 0.
}
return 1;
}


Функция возвращает 1 или 0. Например если мы нажали картинку-кнопку "Корабли", то выполнится ветвь WM_PLACEMENT и функция вернет 1. Если мы нажали кнопку-картинку
"Один игрок", то выполнится ветвь WM_IS_OK и функция может возвратить одно из двух
значений - если все корабли уже расставлены, то возвратит 1, в противном случае 0.

Вернемся к рассмотрению функции SetBtDown().

В первой ветви после вызова функции ReceiveMessage() класса Field (очищено поле от кораблей и инициированы переменные), функция SetBtDown() обновила InvalidateRect и присвоила переменной m_Process значение PLACE (можно ставить корабли):

InvalidateRect(CRect(105, 300, 130, 345));
m_Process = PLACE;
break;

Во второй ветви после вызова функции ReceiveMessage() класса Field (все корабли расставлены), функция SetBtDown() в зависимости от того, что вернула ReceiveMessage()
выполняет один из двух вариантов:

Первый вариант - корабли расставлены:

m_Process = SINGLE_PLAY;//поменяем значение
code = ::AfxMessageBox("Вы первым начнете???", MB_YESNO);
m_SingleWnd.IsFocus = false;
m_SingleWnd.Invalidate();

Второй вариант - корабли не расставлены:

// m_Process = PLACE; значение осталось прежним
::AfxMessageBox("Расставьте сначала свои корабли");
m_SingleWnd.IsFocus = false;
m_SingleWnd.Invalidate();

Как видим функция SetBtDown() вызывается внутри функции главного окна ReceiveMessage()
(получить сообщение), анализирует переданный ей параметр, в результате определяет какое окно-картинка было нажато. Вызывает соответсвующую функцию ReceiveMessage() этого дочернего окна и реагирует должным образом.


Назад | Начало урока | Вверх | Вперед
Содержание

Hosted by uCoz