уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Помнится года 2 назад попалась мне на глаза программа из разряда «бесполезное, но прикольное» под названием «Мышометр». Соответственно названию, программа измеряет расстояние пройденное мышкой. Причем не только в пикселях, но и в метрах, километрах, дюймах и, как ни странно, в зелёных президентах…

мыша

Помню, что тогда меня заинтересовало то, каким это волшебным образом программа переводит пиксели в метры? По сути пиксель — это условно-безразмерная величина и его размер зависит от многих параметров, например разрешения монитора.  Может и разобрался с этим вопросом, но как-то не хотелось долго заморачиваться, да и нужды особой в этом не было. А вот недавно, при разработке большого программного комплекса для экологов этот вопрос таки всплыл, только в несколько ином виде, а именно:  как при работе со сканированными рисунками с высокой точностью определять размеры реальных объектов, изображенных на схеме/карте и т.д.? Собственно, решение нашлось довольно быстро. Приведу его Вам на заметку. Для того, чтобы сильно не загружать Вас, уважаемые читатели, всякими терминами и определениями из области картографирования и экологии, напишем аналог того самого «Мышометра». Так Вы узнаете ответ на вопрос и, к тому же, узнаете как писать подобные программы-шутки.

1. Пара слов об определении размера пикселя.

В принципе, основных методов определения размера пикселя в миллиметрах в Интернете встречается два.

Первый метод — с использованием масштабного коэффициента, заданного в настройках Windows. При этом перевод длины какого-либо объекта из пикселей в миллиметры будет иметь вид:

width_mm:=width_pixels/PixelsPerInch*25.4

где width_pixels — длина объекта в пикселях, а PixelsPerInch — свойство объекта Screen, определяющее масштабный коэффициент пикселей/дюйм.

Второй способ — более сложный и заключается в определении какого-либо размера монитора (длины или ширины) в физических единицах, т.е., в нашем случае — в миллиметрах.

Для того, чтобы определить размер монитора в физиеских единицах измерения, нам достаточно воспользоваться функцией: GetDeviceCaps (DC: HDC; int:integer). С помощью этой функции можно получить специфическую информацию относительно экранного устройства. Этим устройством может быть как экран монитора, так и принтер с плоттером. В нашем случае, устройством является экран монитора.

Применительно к экрану монитора, параметр int в функции может принимать одно из следующих значений:

HORZSIZE — Ширина физического дисплея (в миллиметрах)
VERTSIZE — Высота дисплея (в миллиметрах)
HORZRES — Ширина дисплея (в пикселях)
VERTRES — Высота дисплея (в линиях растра)
LOGPIXELSX — Число пикселей на горизонтальный логический дюйм
LOGPIXELSY — Число пикселей на вертикальный логический дюйм
ASPECTX — Относительная ширина пикселя устройства, которая используется для линий рисунка
ASPECTY — Относительная высота пикселя устройства, которая используется для линий рисунка
ASPECTXY — Диагональная ширина пикселя устройства, которая используется для линии рисунка.

Как не трудно догадаться, использовать мы будем либо HORZSIZE либо VERTSIZE так как именно они возвращают размеры дисплея в мм.  Зная текущее разрешение монитора будет достаточно просто определить масштабный коэффициент, а именно — количество пикселей в одном милиметре и, исспользуя этот коэффициент, получать размеры объекта в мм.

Ну а теперь переходим к практике. Сравним два этих способа на предмет погрешностей и напишем программу, которая будет считать пробег мыши по экрану монитора.

2. Пишем свой «Мышометр» на Delphi.

Итак, запускаем Delphi, создаем новый проект и располагаем на главной форме приложения элементы, как показано на рисунке:

mishometr_1

Сразу обращу Ваше внимание, что эталонный прямоугольник добавлен просто для того, чтобы можно было визуально определять погрешности методов измерения размера объектов.

Теперь определяем необходимые переменные:

public
  doUpdate: boolean; //при значении true обновляет значение пройденного расстояния
  distance: single; //пройденное расстояние
  LastPos: TPoint; //последняя зафиксированная позиция курсора мыши
end;

Теперь напишем процедуру, определяющую все масштабные коэффициенты, а также длину эталонного прямоугольника. Кстати, сказать длина прямоугольника составляет 100 пикселей.

procedure TForm1.Button1Click(Sender: TObject);
var DC: HDC;
begin
  GetCursorPos(LastPos);
  doUpdate:=true;
  DC:=GetDC(Handle);
  label2.Caption:=intToStr(PixelsPerInch);
  label4.Caption:=CurrToStr(PixelsPerInch/25.4);
  label6.Caption:=IntToStr(Screen.Width)+'x'+IntToStr(Screen.Height);
  label8.Caption:=CurrToStr(Shape1.Width/PixelsPerInch*25.4);
  label10.Caption:=IntToStr(GetDeviceCaps(DC, HORZSIZE));
  label12.Caption:=CurrToStr(GetDeviceCaps(DC, HORZSIZE)/Screen.Width);
  label14.Caption:=CurrToStr(Shape1.Width*GetDeviceCaps(DC,   HORZSIZE)/Screen.Width);
end;

Запускаем приложение. И что мы видим?

mishometr_2

Получается, что оба метода имеют определенную погрешность, но второй метод более точный. Более того, первый метод никак не отреагирует на изменение разрешения экрана, например с 1024х768 на 800х600, несмотря на то, что при этом размер объекта на экране должен увеличиться. Таким образом, для определения расстояния, пройденного мышкой по экрану монитора, воспользуемся вторым методом.

Пишем процедуру определения пройденного расстояния.

procedure TForm1.Timer1Timer(Sender: TObject);
var curPos: TPoint;
  delta:real;
  DC: HDC;
begin
  DC:=GetDC(Handle);
  GetCursorPos(curPos);
  if (curPos.X<>LastPos.X)or(curPos.Y<>LastPos.Y) then
    if doUpdate then
      begin
        delta:=Sqrt(sqr(curPos.X-LastPos.X)+sqr(curPos.Y-LastPos.Y));
        distance:=distance+delta;
        LastPos:=curPos;
        label18.Caption:=CurrToStr(distance*GetDeviceCaps(DC,  HORZSIZE)/Screen.Width*0.001);
      end;
end;

Интервал срабатывания таймера необходимо ставить наименьшим, но, как показывает практика, сработает максимум 18 раз в секунду, несмотря на то, что параметр Interval можно выставить равным 1, но это уже другой вопрос. Проверяем программу

mishometr_3

После нажатия кнопки «Определить» программа начинает отсчитывать пройденное расстояние в метрах. Вот и все решение вопроса. Конечно, представленные методы определения расстояние не самые точные и, на самом деле в ГИС используются более сложные функции для работы со сканами изображений, но и представленные метод имеет право на существование.

Теперь можете модифицировать программу и попробовать определить скорость движения мыши :) Думаете это легко? Ничего подобного — стандартные TTimer Вам в этом вопросе не поможет, уверяю Вас.

0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
4 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Кирилл
Кирилл
26/10/2009 09:53

При вет!!! Есть один вопросик. Я работаю немного в друглй отрасли, но приложить мышку можно и там. Для меня более важно, как определить расстояние фактически пройденное оптической мышкой по рабочему столу в метрах. Есть проги?

trackback

[…] ранее рассмотренным проектом из статьи "Мышометры и им подобные звери". Доработаем проект таким образом, чтобы избавиться от […]

trackback

[…] delphi количество пикселей […]