#c #windows #c builder-2007
#c #Windows #c builder-2007
Вопрос:
Мне необходимо каким-то образом разрешить перемещение окна с помощью опции перетаскивания правой кнопкой мыши. Я сделал это с помощью какого-то хитрого кода, который мне не очень нравится, но он работает.
В настоящее время я перехватываю сообщение WM_NCRBUTTONDOWN и устанавливаю bool, чтобы сказать, что я нахожусь в режиме перемещения, сбрасывая эту переменную при получении WM_NCRBUTTONUP. В режиме перемещения я проверяю наличие WMNCMouseMove и сам перемещаю форму. Поскольку это медленно, чтобы не отставать от быстрых движений мыши, я также установил таймер, чтобы сделать то же самое, используя GetCursorPos .
Недавно я обнаружил функцию SwapMouseButton, и это делает именно то, что я хочу. Однако есть но! Мне нужно поменять его условно и только тогда, когда пользователь щелкнул правой кнопкой мыши область ЗАГОЛОВКА окна.
Поэтому я меняю местами кнопки мыши, когда получаю WM_NCRBUTTONDOWN и сбрасываю WM_NCRBUTTONUP. Однако это будет работать при последующих щелчках при условии, что WM_NCRBUTTONUP никогда не сбрасывает его. Я думаю, это связано с тем, что событие щелчка уже произошло, поэтому слишком поздно менять местами, поэтому оно работает для последующих нажатий правой кнопкой мыши, но не для щелчка правой кнопкой мыши и перетаскивания, что привело к замене мыши!
Кто-нибудь может найти способ обойти это. Имея в виду, что мне нужна функция щелчка левой кнопкой мыши для кнопок закрытия, сворачивания, разворачивания и т.д. Щелкните правой кнопкой мыши onyl для перемещения!
Пожалуйста, помогите!!!!!
Спасибо, Джо
Ответ №1:
Вместо того, чтобы вручную отслеживать мышь или менять местами кнопки, есть более простой способ — в ответ на WM_NCRBUTTONDOWN
, просто переведите окно в режим перемещения изначально, отправив ему специальное WM_SYSCOMMAND
сообщение, тогда оно выполнит всю тяжелую работу по перетаскиванию за вас, например:
const WPARAM MOUSE_MOVE = SC_MOVE 2;
case WM_NCRBUTTONDOWN:
{
POINT pt;
GetCursorPos(amp;pt);
SendMessage(Handle, WM_NCRBUTTONUP, 0, MAKELPARAM(pt.x, pt.y));
SendMessage(Handle, WM_SYSCOMMAND, MOUSE_MOVE, MAKELPARAM(pt.x, pt.y));
break;
}
См. Q114593 для получения более подробной информации.
Обновление: я не смог приступить WM_SYSCOMMAND
к работе с щелчком правой кнопкой мыши (хотя это отлично работает при щелчке левой кнопкой мыши по дочерним элементам управления). Я думаю, что ОС выполняет некоторую внутреннюю обработку, которая просто делает невозможной корректную работу. Поэтому я пошел с подходом перехвата движений мыши для перемещения окна вручную, что позволяет ему корректно работать с быстрыми движениями мыши без использования таймера, используя SetCapture()
вместо:
bool RightButton_CanMove = false;
bool RightButton_WindowMoved = false;
POINTS LastPoint;
void __fastcall TForm1::WndProc(TMessage amp;Message)
{
switch( Message.Msg )
{
case WM_NCRBUTTONDOWN:
LastPoint = MAKEPOINTS(Message.LParam);
RightButton_CanMove = true;
RightButton_WindowMoved = false;
SetCapture(Handle);
Message.Result = 0;
return;
case WM_MOUSEMOVE:
if( (Message.WParam amp; MK_RBUTTON) amp;amp; (RightButton_CanMove) )
{
POINT CurPoint;
GetCursorPos(amp;CurPoint);
SetWindowPos(Handle, NULL, Left (CurPoint.x - LastPoint.x), Top (CurPoint.y - LastPoint.y), 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
LastPoint.x = CurPoint.x;
LastPoint.y = CurPoint.y;
RightButton_WindowMoved = true;
}
break;
case WM_RBUTTONUP:
if( RightButton_CanMove )
{
RightButton_CanMove = false;
ReleaseCapture();
if( RightButton_WindowMoved )
{
RightButton_WindowMoved = false;
Message.Result = 0;
return;
}
}
break;
}
TForm::WndProc(Message);
}
Код различает операции щелчка правой кнопкой мыши и перемещения вправо. Если пользователь щелкает правой кнопкой мыши, не перемещая ее, всплывающее меню по умолчанию отображается нормально. Если пользователь удерживает правую кнопку мыши нажатой и перемещает окно, всплывающее окно по умолчанию не отображается, когда пользователь отпускает правую кнопку.
Комментарии:
1. Это намного лучший способ, но, похоже, не работает -код выглядит следующим образом: void __fastcall TForm2::WndProc(TMessage amp;Message) { переключатель ( сообщение. Сообщение ) { case WM_NCRBUTTONDOWN: { const WPARAM MOUSE_MOVE = SC_MOVE 2; ТОЧКА pt; GetCursorPos(amp;pt); SendMessage(дескриптор, WM_NCRBUTTONUP, 0, MAKELPARAM(pt.x, pt.y)); SendMessage(дескриптор, WM_SYSCOMMAND, MOUSE_MOVE, MAKELPARAM( pt.x, pt.y)); break; } по умолчанию: { break; } } TForm::WndProc(сообщение); }
2. Вы передаете сообщение WM_NCRBUTTONDOWN унаследованному WndProc() для обработки по умолчанию после отправки сообщений WM_NCRBUTTONUP и WM_SYSCOMMAND. Пытаюсь сделать этот шаг.
3. Привет, не передача WM_NCRBUTTONDOWN унаследованному WndProc не решает проблему. У вас есть какие-либо другие идеи? Для этого я использую фреймворк (Borland C Builder). Имеет ли это значение? Еще раз спасибо!
4. Кроме того, почему в вашем примере вы устанавливаете для параметра WPARAM значение SC_MOVE 2? Если я просто отправлю SC_MOVE в качестве параметра в WM_SYSCOMMAND, я получу забавный курсор, но по-прежнему не выполняю никаких действий?
5. Вы читали статью, на которую я вам указал?
SC_MOVE 2
имеет особое значение для Windows. Я также использую C Builder, я постараюсь опубликовать рабочий пример в ближайшее время.