Как разрешить перетаскивание окна за любую точку?

  • Автор темы Guest
  • Дата начала
Статус
Закрыто для дальнейших ответов.
G

Guest

#1
Как разрешить перетаскивание окна за любую точку?
 
G

Guest

#2
Демонстрационное приложение DragWin

Пример - приложение DragWin (диалоговое окошко, MFC) иллюстрирует
два способа осуществить перемещение окна с захватом его не только
за заголовок, но и за любую точку на клиентской области. Идея
первого способа проста - при получении сообщения о перемещении
мыши передвигаем наше окно в соответствии с новыми координатами.
Второй способ поизящнее, и заключается в некотором "обмане"
Windows, после которого она считает, что мышь находится над
заголовоком окна, даже если реально это уже клиентсткая часть.

Способ 1

Реализован для главного окна приложения. Заключается в написании
собственных обработчиков нажатия (WM_LBUTTONDOWN), перемещения
(WM_MOUSEMOVE) и отпускания (WM_LBUTTONUP) левой кнопки мыши.
Обработчики на данные события устанавливаются стандартным образом
- через MFC ClassWizard.
Код:
void CDragWinDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
 // выставим флажок - пошло перетаскивание
 m_bMoveWindow = TRUE;
 // все сообщения от мыши - к нашему окну, независимо от координат
 // чтобы мышь не улетала с окна при быстром движении
 SetCapture();
 // сохраняем координаты окна
 GetWindowRect(m_RectDlg);
 // сохраняем положение мышки внутри окна программы
 ClientToScreen(&point);
 m_MouseInDlg = point - m_RectDlg.TopLeft();
 // меняем курсор, чтоб веселее было тащить
 m_hCursor = m_hCursorDown;
 ::SetCursor(m_hCursor);

 // вызываем обработчик по умолчанию
 CDialog::OnLButtonDown(nFlags, point);
}

void CDragWinDlg::OnMouseMove(UINT nFlags, CPoint point)
{
 if (m_bMoveWindow) // надо тащить
 {
   // преобразуем координаты мыши в экранные
   // именно они нужны будут для SetWindowPos()
   ClientToScreen(&point);
   // двигаем окно в соответствии с новыми координатами мыши
   SetWindowPos(&wndTop,
     point.x - m_MouseInDlg.x, point.y - m_MouseInDlg.y,
     m_RectDlg.right - m_RectDlg.left,
     m_RectDlg.bottom - m_RectDlg.top,
     SWP_SHOWWINDOW);
   // поскольку обработчик по умолчанию все равно будет использовать
   // первоначальные параметры сообщения
   // обратное преобразование ScreenToClient(&point);
   // можно не вызывать
 }

 // вызываем обработчик по умолчанию
 CDialog::OnMouseMove(nFlags, point);
}

void CDragWinDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
 // перетаскивание закончилось
 m_bMoveWindow = FALSE;

 // "отпускаем" мышку
 ReleaseCapture();

 // меняем курсор на исходный
 m_hCursor = m_hCursorUp;

 // вызываем обработчик по умолчанию
 CDialog::OnLButtonUp(nFlags, point);
}

BOOL CDragWinDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
 // заменяем курсор на свой
 ::SetCursor(m_hCursor);

 return TRUE;
 // !!! было return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
Замена курсора естесственно не является критичной для собственно
перетаскивания, а добавлена исключительно для визуализации
процесса захвата окошка.

Способ 2

Реализован для окна About этого же приложения. Заключается в
замене обработчика события WM_NCHITTEST, которое информирует об
области, над которой в данный момент находится мышка. Обработчик
этого сообщения также можно добавить через MFC ClassWizard.
Предварительно на закладке ClassInfo для класса CAboutDlg нужно
установить для Message Filter значение Window.

Переписываем функцию - обработчик следующим образом:

Код:
UINT CAboutDlg::OnNcHitTest(CPoint point)
{
 UINT ret = CDialog::OnNcHitTest(point);

 // если обработчик по умолчанию говорит нам что мышка
 // над клиентской областью окна, заменяем возвращаемое
 // значение на HTCAPTION - мышка над заголовком окна,
 // а за заголовок перемещать окно можно!
 if (ret == HTCLIENT)
   return HTCAPTION;

 return ret;
}
Второй способ проще, первый потенциально гибче, используйте тот,
что лучше подходит к вашему конкретному случаю.
 
Статус
Закрыто для дальнейших ответов.