|
::Главная страница :: С++/Си :: Статьи ___ Еще раз о перетаскивании мышью окна за любую точку |
Пример - приложение DragWin (диалоговое окошко, MFC) иллюстрирует два способа осуществить перемещение окна с захватом его не только за заголовок, но и за любую точку на клиентской области. Идея первого способа проста - при получении сообщения о перемещении мыши передвигаем наше окно в соответствии с новыми координатами. Второй способ поизящнее, и заключается в некотором "обмане" Windows, после которого она считает, что мышь находится над заголовоком окна, даже если реально это уже клиентсткая часть.
Реализован для главного окна приложения. Заключается в написании собственных обработчиков нажатия (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); }
Замена курсора естесственно не является критичной для собственно перетаскивания, а добавлена исключительно для визуализации процесса захвата окошка.
Реализован для окна 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; }
Второй способ проще, первый потенциально гибче, используйте тот, что лучше подходит к вашему конкретному случаю.
Тематические
ссылки
|
Ваша ссылка | Ваша ссылка |
Обмен кнопками, ведение статистики, реклама. |
|||