15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Перетаскивание элементов из Toolbar в view


Автор: Pham Hong Nguyen.

Основноя проблема заключается в том, что toolbar не реагирует на действие переноса элементов. Следовательно нам нужно брать и посылать соответствующие сообщения самостоятельно. Итак, наследуем новый класс CDragToolBar от CToolBar, затем добавляем в него обработчик события LButtonDown:

void CDragToolBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
   int nCount = GetToolBarCtrl().GetButtonCount();
   for (int i=0; i<nCount; i++) {
   CRect rect;
      GetItemRect(i, rect);
      if (rect.PtInRect(point)) {
         PostMessage(WM_COMMAND, GetItemID(i));
         return;
      }
   }
      
   CToolBar::OnLButtonDown(nFlags, point);
}

Теперь во view перехватываем все события, поступающие от toolbar и переводим программу в режим перетаскивания:

void CDTBView::OnDragToolBar(UINT nCmdID)
{
   m_dragBtn = nCmdID;
   BeginDrag ();
}

В этом примере drag and drop работает через CImageList.

Данный метод прекрасно работает. Однако, существует небольшая проблемма, заключающаяся в том, что перетаскиваемая кнопка тулбара не правильно перерисовывается ввиду нарушения курсора перетаскивания (он фиксирует изображение кнопки до апдейта, а затем только перерисовывает его). Поэтому нам потребуется небольшое улучшение кода.

Вместо того, чтобы входить в режим перетаскивания после получения сообщения, программа должна записать событие перетаскиваемой кнопки и дать немного времени, чтобы тулбар проапдейтил статус кнопки. Чтобы гарантировать это, мы фиксируем событие перемещения мышки, и проверяем как далеко была перемещена мышка. Если всё ОК, то отправляем другое сообщение, для того, чтобы программа вошла в режим перетаскивания:

void CDragToolBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
   int nCount = GetToolBarCtrl().GetButtonCount();
   for (int i=0; i<nCount; i++) {
      CRect rect;
      GetItemRect(i, rect);
      if (rect.PtInRect(point)) {
         PostMessage(WM_COMMAND, GetItemID(i));
         m_dragMode = TRUE;
         m_point = point;
         return;
      }
   }
      
   CToolBar::OnLButtonDown(nFlags, point);
}

void CDragToolBar::OnMouseMove(UINT nFlags, CPoint point) 
{
   if (m_dragMode && 
             abs(m_point.x-point.x)+abs(m_point.y-point.y)>=3) {
      PostMessage(WM_COMMAND, ID_START_DRAG);
      m_dragMode = FALSE;
   }
   CToolBar::OnMouseMove(nFlags, point);
}

Во view делаем соответствующие изменения:

void CDTBView::OnDragToolBar(UINT nCmdID)
{
   m_dragBtn = nCmdID;
}

void CDTBView::OnStartDrag() 
{
   BeginDrag();
}

А теперь добавим немного кода, чтобы придать тулбару немного интеллектуальности.

void CDragToolBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
   int nCount = GetToolBarCtrl().GetButtonCount();
   for (int i=0; i<nCount; i++) {
      CRect rect;
      GetItemRect(i, rect);
      if (rect.PtInRect(point)) {
         PostMessage(WM_COMMAND, GetItemID(i));
         m_dragMode = TRUE;
         m_point = point;
         return;
      }
   }
      
   CToolBar::OnLButtonDown(nFlags, point);
}

void CDragToolBar::OnMouseMove(UINT nFlags, CPoint point) 
{
   if (m_dragMode && 
             abs(m_point.x-point.x)+abs(m_point.y-point.y)>=3) {
      PostMessage(WM_COMMAND, ID_START_DRAG);
      m_dragMode = FALSE;
   }
   CToolBar::OnMouseMove(nFlags, point);
}

Ну и во view тоже сделаем немного изменений:

void CDTBView::OnDragToolBar(UINT nCmdID)
{
   m_dragBtn = nCmdID;
}

void CDTBView::OnStartDrag() 
{
   BeginDrag();
}

 

Downloads

Скачать демонстрационный проект - 30 Kb
Скачать исходник - 2 Kb