Графические устройства



 

Вывод информационных строк

В процессе выполнения графических программ на экран могут выводиться информационные строки, которые делятся на две основные категории.

К первой категории относятся напоминания о назначении различных значков, находящихся на экране, не требующие конкретной реакции оператора. Например, одно из подобных сообщений, выдаваемых Windows 9X, выглядит так:

"Начните работу с нажатия этой кнопки".

Обычно такие строки через некоторое время удаляются с экрана.

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

В данном разделе мы рассмотрим общую схему вывода информационных строк, а в следующих — программирование ввода текста в ответ на подсказку оператору. При изложении материала нас будет интересовать вывод отдельных строк, а не больших объемов текста, именно поэтому в заголовке раздела использовано выражение "информационная строка". При работе с текстами большего объема применяются совершенно другие приемы.

Расположение и адрес строки

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

Где бы ни располагалась информационная строка для работы, надо знать адрес ее начала в видеопамяти и соответствующее ему окно. При построении изображения символа знакогенератор выводит точки на экран в том порядке, в котором их коды хранятся в таблице, а именно слева направо и сверху вниз. Поэтому для вывода текста надо знать адрес верхнего левого угла первого символа информационной строки. Для его хранения в разделе данных программы надо описать две следующие переменные:

Inflino dw 0; для хранения адреса начала информационной строки
Inflinw dw 0; для хранения окна, к которому относится этот адрес

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

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

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

Если верхнюю линию изображения текста поместить в строку с номером (versize - hsymb), то его нижняя линия совпадет с нижней границей рабочей области экрана.

Замечание
Напомним, что переменные Horsize и versize содержат соответственно размер строк и их количество на экране, а переменная hsymb— высоту символа (см. пример 5.18), ее значение зависит от используемой таблицы.

Предположим, что левый край информационной строки расположен в нулевом столбце рабочей области экрана. В таком случае нам нужен адрес видеопамяти, соответствующий точке, расположенной .в рабочей области экрана на пересечении нулевого столбца и строки с номером (versize - hsymb). Его можно вычислить, например, как приведено в примере 5.20.

Пример 5.20. Вычисление адреса начала информационной строки

mov ax, versize ; ax = количество строк на экране
sub ax, hsymb ; уменьшаем его на высоту символа
mul horsize ; разность умножаем на размер строки
mov Inflino, ax ; сохраняем адрес в Inflino
mov ax, dx ; копируем содержимое dx в ах
mul GrUnit ; вьиисляем номер окна
mov Inf linw ; и сохраняем его в Inflinw

Если выводимый текст смещен относительно левого края информационной строки, то вычисленное в примере 5.20 значение переменной Inflino надо увеличить на соответствующее число столбцов.

Манипуляции с исходным фоном

Информационная строка, как правило, располагается не на пустом экране. Поэтому надо сохранять изображение в той части рабочей области экрана, которую займет текст, и восстанавливать его при удалении текста с экрана. Сохраняемые коды точек изображения копируются из видеопамяти в оперативную память, так чтобы потом их можно было вернуть на прежнее место.

Подпрограммы копирования строки видеопамяти в оперативную память приведены в примерах 3.19 и 3.20, нам остается применить их для пересылки нескольких строк. Восстановление сохраненного фона ничем не отличается от построения рисунка, полностью помещающегося в оперативной памяти. Соответствующая подпрограмма описана в примере 3.21.

Для использования указанных или аналогичных подпрограмм пересылки надо знать исходные адреса видео и оперативной памяти и количество пересылаемых байтов. Начнем с последнего.

Размер и размещение фона

Высота информационной строки нам известна, точнее мы знаем, что ее значение хранится в переменной hsymb. Ширина строки равна произведению ширины символов на их количество, но последнее является переменной величиной. Ее значение зависит как от размера текста сообщения, так и от ответа оператора, если таковой подразумевается. Поэтому лучше выбрать ширину информационной строки равную ширине рабочей области экрана (значению переменной Horsize). При использовании стандартных таблиц в такой строке можно разместить 80, 100, 128 или 160 символов, в зависимости от установленного видеорежима. Чем выше разрешение, тем мельче изображение символов на экране и тем труднее читать текст, поэтому при работе с высоким разрешением вам могут понадобиться таблицы с более крупными символами.

Если информационная строка занимает всю ширину экрана, то количество сохраняемых байтов и размер буфера для их размещения вычисляются как произведение значений переменных Horsize и hsymb. Если hsymb = 16, то, в зависимости от видеорежима PPG, информационная строка содержит следующее количество байтов: 101h - 7680, 103h - 9600, 105h - 12288, 107h - 16384. При работе в режимах Hi-Color указанные числа увеличатся в два раза, а в режимах True Color — в четыре раза. Очевидно, что буфер таких размеров нецелесообразно располагать в разделе данных задачи, для него надо выделить отдельное место в оперативной памяти ПК.

Способы резервирования пространства оперативной памяти описаны в приложении Б данной книги. При программировании задачи надо следить за тем, чтобы это пространство не использовалось по другому назначению. Для этого надо имя переменной, содержащей адрес выделенного сегмента, использовать только в подпрограммах сохранения и восстановления исходного фона информационной строки, но есть и другой способ защиты.

Нужный нам буфер можно расположить в начале сегмента общего назначения, выделенного в разделе для временного хранения распакованной строки рисунка. Код сегмента хранится в переменной GenSeg, а начало свободного в нем пространства в переменной GenOffs. Если Genoffs присвоить значение horsize и hsymb, то соответствующая часть сегмента будет недоступна другим подпрограммам, при условии, что они используют адрес, хранящийся в Genoffs, и не уменьшают его.

Таким образом, адрес начала информационной строки в видеопамяти хранится в переменных inf lino и inf linw, а буфер для ее размещения расположен в начале сегмента, указанного в переменных Genoffs и GenSeg.

Подпрограмма Savinfo

Текст подпрограммы, выполняющей сохранение исходного фона, приведен в примере 5.21. Перед ее вызовом надо сохранить содержимое переменной cur_win и поместить в нее номер окна из переменной infiinw, предварительная установка этого окна не требуется.

Пример 5.21. Сохранение фона на месте информационной строки

Savinfo: PushReg <Cur_win,ax,ex,si,di,fs,es>; сохранение в стеке
call setwin установка исходного окна
mov fs, Vbuff fs = сегмент видеобуфера
mov si, Inflino si = адрес начала информ. строки
mov es, GenSeg es = сегмент общего назначения
xor di, di di = 0 — смещение в GenSeg
mov ax, horsize ax = ширина экрана
mul byte ptr hsymb умножаем ее на высоту символа
mov ex, ax копируем результат в сх
shr сх, 02 уменьшаем его в 4 раза
Savlp: movs dword ptr [di] fs:[si]; копирование двойного слова
or si, si адрес в пределах видеосегмента ?
jnc @F -> да, переход на команду loop
call nxtwin установка следующего окна
@@: loop savlp » управление циклом копирования
PopReg <es,fs,di,si,cx,ax,Cur_win>; восстановление из стека
call setwin ; восстановление исходного окна
ret ; возврат из подпрограммы

В примере 5.21 копирование содержимого видеопамяти в оперативную выполняет строковая операция movs, у которой приемник находится в регистрах es:di, а источник в fs:si. Содержимое этих регистров формируется перед циклом пересылки. Затем вычисляется размер информационной области в байтах, и результат преобразуется в количество двойных слов. Строки рабочей области экрана копируются полностью, поэтому нужен только один цикл, в котором пересылается сразу по 4 байта. Цикл пересылки повторяет аналогичный цикл из примера 3.20 с той разницей, что копируются не байты, а двойные слова.

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

Подпрограмма Delinfo

Текст подпрограммы, восстанавливающей исходный фон из оперативной памяти, приведен в примере 5.22. Перед ее вызовом надо сохранить содержимое переменной Cur_win и поместить в нее номер окна из переменной infiinw, предварительная установка этого окна не требуется.

Пример 5.22. Восстановление фона на месте информационной строки

Delinfo : PushReg <Cur win, ax , ex, si, di, fs>; сохранение в стеке
call setwin установка исходного окна
mov di, Inflino di = адрес начала информ. строки
mov fs, GenSeg fs = сегмент общего назначения
xor si, si si = смещение в GenSeg (0)
mov ax, horsize ах = ширина экрана
mul byte ptr hsymh ) умножаем ее на высоту символа
mov ex , ax копируем результат в сх
shr ex, 02 и уменьшаем его в 4 раза
Dellp: movs dword prr [di fs:[si]; копирование двойного слова
or di, di адрес в пределах видеосегмента ?
jne @F -> да, переход на команду loop
call nxtwin установка следующего окна
@@: loop dellp управление циклом копирования
PopReg <fs,di,si,cx , Cur win>; восстановление из стека
call setwin восстановление исходного окна
ret возврат из подпрограммы

В примере 5.22 данные пересылаются из оперативной в видеопамять, что и объясняет все различия текстов примеров 5.21 и 5.22. Цикл пересылки, практически, повторяет анапогичный цикл из примера 3.15 с той разницей, что копируются не байты, а двойные слова. Подразумевается, что регистр es содержит код видеосегмента, указанный в переменной vbuff.

Замечание
При компиляции инструкции movs в том виде, как она записана в примерах 5.21 и 5.22, Макроассемблер MASM 5.1 выдает предупреждающее сообщение, но генерирует правильный код. На это сообщение можно не обращать внимание.

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

Упрощение подпрограмм

Во всех режимах PPG при выбранном нами размере и расположении информационная строка полностью помещается в последнем окне видеопамяти. Поэтому в цикле пересылки проверять значение текущего адреса видеопамяти не имеет смысла. В примерах 5.21 и 5.22 циклы пересылки состоят из пяти команд и имеют метки savip и oeiip. Все пять команд надо исключить из текста примеров, а вместо них записать одну команду, одинаковую в обоих случаях:

rep movs dword ptr [di],fs: [si]/цикл пересылки для примеров 5.21, 5.22.

Кроме этого, из списка параметров макровызовов PushReg и PopReg надо исключить имя переменной cur_win и удалить команду-call setwin перед ret.

Упрощенный вариант подпрограмм можно использовать, только если информационная строка полностью расположена в одном окне. Кроме рассмотренного нами случая, это условие выполняется, если строка расположена вверху рабочей области экрана (коды ее точек расположены в нулевом окне видеопамяти).

Вывод информационной строки. Мы описали сопутствующие действия и можем, наконец, рассмотреть конкретную подпрограмму для вывода строки на экран. Ее текст приведен в примере 5.23. Перед обращением адрес начала строки помещается в регистр si, предполагается, что строка расположена в разделе данных задачи. Признаком конца строки является пустой байт, т. е. строка подготавливается в формате ASCIIZ.

Пример 5.23. Вывод текста информационной строки

Outlnf: push Cur_win ; сохранение исходного значения Cur_win
mov ax, Inflinw ; ax = номер окна информационной строки
mov Cur_win, ax ; Cur_win = ax
call Savinfo ; сохранение исходного фона
jmp short outstr ; переход на выборку первого символа
outl: call outsgn вывод на экран очередного символа
outstr: lodsb al = К°Д очередного символа (al = ds:si)
or al, al конец выводимого текста ?
jne outl -> нет, переход на метку outl ;
Здесь могут выполняться сопутствующие действия pop Cur_win восстановление исходного значения Cur win
call setwin восстановление исходного окна
ret возврат из подпрограммы

Собственно вывод текста в примере 5.23 выполняется в цикле, состоящем из четырех команд. Первая из них имеет имя outl, но точкой входа является следующая команда, имеющая метку outstr. Код очередного символа строки считывается в регистр al, и если он не равен нулю, то происходит возврат на метку outl для обращения к подпрограмме outsgn (см. пример 5.19). Цикл повторяется, пока в строке не будет обнаружен пустой байт.

При желании вы можете изменить цикл так, чтобы использовался другой признак конца строки или задавалось количество символов в строке. Однако формат ASCIIZ является наиболее удобным.

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

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

 
Назад Начало Вперед