Проблема
В окнах координаты, возвращаемые для события «кнопка мыши вниз», кажутся немного неправильными для курсора I-Beam. По сути, координата x всегда находится в двух пикселях от того места, где она должна быть.
Я написал очень простую программу для win32, чтобы продемонстрировать проблему. Все, что он делает, это превращает курсор в IBeam и визуализирует вертикальную красную линию, где было последнее событие нажатия мыши. Я ожидаю, что красная линия точно совпадет с вертикальной частью двутавровой балки, но это не так.
Вот скриншот того, что происходит .
Как видите, красная линия находится в двух пикселях слева от того места, где она должна быть (поведение для стандартного указателя стрелки правильное), поэтому создается впечатление, что точка доступа для курсора I-Beam неверна.
У меня есть кто-то еще, работающий под управлением Windows 7 64-битный, подтвердите, что они сталкиваются с той же проблемой, но другой тестер на Vista не имеет проблемы.
Некоторая информация о моем окружении
- Windows 7 64 бит. Конфигурация полностью по умолчанию (т.е. без масштабирования DPI, без странных тем и т. Д.)
- Visual Studio Express 2010
- Видеокарта NVidia с последними драйверами (v270.61)
- Включение или выключение Aero не имеет значения. Выбор разных курсоров в настройках дисплея не имеет значения
Соответствующие биты кода
Мой тестовый проект - это в основном шаблон Win32 Project в Visual C ++ 2010 с изменениями, описанными ниже.
Вот код, где я регистрирую класс окна и устанавливаю курсор на I Beam
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CURSOR_TEST));
wcex.hCursor = LoadCursor(NULL, IDC_IBEAM); // this is the only line I changed in this function
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CURSOR_TEST);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
Вот соответствующие части из моего основного цикла сообщений:
case WM_LBUTTONDOWN:
// record position of mouse down.
// xPos and yPos are just declared as
// global ints for the purpose of this test
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
// cause redraw
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
break;
case WM_PAINT:
// paint vertical red line at position of last click
hdc = BeginPaint(hWnd, &ps);
RECT rcClient;
GetClientRect(hWnd, &rcClient);
hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
SelectObject(hdc, hPen);
MoveToEx(hdc, xPos, 0, NULL);
LineTo(hdc, xPos, rcClient.bottom);
DeleteObject(hPen);
EndPaint(hWnd, &ps);
break;
Резюме
Я много гуглил для ответов, но не могу найти что-нибудь подходящее. Я делаю что-то не так с обработкой входящих координат курсора?
Спасибо!
РЕДАКТИРОВАТЬ: дополнительная информация после проницательных вопросов в комментариях
Руководствуясь @Mark Ransom в комментариях, я использовал функцию GetIconInfo
, чтобы получить больше информации о курсоре I-Beam. Структура ICONINFO
для курсора указывает, что координата x для горячей точки курсора равна x = 8. Однако, когда я выгружаю растровое изображение для курсора (элемент hbmMask
структуры ICONINFO
, так как это монохромный курсор), вертикальная полоса находится в 10 пикселях слева от изображения, а не в 8 пикселях. Как указывает Марк, это, вероятно, является причиной визуальной несоответствия, но почему это произошло и как я могу это исправить?
(я также заметил, что ответ на этот другой вопрос содержит некоторую интересную информацию о том, как обрабатываются курсоры I-Beam. Интересно, уместно ли это)