Программирование на Паскале. Выпуск 10


Работа с мышью. 2

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

Вид курсора мыши зависит от режима

Во-первых, убедитесь в том, что в оконном режиме указатель "виндовский", а в полноэкранном - "текстовый" прямоугольник. Переключаться между режимами лучше всего с помощью комбинации Alt + ENTER.

Теперь видоизменим программу. Заставим ее читать содержимое экрана по курсором мыши. Именно так и организована работа многих ДОСовские справочных систем. При этом мы, конечно, будем читать не с экрана, а из видеобуфера. Прочитанное слово будем на несколько секунд показывать внизу экрана.

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

Вот полный листинг программы. Скопируйте в окно редактора Borland Pascal и запустите, а я тем временем буду рассказывать, как она работает:

program mouse_02a;
uses DOS, CRT;

const
  WordChars: Set of Char = ['A'..'п','р'..'я'];

procedure FillScreen;
var f: File of char; c: Char;
begin
  Assign(f, 'mou_02a.pas');
 {$I-} Reset(f); {$I+}
  if IOResult <> 0 then Exit;
  ClrScr;
  While NOT EOF(f) do begin
    Read(f, c); Write(c)
  end;
  Close(f);
end;

procedure ShowStatusBar(mes: String);
var buf: array[1..160] of byte;
    x, y: Integer; Attr: Byte;
begin
 Move(ptr(SegB800, 24*160)^, buf, 160);
 x:=WhereX; y:=WhereY;  Attr:=TextAttr;
 Attr:=$4e;
 GotoXY(1, 25); Write(copy(mes,1, 79));
 GotoXY(x, y); TextAttr:=Attr;
 Delay(500);
 Move(buf, ptr(SegB800, 24*160)^, 160);
end;

function IntToStr(Int: Integer): String;
var S: String;
begin
  Str(Int, s); 
  if length(s)=1 then s:='0'+s; 
  IntToStr:=S
end;

function ReadWordAtPos(X_pos, Y_Pos: Integer): String;
var S: String; i: Integer;
begin
  S:='';
  if chr(mem[SegB800:(Y_pos*80+X_Pos)*2]) in WordChars then
  begin
     S:=chr(mem[SegB800:(Y_pos*80+X_Pos)*2]);
     i:=-1;
     while chr(mem[SegB800:(Y_pos*80+X_Pos+i)*2]) in WordChars do
     begin
       s:=chr(mem[SegB800:(Y_pos*80+X_Pos+i)*2])+s;
       dec(i);
     end;
     i:=1;
     while chr(mem[SegB800:(Y_pos*80+X_Pos+i)*2]) in WordChars do
     begin
       s:=s+chr(mem[SegB800:(Y_pos*80+X_Pos+i)*2]);
       inc(i);
     end;
  end;
  if S = '' then S:='Нет слова';
  ReadWordAtPos:=S
end;

var
 r: Registers;
 x, y: Word;

BEGIN

  r.ax:=0;
  intr($33, r);
  if r.ax <> $FFFF then
   begin
     WriteLn('Мышь не обнаружена'); Halt(1)
   end;
  FillScreen;
  Write('Мышь обнаружена с ',r.bx,' кнопками');

  r.ax:=1;
  intr($33, r);
  repeat
    r.ax:=3;
    intr($33, r);
    if  r.bx and 1 <> 0 then
    begin
      x:=r.cx div 8;
      y:=r.dx div 8;
      r.ax:=2; intr($33, r);

      ShowStatusBar(IntToStr(x)+':'+
        IntToStr(y)+'  '+ReadWordAtPos(x,y));
      r.ax:=1; intr($33, r);
    end;
  until KeyPressed or (r.bx and 2 <> 0);
END.
Сразу замечу, что эта программа, по-прежнему, не оптимальна. "Мышиное" прерывание (с номером $33) позволяет и даже ориентировано на использование процедуры - обработчика событий от мыши. То есть, сейчас мы принудительно, нужно это или нет, вызываем прерывание, чтобы определить не случилось ли чего. В принципе, это должно существенно тормозить работу системы.

Вместо этого можно создать процедуру, которую СИСТЕМА САМА будет вызывать только тогда, когда что-либо произойдет с мышью. Об этом я напишу позднее. Сейчас не будем торопиться.

Итак, структура программы mou_02a.pas

Программа при нажатии на левую кнопку мыши "читает" слово, которое находится под "мышиным" курсором. А при нажатии на правую завершает работу.

Я добавил несколько подпрограмм, в которые "вынес" код, выполняющий конкретную группу действий. Это

  1. Процедура, которая заполняет экран текстом FillScreen. В данном случае просто исходным текстом программы. Вы, при желании, можете заменить имя открываемого файла любым другим. Эта процедура отрывает файл, рассматривая его как набор символов, и переносит их все на экран.
    Эта процедура вызывается в исполняемом блоке программы сразу же, как только убеждаемся, что можем получать события от мыши.
  2. Я написал процедуру ShowStatusBar, которая выводит сообщение mes на последней строке экрана. Для этого она копирует содержимое видеобуфера в переменную buf длиной 160 байт (еще помните, что это длина, которую занимает в памяти одна текстовая строка?). Копирование произведено с помощью процедуры Move.
    Затем запоминает, где находился текстовый курсор (не мышиный!) с помощью функций WhereX и WhereY, запоминает, какими цветами выводится текст. Эти цвета хранятся в переменной TextAttr, определенной в модуле CRT.
    После этого задаем цвет: желтые буквы на красном фоне и выводим в нижней строке текст сообщения длиной не более 79 символов.
    Даем задержку и опять возвращаем строку в исходное состояние опять же с помощью очень быстрой процедуры Move.
    Конечно, это не всегда нужно, но мне вдруг захотелось показать, как такой эффект можно реализовать. Прием можно использовать при создании меню.
  3. Я захотел написать и координаты точки экрана, где была нажата кнопка мыши. Для удобства я написал функцию преобразования чисел в строку IntToStr. В ней, по-моему, нет ничего особенного.
  4. "Чтение" реализует функция ReadWordAtPos. Ей передаются координаты точки X_pos и Y_Pos, а она "возвращает" результат типа String, в который записано слово, если оно под курсором было, или фразу "Нет слова" - если там были символы, из которых нельзя составить слово.
    Для удобства работы я определил постоянную WordChars типа "набор символов" (Set of char). Обратите внимание, что первый символ - это "A" англоязычное.
    С помощью логической функции in, которая определяет принадлежность диапазону, очень легко проверить - этот символ буква или нет.
    Сначала определяем, под курсором буква или нет? Если "да", то с помощью простого цикла while прибавляем к переменной S все символы слева и справа.
    По-моему, это просто
Ну вот и все особенности данной программы.

В следующем выпуске я планирую рассказывать о мыши на графическом экране, в том числе и о спрайтовой мыши. Именно, такую чаще всего используют в играх


Свои вопросы и предложения присылайте Борису

Мы приглашаем Вас и Ваших друзей к сотрудничеству. Напишите, какая проблема Вас лично интересует - и мы постараемся помочь Вам. Поделитесь со всеми, если Вам удастся найти красивое решение. Присылайте свои программы, и если они хороши, то опубликуем их с обязательным указанием Вашего авторства.

По всем вопросам можно писать либо в Гостевую книгу нашего сайта на www.turbopascal.tk, либо

мне, автору этого выпуска, © Сурину Борису: surin_bp@mail.ru, ICQ: 320096696.

Постараюсь ответить на все вопросы и учесть все разумные предложения

Рассылка поддерживается сайтом www.turbopascal.tk. При перепечатке ссылка на сайт обязательна

Hosted by uCoz