SetCursor возвращается после перемещения мыши - PullRequest
8 голосов
/ 04 октября 2008

Я использую SetCursor, чтобы установить системный курсор на собственное изображение. Код выглядит примерно так:

// member on some class
HCURSOR _cursor;

// at init time
_cursor = LoadCursorFromFile("somefilename.cur");

// in some function
SetCursor(_cursor);

Когда я делаю это, курсор меняется, но при первом сообщении о перемещении мыши он снова превращается в системный курсор по умолчанию. Это единственный код в проекте, который устанавливает курсор. Что мне нужно сделать, чтобы курсор остался таким, каким я его установил?

Ответы [ 5 ]

10 голосов
/ 04 октября 2008

Кажется, у меня есть два варианта. Первый из них, предложенный Марком Рэнсомом, заключается в том, чтобы ответить на сообщение windows WM_SETCURSOR и вызвать SetCursor в это время в зависимости от того, где находится мышь. Обычно окна будут отправлять вам WM_SETCURSOR только когда курсор находится над вашим окном, поэтому вы устанавливаете курсор только в вашем окне.

Другой вариант - установить курсор по умолчанию для дескриптора окна одновременно с вызовом SetCursor. Это меняет курсор, установленный обработчиком по умолчанию на WM_SETCURSOR. Этот код будет выглядеть примерно так:

// defined somewhere
HWND windowHandle;
HCURSOR cursor;

SetCursor(cursor);
SetClassLong(windowHandle, GCL_HCURSOR, (DWORD)cursor);

Если вы используете второй метод, вы должны вызвать оба SetCursor и SetClassLong, иначе ваш курсор не обновится до следующего движения мыши.

5 голосов
/ 04 октября 2008

Вам необходимо ответить на сообщение Windows WM_SETCURSOR .

2 голосов
/ 04 октября 2008

Вы должны сделать так, чтобы ваша ручка HCURSOR не выходила за рамки. Когда мышь перемещается, сообщения Windows начинают летать повсюду, и это уничтожит ваш дескриптор (в примере выше).

Сделайте HCURSOR закрытым членом класса и используйте этот дескриптор при вызове LoadCursor ... () и SetCursor (). Когда вы закончите, не забудьте освободить его и очистить, иначе у вас будет утечка ресурсов.

1 голос
/ 20 октября 2009

Такое поведение должно быть таким. Я думаю, что самое простое решение: при создании класса окна (RegisterClass || RegisterClassEx), установите WNDCLASS.hCursor || WNDCLASSEX.hCursor член NULL.

0 голосов
/ 18 октября 2016

Как сказал @Heinz Traub, проблема возникает из-за курсора, определенного в вызове RegisterClass или RegisterClassEx. У вас, вероятно, есть код вроде:

BOOL CMyWnd::RegisterWindowClass()
{
    WNDCLASS wndcls;
    // HINSTANCE hInst = AfxGetInstanceHandle();
    HINSTANCE hInst = AfxGetResourceHandle();

    if (!(::GetClassInfo(hInst, _T("MyCtrl"), &wndcls)))
    {
        // otherwise we need to register a new class
        wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
        wndcls.lpfnWndProc      = ::DefWindowProc;
        wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
        wndcls.hInstance        = hInst;
        wndcls.hIcon            = NULL;
        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
        wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
        wndcls.lpszMenuName     = NULL;
        wndcls.lpszClassName    = _T("MyCtrl");

        if (!AfxRegisterClass(&wndcls))
        {
            AfxThrowResourceException();
            return FALSE;
        }
    }

    return TRUE;
}

где wndcls.hCursor говорит, какой курсор будет использоваться при выдаче сообщения WM_SETCURSOR; это происходит каждый раз, когда происходит движение мыши, и не только.

Я решил похожую проблему следующим образом:

В карте сообщений класса добавьте запись для сообщения WM_SETCURSOR:

BEGIN_MESSAGE_MAP(CMyWnd, CWnd)
    //... other messages
    ON_WM_SETCURSOR()
END_MESSAGE_MAP()

Добавьте метод OnSetCursor, который переопределит реализацию родительского класса:

BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (SomeCondition())
        return FALSE;

    return __super::OnSetCursor(pWnd, nHitTest, message);
}

Объяснение: когда SomeCondition() истинно, вы не будете вызывать реализацию родителя. Может быть, вы всегда хотите, чтобы курсор не заменял поведение родительского класса, поэтому вам просто нужен еще более короткий метод:

BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    return FALSE;
}

И объявление метода в заголовочном файле:

afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...