Глава 4
Класс CButWnd - производный от CWnd. При помощи этого класса будут созданы дочерние окна, помещены на родительское окно. В эти окна будут размещены картинки (изображения). Визуально будет так, что при наведении курсора на эти окна, картинка на нем будет меняться, а при нажатии левой кнопкой (клик левой) будет выполняться определенная реакция. Например вывод сообщения. Эти дочерние окна будут выполнять в программе роль необычных кнопок. Рассмотрим этот класс.
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)
{
SetCapture();
IsFocus = true;
Invalidate();
ИНАЧЕ(курсор не на территории кнопки-картинки){
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_SingleWnd.Create(NULL, NULL, WS_CHILD|WS_VISIBLE, CRect(220,18,220+142,18+68),this, 0);
m_ShipWnd.Create(NULL, NULL, WS_CHILD|WS_VISIBLE, CRect(0, 0, 103, 88), this, 0);
m_ShipWnd.SetMode(BT_SHIPS, this);
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;
}
Два дочерних окна-картинки выведены в родительское окно.
Назад |
Начало урока |
Вверх |
Вперед
Содержание