Учебник по Visual C++ .Net

         

Визуальное редактирование данных


CDrawView::OnLButtonDown(UINT nFlags, CPoint point)

{

//====== В режиме создания нового полигона

if (m_bNewPoints)

{

CTreeDoc *pDoc = GetDocument();

//====== Ссылка на массив точек текущего полигона

VECPTSS pts = pDoc->m_Poly.m_Points;

//=== Получаем адрес текущего контекста устройства

CDC *pDC = GetDC() ;

//====== Настраиваем его с учетом размеров окна

SetDC(pDC) ;

//=== Преобразуем аппаратные координаты в логические

pDC->DPtoLP(ipoint);

//=== Преобразуем Page-координаты в World-координаты

CDPoint pt = pDoc->MapToWorldPt(point);



//====== Запоминаем в контейнере

pts.push_back (pt);

}

//====== В режиме готовности к захвату

else if (m_bReady)

{

ra_bLock = true; // Запоминаем состояние захвата

m_bReady = false; // Снимаем флаг готовности

}

//====== В режиме повторного нажатия

else if (mJbLock)

m_bLock = false; // Снимаем флаг захвата

else

//В случае бездумного нажатия

return; // уходим

Invalidated; // Просим перерисовать

}

void CDrawView::OnMouseMove(UINT nFlags, CPoint point)

{

//=== В режиме создания нового полигона не участвуем

if (m_bNewPoints) return;

//====== Получаем и настраиваем контекст

CDC *pDC = GetDCO ;

SetDC(pDC);

//=== Преобразуем аппаратные координаты в логические

pDC->DPtoLP(Spoint);

//=== Преобразуем Page-координаты в World-координаты

CTreeDoc *pDoc = GetDocument();

CDPoint pt = pDoc->MapToWorldPt(point);

//====== Если был захват, то перерисовываем

//====== контуры двух соседних с узлом линий

if (m_bLock)

{

// Курсор должен показывать операцию перемещения

SetCursor(m_hGrab);

//====== Установка режима

pDC->SetROP2(R2_XORPEN);

//====== Двойное рисование

//====== Сначала стираем старые линии

RedrawLines(pDC, pDoc->MapToLogPt (pDoc->

m_Poly.m_Points[ra_CurID]));

//====== Затем рисуем новые

RedrawLines(pDC, point);

//====== Запоминаем новое положение вершины

pDoc->m_Poly.m_Points[m_CurID] = pt;

}

//====== Обычный режим поиска близости к вершине


else

{

m_CurID = pDoc->FindPoint(pt);

// Если близко, то m_CurID получит индекс вершины

// Если далеко, то индекс будет равен -1

m_bReady = m_CurID >= 0;

//=== Если близко, то меняем курсор

if (m_bReady)

SetCursor(m_hGrab);

}

}

//====== Перерисовка двух линий, соединяющих

//====== перемещаемую вершину с двумя соседними

void CDrawView::RedrawLines (CDC *pDC, CPointS point)

{

CTreeDoc *pDoc = GetDocument();

//====== Ссылка на массив точек текущего полигона

VECPTS& pts = pDoc->m_Poly.m_Points;

UINT size = pts.sizeO;

//====== Если полигон вырожден, уходим

if (size < 2) return;

//====== Индексы соседних вершин

int il = m_CurID == 0 ? size - 1 : m_CurID - 1;

int 12 = m_CurID == size - 1 ? 0 : m_CurID + 1;

// ====== Берем перо и рисуем две линии

pDC->SelectObject(Sm_penLine);

pDC->MoveTo(pDoc->MapToLogPt(pts[11] ) ) ;

pDC->LineTo(point);

pDC->LineTo(pDoc->MapToLogPt(pts[12]));

}

Определение индекса вершины, к которой достаточно близко подобрался указатель мыши, производится в методе FindPoint класса документа. В случае если степень близости недостаточна, функция возвращает значение -1. Вставьте этот метод в файл реализации класса (TreeDoc.cpp):

int CTreeDoc::FindPoint(CDPointS pt)

{

//====== Пессимистический прогноз

int id = -1;

//====== Поиск среди точек дежуоного полигона

for (UINT 1=0; i<m_Poly.m_Points.size(); i++)

{

//=== Степень близости в World-пространстве.

//=== Здесь мы используем операцию взятия нормы

//=== вектора, которую определили в классе CDPoint

if ( !(m_Poly.m_Points[i) - pt) <= 5e-2)

(

id = i;

break; // Нашли

}

}

//====== Возвращаем результат

return id;

}

В этот момент вы можете запустить приложение, выбрать шаблон Draw и проверить возможности визуального редактирования, перетаскивая вершины звезды в пределах клиентской области окна документа.

Включение или выключение второго режима редактирования, служащего для создания нового полигона и ввода координат вершин с помощью мыши, потребует меньше усилий, так как логика самого режима уже реализована в обработчике нажатия левой кнопки мыши. Для включения или выключения (toggle) второго режима используется одна и та же команда. Создайте обработчик команды Edit > New Poly. Для этого:



  • Поставьте фокус на элемент CDrawView в представлении классов (Class View) и перейдите в окно Properties.

  • Нажав кнопку Events, выберите идентификатор ID_EDIT_NEWPOLY, раскройте маркер (+) и выберите COMMAND (первую из двух выпавших строк).

  • Создайте обработчик, выбрав <Add> в выпадающем списке справа от COMMAND.



    Рис. 5.3. Редактируемый полигон

    В теле обработчика следует установить флаги состояния, уничтожить все вершины дежурного полигона и перерисовать представление:

    void CDrawView::OnEditNewpoly(void)

    {

    //====== Включаем/Выключаем режим ввода вершин

    m_bNewPoints = !m_bNewPoints;

    //=== Снимаем флаги редактирования перетаскиванием

    m_bReady = false;

    m_bLock = false;

    //====== Если режим включен, то уничтожаем вершины

    if (m_bNewPoints)

    {

    GetDocument()->m_Poly.m_Points.clear() ;

    Invalidate();

    }

    }

    Запустите приложение, выберите шаблон Draw и дайте команду Edit > New Poly. Щелкайте левой кнопкой мыши разные места клиентской области окна и наблюдайте за трансформациями полигона m_Poly при добавлении в контейнер его точек новых значений. Мысленно проследите за преобразованиями координат, которые происходят в эти моменты. Вы помните, что мышь дает аппаратные координаты, а в контейнер попадают World-координаты вершин полигона?


    Содержание раздела