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

Глава 4

Нам в программе "Морской бой" естественно потребуется поле боя,
на котором будут располагаться наши корабли. Пока напишем программу,
в которой будет только одно наше поле. Поле противника можно будет создать
аналогично.
Создадим новый класс "Поле боя" - класс Field. Это будет так же окно,
но наследуем его от CStatic, так как наше окно не надо будет двигать, сжимать.
у него не должно быть заголовка и тд.

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

Заголовок Field.h:


#pragma once
//objects
#define OWN_FIELD 1
#define LETTERS 3
#define NUMBERS 4

//properties
#define EMPTY 1000

// CField
class CField : public CStatic {

DECLARE_DYNAMIC(CField)
public:
CField();
virtual ~CField();
// Implementation
public:
CWnd* m_Parent;
void SetParent(CWnd *wnd);
void SetMode(int mode);

// Generated message map functions

protected:
//{{AFX_MSG(CField)
afx_msg void OnPaint();
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
CBitmap bmp, *pOld;
CDC WaterDC;
int m_Mode;
short m_Event[10][10];
};

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

Определим конструктор.


CField::CField() {
m_Parent = NULL;
for(int i=0; i<10; i++)
for(int j=0; j<10; j++)
m_Event[i][j] = EMPTY;
}
CField::~CField() {
WaterDC.DeleteDC();
bmp.Detach();
}

Карта сообщений так же минимальна



BEGIN_MESSAGE_MAP(CField, CStatic)
//{{AFX_MSG_MAP(CField)
ON_WM_PAINT()
ON_WM_SETCURSOR()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

Определим функцию рисования.


Функция void CField::OnPaint()
void CField::OnPaint() {
CPaintDC dc(this); // device context for painting
int i;
RECT rect;
char *let = "abcdefghik";

GetClientRect(&rect);
if(m_Mode == OWN_FIELD) {

//Нарисуем синюю воду
//интересно, что без этой функции фон нашего поля не будет нарисован
dc.BitBlt(dc.m_ps.rcPaint.left, dc.m_ps.rcPaint.top,
dc.m_ps.rcPaint.right - dc.m_ps.rcPaint.left,
dc.m_ps.rcPaint.bottom - dc.m_ps.rcPaint.top,
&WaterDC, dc.m_ps.rcPaint.left,
dc.m_ps.rcPaint.top, SRCCOPY);

//горизонтальные линии сетки
for(i=(dc.m_ps.rcPaint.top/20)*20; i<=(dc.m_ps.rcPaint.bottom/20)*20; i+=20) {

dc.MoveTo(dc.m_ps.rcPaint.left, i);
dc.LineTo(dc.m_ps.rcPaint.right, i);
}
//вериткальные линии сетки
for(i=(dc.m_ps.rcPaint.left/20)*20; i<=(dc.m_ps.rcPaint.right/20)*20; i+=20) {
dc.MoveTo(i, dc.m_ps.rcPaint.top);
dc.LineTo(i, dc.m_ps.rcPaint.bottom);
}


}//end (m_Mode == OWN_FIELD)


if(m_Mode == NUMBERS) {

dc.SetBkMode(TRANSPARENT);
dc.TextOut(0, 4, " 1 2 3 4 5 6 7 8 9 10");
}
if(m_Mode == LETTERS) {
dc.SetBkMode(TRANSPARENT);
for(i=0; i dc.TextOut(8, i+2, (CString)let[i/20]);
}
}

Что делает функция OnPaint() ясно из ее комментариев.

Еще сделаем функцию, которая будет определять,
как именно рисовать объект типа Field. Или это будет сетчатое
голубое поле, или это будут горизонтальное поле с цифрами,
или вертикальное поле с буквами. Это будет определяться вызовом функции
SetMode() соответствующим экземпляром Field.


void CField::SetMode(int mode) {
m_Mode = mode;
}


В функции OnPaint() происходит проверка этой переменной:

if(m_Mode == OWN_FIELD){}
if(m_Mode == NUMBERS){}
if(m_Mode == LETTERS){}

Еще нам понадобится функция:


void CField::SetParent(CWnd *wnd) {
RECT rect;
CBitmap bmp;
CDC *dc = GetDC();
CPicture m_Fon;

m_Parent = wnd;
GetClientRect(&rect);
WaterDC.CreateCompatibleDC(dc);
bmp.CreateCompatibleBitmap(dc, rect.right, rect.bottom);
ReleaseDC(dc);
pOld = WaterDC.SelectObject(&bmp);

m_Fon.Load(JPG_BACKGROUND);
m_Fon.Render(&WaterDC, CRect(0, 0, 50, 50));

//замостим голубыми плитками 50х50 все главное окно
for(int i=0; i<=rect.right/50+3; i++)

for(int j=0; j<=rect.bottom/50; j++)
WaterDC.BitBlt(i*50, j*50, 50, 50, &WaterDC, 0, 0, SRCCOPY);

}

Эта функция присваивает переменной-указателю на окно m_Parent значение *wnd,
то есть этот указатель указывает на главное окно приложения.
Переменная m_Parent используется в функции void CField::OnLButtonDown().
Кроме того в этой функции на "поле боя" рисуется голубой фон.

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

Эта функция в программе вызывается один раз, а функция OnPaint() - многократно.

Еще две служебных функции:


BOOL CField::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {
return CStatic::OnSetCursor(pWnd, nHitTest, message);
}

void CField::OnDestroy() {
WaterDC.DeleteDC();
bmp.DeleteObject();
CStatic::OnDestroy();
}

Полностью файл Field.cpp на следующей странице.


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

Hosted by uCoz