Использование кнопки SwapMouseButton( TRUE ); разрешить перетаскивание окна правой кнопкой мыши

#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, я постараюсь опубликовать рабочий пример в ближайшее время.