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

Глава 4

Программирование графики
Служебный класс CButWnd
Для программирования графики в данной программе специально объявлены и определены два служебных класса CButWnd и CPicture.

Класс CButWnd - производный от CWnd. При помощи этого класса будут созданы дочерние окна, помещены на родительское окно. В эти окна будут размещены картинки (изображения). Визуально будет так, что при наведении курсора на эти окна, картинка на нем будет меняться, а при нажатии левой кнопкой (клик левой) будет выполняться определенная реакция. Например вывод сообщения. Эти дочерние окна будут выполнять в программе роль необычных кнопок. Рассмотрим этот класс.


В классе CButWnd объявлены пять открытых переменных.

class CButWnd : public CWnd {

// Construction
public:
CWnd *m_Parent;
CPicture ActPic, Pic;
int mode;
POINT LastPoint;
int IsFocus;

Переменная LastPoint типа POINT используется в двух функциях:
OnMouseMove() и OnLButtonDown().

Перемення LastPoint служит в функции OnMouseMove() для определения первого входа
курсора на территорию картинки-кнопки.


void CButWnd::OnMouseMove(UINT nFlags, CPoint point) {
RECT rect;
GetWindowRect(&rect);
if(Cely(rect, point)) {
if(!Cely(rect, LastPoint)) {
SetCapture();
IsFocus = true;
Invalidate();
}
}
else {
if(Cely(rect, LastPoint)) {
ReleaseCapture();
IsFocus = false;
Invalidate();
}
}
LastPoint = point;
CWnd::OnMouseMove(nFlags, point);
}

Анализ

Этот же алгоритм на псевдокоде:

void CButWnd::OnMouseMove(UINT nFlags, CPoint point) {

ЕСЛИ(курсор на территории кнопки-картинки){
ЕСЛИ(при этом координаты LastPoint - вне территории кнопки) {
//перехватываем и перерисовываем
SetCapture();
IsFocus = true;
Invalidate();
}
}
ИНАЧЕ(курсор не на территории кнопки-картинки){
ЕСЛИ(при этом координаты LastPoint - на территории кнопки) {
//отпускаем и перерисовываем
ReleaseCapture();
IsFocus = false;
Invalidate();
}
//сделаем совпадение координат
LastPoint = point;
CWnd::OnMouseMove(nFlags, point);
}
}

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

Функция Cely() определяет находится ли точка point на территории rect


bool CButWnd::Cely(RECT rect, CPoint point){
int w, h;
w = rect.right-rect.left;
h = rect.bottom-rect.top;

if(point.x >= 0 && point.y >= 0 && point.x <= w && point.y <= h)

return true;
return false;
}

Теперь посмотрим функцию:


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);
}

Открытая переменная mode может принимать три значения:

#define BT_NONE 0
#define BT_SHIPS 1
#define BT_SINGLE 3

В конструкторе класса ей дается значение BT_NONE, но в процессе работы программы
она может принимать и другие два значения. В функции рассматриваются случаи, когда
переменная mode принимает значения BT_SHIPS или BT_SINGLE, то есть пользователь нажал
на одну из кнопок-картинок. В этом случае переменная LastPoint выводится за пределы поля
(это для того, чтобы функция OnMouseMove() реагировала соответствующим образом при движении
курсора над картинкой).

А сообщение ::SendMessage() посылается с соответствующим аргументом.

Первый аргумент функции SendMessage() указатель на окно m_Parent->m_hWnd.
Этому указателю присваивается значение в функции SetMode(), переданное через параметр.
В главном окне функция SetMode() вызывается со значением этого параметра - this.
То есть сообщение будет выводиться в главное окно.

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

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

Открытым переменным - переменной mode и указателю на окно m_Parent - присваиваются
значения в функции SetMode(), которая вызывается в главном окне приложения.
Кроме того, эта функция загружает ту или иную картинку учитывая значение
переменной mode:


void CButWnd::SetMode(int md, CWnd *parent) {
mode = md;
m_Parent = parent;
switch(md) {
case BT_SHIPS:
Pic.Load(JPG_BT_SHIPS);
ActPic.Load(JPG_BT_ACT_SHIPS);
break;
case BT_SINGLE:
Pic.Load(JPG_BT_SINGLE);
ActPic.Load(JPG_BT_ACT_SINGLE);
break;
}
}

Вот как вызывается эта функция в главном окне:

//Красивые Кнопки
m_ShipWnd.Create(NULL, NULL, WS_CHILD|WS_VISIBLE, CRect(0, 0, 103, 88), this, 0);
m_ShipWnd.SetMode(BT_SHIPS, this);

m_SingleWnd.Create(NULL, NULL, WS_CHILD|WS_VISIBLE, CRect(220,18,220+142,18+68),this, 0);
m_SingleWnd.SetMode(BT_SINGLE, this);

После этих инструкций созданы два экземпляра класса CButWnd (две кнопки-картинки).
Они расположены в своих координатах в главном окне. Функция SetMode() присвоила значение
переменным mode и m_Parent, а так же загрузила изображения в экземпляры Pic и ActPic
класса Picture. При этом указатель m_Parent в обоих случаях указыавет на главное окно.

Теперь самое время рассмотреть функцию:


void CButWnd::OnPaint() {
CPaintDC dc(this); // device context for painting
RECT rect;
GetClientRect(&rect);
if(IsFocus)
ActPic.Render(&dc, &rect);
else
Pic.Render(&dc, &rect);
}

Как видим функция анализирует значение переменной IsFocus и в зависимости от этого значения подготавливает к выводу ту или иную картинку. Напомню, что в функции OnMouseMove() переменной IsFocus присваивается знчение true, когда курсор заходит на территорию окна-картинки, и false когда покидает.

Именно функция OnPaint() определяет всякий раз, какую из картинок надо перерисовать.
(при помощи функции Render()). Функция Render() - это функция конвертации одних единиц в другие.


// Render to device context. Covert to HIMETRIC for IPicture.
//
BOOL CPicture::Render(CDC* pDC, CRect rc, LPCRECT prcMFBounds) const {
ASSERT(pDC);

if (rc.IsRectNull()) {

CSize sz = GetImageSize(pDC);
rc.right = sz.cx;
rc.bottom = sz.cy;
}
long hmWidth,hmHeight; // HIMETRIC units
GetHIMETRICSize(hmWidth, hmHeight);
m_spIPicture->Render(*pDC, rc.left, rc.top, rc.Width(), rc.Height(),
0, hmHeight, hmWidth, -hmHeight, prcMFBounds);

return TRUE;

}

Подсказка

Два дочерних окна-картинки выведены в родительское окно.

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

Hosted by uCoz