Получить координаты сообщения WM_NCHITTEST?

Как получить координаты сообщения WM_NCHITTEST в коде C#?
Я хотел бы получить самый быстрый способ, потому что производительность является требованием.

3 ответа

Решение

Из MSDN:

WPARAM
Этот параметр не используется.

LPARAM
Слово младшего разряда определяет x-координату курсора. Координата относительно левого верхнего угла экрана.
Старшее слово определяет y-координату курсора. Координата относительно левого верхнего угла экрана.

Так что вам просто нужно извлечь младшие и старшие слова из сообщения lParam:

int x = lParam.ToInt32() & 0x0000FFFF;
int y = (int)((lParam.ToInt32() & 0xFFFF0000) >> 16)
Point pos = new Point(x, y);

Я бы не стал сильно беспокоиться о производительности, так как эти операции - всего лишь битовая арифметика...

Обратите внимание, что эти координаты относятся к экрану. Если вы хотите координаты относительно элемента управления (или формы), вы можете использовать PointToClient метод:

Point relativePos = theControl.PointToClient(pos);

До этого утра я бы согласился на 100% с ответом Томаса Левеска, я вытащил ту же информацию из msdn, и код (казалось бы) работал отлично. Однако есть один случай, когда вас это укусит, мне понадобилось три часа, чтобы найти причину сегодня днем.

Симптом, который у меня был, заключался в том, что на одной из моих машин разработки в IDE VS2010 мой элемент управления можно было выбирать только нажатием, когда я щелкал по нему в определенной позиции y. Очень маленькие элементы управления в верхней части формы вообще не могли быть выбраны щелчком мыши. Размер области, на которую нельзя было щелкнуть мышью, выглядел идентично размеру среды IDE, окружающей дизайнер Windows Forms, поэтому сначала я подумал, что у меня возникла странная, малоизвестная проблема DesignMode. Самым запутанным моментом было то, что точно такой же проект (извлеченный из TFS на другом компьютере) не продемонстрировал бы такое поведение.

Вот что происходит:

Представьте, что у вас двойная настройка монитора, как показано здесь (извините за скриншот на немецком языке, у меня под рукой нет английской ОС):

Двойная настройка монитора

Как видите, верхний левый угол монитора 2 находится в координатах (1280, -256). Если вы используете решение, показанное выше, вы получите что-то вроде 65505, если мышь на самом деле на -30. Это связано с тем, что позиции хранятся в старших и младших разрядах. WORD Л.Парам. Итак, делая (lParam.ToInt32() & 0xFFFF0000) >> 16 даст вам правильные биты для y-позиции. Однако приведение к int приводит к получению 65505, поскольку вы приводите неверный тип данных.

Решение:

int x = (short)(lParam.ToInt32() & 0x0000FFFF);
int y = (short)((lParam.ToInt32() & 0xFFFF0000) >> 16);
Point pos = new Point(x, y);

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

Я недавно обнаружил, что один из конструкторов Point воля к работе для вас. Итак, короткая версия:

Point pos = new Point(lParam.ToInt32());

Я знаю, что на этот вопрос уже был дан ответ, и все, кроме...

Point p = new Point(m.LParam.ToInt32());

System.Drawing.Point теперь имеет конструктор, специально предназначенный для принятия этого точного значения. Строго говоря, я думаю, что это, наверное, самый простой способ.

Честно говоря, я понятия не имею, существовал ли этот конструктор, когда были опубликованы другие ответы.

Это все, что говорится, это, вероятно, не так быстро, потому что ответ Такрла почти наверняка то, что вышеупомянутый конструктор в любом случае делает внутренне.

Другие вопросы по тегам