Получить координаты сообщения WM_NCHITTEST? - PullRequest
7 голосов
/ 17 декабря 2010

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

Ответы [ 3 ]

13 голосов
/ 17 июня 2011

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

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

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

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

Double monitor setup

Как видите, верхний левый угол монитора 2в координатах (1280, -256).Если вы используете решение, показанное выше, вы получите что-то вроде 65505, если мышь на самом деле на -30.Это связано с тем, что позиции хранятся в старших и младших разрядах WORD от LParam.Таким образом, выполнение (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());
11 голосов
/ 17 декабря 2010

Из 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);
8 голосов
/ 30 ноября 2014

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

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

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

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

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

...