Последний раз обновлено 27.06.01
Просмотр файла с памятью (проект VM)
Если мы хотим использовать больше возможностей, чем создавать файлы диагностики или выдавать строчку "здравствуй мир", то нам надо определить удобный ввод с клавиатуры от горячих клавиш и окна отображения. В сам язык не входят средства ввода-вывода. Стандартная библиотека предоставляет работу с потоками, но мы пока не будем писать то, что нам надо через потоки, так как это хотя и здорово, но сложно. Пока привяжемся конкретно к двум устройствам - окно текстового режима ДОС или WIN32 и клавиатура. Драйвером с этими устройствами для нас будет та часть библиотеки компилятора, которая отражена в conio.h.
Ввод и вывод на основе conio.h
Основная цель, стоящая перед перед этим объектом - посылать сообщение любому объекту или вызывать простую функцию при нажатии клавиши. Возможны все сочетания клавиш, которые различаются getch()
. Для проверки наличия нажатой клавиши и вызова сообщения, связанного с этой клавишей, программа должна вызвать сообщение action()
.
Непосредственно с клавишей или сочетанием связана функция фиксированного типа - функция отклика, которая может быть сразу дружественной какому-то классу, либо, что лучше, вызывать сообщение, может быть виртуальное, уже принадлежащее какому-то классу. Сама функция отклика определена как не принадлежащая ни к какому объекту. Функция отклика устанавливается сообщением install()
или replace()
. Только один набор функций отклика доступен в каждый момент времени.
Честно говоря, этот объект задумывался и использовался задолго до внедрения ООП в мои программы, поэтому он носит много рудиментарных вещей и может выглядеть странно, но это компромис для совместимости с моими старыми не объектными программами. Так как наша задача не ввод-вывод и его обсуждение, а его использование, то нам все равно, как сделан этот объект и почему, а я новый простой объект делать специально не захотел. Он все же более подходит, чем простой ввод с потока.
Вот классы и типы, используемые для клавиатуры:
| ||
| ||
| ||
| ||
Тип функции отклика t_keyb_action_f
| ||
|
Объект Tkeyb_key
описывает кнопку или сочетание, которое можно получить от getch()
. Эта функция возвращает или символ, или два, если первый символ равен нулю. Это позволяет иметь 2*256-1 отдельных сочетаний клавиш, но не все используются. Посмотреть сочетания клавиш, которые возвращаются getch()
, можно для ДОС утилитой keyview(download keyview). Этот объект содержит тип кнопки ( KEY_EXT
для двухбайтового кода ) и сам код.
С каждым сочетанием клавиш связан элемент таблицы реакций на кнопку Tkeyb_action
. Его поля это функция отклика и указатель на объект, который используется, если надо вызывать сообщение объекта.
Все элементы таблицы реакций объединены в одну таблицу реакций на кнопки Tkeyb_actions
. Этот объект имеет поле таблица кнопок, как массив [2][256]. Первый индекс соответствует типу кнопки Tkeyb_key
, второй коду кнопки. Таблицу можно скопировать в другую или очистить сообщением clear()
.
Функцию отклика удобно обявлять и определять, используя макрос KEYB_ACTION(имя_функции)
. Параметры, нажатая кнопка и указатель на объект, могут использоваться для дополнительной селекции, если одна функция отклика отвечает за несколько кнопок.
Создать объект можно без или по готовой таблице реакций. Мы будем использовать только конструктор по умолчанию и один глобальный объект клавиатуры. При удалении деструктор освободит память, выделенную конструктором по умолчанию под таблицу реакций.
Мы будем использовать такие сообщения Tkeyb
| ||
| ||
|
Параметр wait
в сообщении action()
задает опрос клавиатуры либо с ожиданием нажатия, либо без для выполнения еще и других задач в цикле, так как наша среда выполнения не многозадачна и мы не используем прерывания. Сообщение replace()
устанавливает действие и возвращает предыдущую функцию отклика. Эти сообщения так же имеют форму для работы без объекта получателя сообщения от нажатия кнопки. Подробности в листинге.
При работе только с одной таблицей реакций, диалоговое окно, например, может потребовать блокировать все сообщения для других, неактивных окон. Легче всего это сделать сохранив существующее состояние таблицы, затем очистив ее и заполнив нужными функциями отклика, после работы диалога восстановив старое состояние. Для доступа к таблице реакций используется сообщение к Tkeyb
получить таблицу Tkeyb_actions
.
Tkeyb_actions_p get_keyb_actions();
Ввод и вывод на основе conio.h
Простой десктоп Tdesktop (easywin.h)
Устоявшимся способом отображения является отображения в логические области экрана - окна. Нам нужны только текстовые окна. Чтобы развязать окна от типа экрана и, возможно, использовать управление сразу всеми окнами на экране, будем использовать что-то вроде драйвера экрана - десктоп. Сам десктоп будет основан на функциях вывода из conio.h.
Простой десктоп Tdesktop (easywin.h)
Свойствами, доступными окнам десктопа и другим элементам программы являются эти
| ||
|
Хотя эти свойства доступны и для записи, использовать их стоит только для чтения. Позиция курсора считается от 0 и за 0,0 принимается левый верхний угол экрана. Вместе с десктопом ассоциируется объект клавиатуры Tkeyb
.
Простой десктоп Tdesktop (easywin.h)
Создать объект можно либо конструктором по умолчанию, либо указав уже существующий объект клавиатуры. При удалении деструктор удалит объект клавиатуры, если десктоп был создан конструктором по умолчанию.
Простой десктоп Tdesktop (easywin.h)
Для десктопа будем использовать следующие операции
| ||
| ||
|
Простой десктоп Tdesktop (easywin.h)
Вспомогательными операциями являются
| ||
|
Допустимые параметры type
и mode
определены для BC45. Под другим компилятором, возможно, придется корректировать код методов этих сообщений.
Ввод и вывод на основе conio.h
Под окном Twin
мы будем понимать объект, который
Содержимое хранится в списке lines
. Свойствами отображения являются
| ||
|
Цвета задаются и читаются сообщением =
(присвоить) и имеют действие при следующей регенерации окна. Размер окна устанавливается сообщением set_size()
. Заметим, что в свойства отображения не входят координаты окна в десктопе или где нибудь еще, как в десктоп не входят положение ручек «яркость» и «контрастность» на мониторе.
Для организации различного вида окон, будем использовать список children
дочерних окон. Наши дочерние окна позволят создать такие элементы окна, как
Эти элементы окна являются для пользователя единым окном, в основном сохраняют свое положение относительно главного и отображаются и перемещаются вместе с главным. Если требуется дочернее окно более свободное, то не следует его, может быть, включать в этот список.
Для отображения данных окна и всех его дочерних окон нам, подобно случаю с клавиатурой, придется самим вызывать сообщение refresh()
. Если нужно установить окно и все дочерние только согласно цветам bk_color
, то надо вызвать сообщение clear()
. Для управления видимостью окна и его дочерних при отображении используется сообщение hide()
.
С окном удобно связать так же ряд свойств, не относящихся прямо к данным окна или их отображению, но позволяющих управлять этим от клавиатуры или чего-нибудь еще. Понятно, что несколько окон на десктопе могут использовать одинаковые клавиши для своих собственных нужд, поэтому используют такую вещь, как активное окно. Все действия, необходимые для превращения окна в активное и снятие такого состояния задаются сообщением sw_active()
.
Настырный читатель рассмотрев все задачи, которые выполняет окно, может быть захочет выделить отдельно какие-нибудь такие абстракции, как
Мы же не будем так делать, так как в наших задачах не потребуются ни шаблоны, работающие с подобными абстракциями, ни повторное использование подобных описаний для конструирования новых объектов, поэтому прямо опишем все эти сообщения и свойства в классе окна.
Наличие в объекте окна свойств по управлению отображением и отсутствие автоматического вызова регенерации говорит о том, что часть горячих клавиш потребует перерисовки окна изнутри окна. Для этого надо знать позицию окна в десктопе. Эта позиция сохраняется от последнего вызова refresh()
или clear()
в last_x
и last_y
, поэтому после первой установки позиции окна, его легко перерисовать изнутри самого окна.
Позиция окна в десктопе, в отличие от многих остальных координат, знаковая, что позволит задвигать его начало за левую и верхнюю границу экрана.
С окном связан объект десктоп. Если при создании первого окна десктоп еще не создан, то он будет создан автоматически и удален, при удалении последнего экземпляра окна.
Окно - очень сложный объект и в нашем случае не предназначен для копирования или передачи его по значению. Но зато это тот объект, который обязательно будет наследоваться с переопределением методов и их конвейерным вызовом.
Элемент списка children
дочерних окон описывается классом Twin_list_item
. Этот объект содержит координаты дочернего окна со знаком x,y
, относительно позиции (0,0) родительского и ссылку win
на само дочернее окно. Признак win_need_free
позволит удалить дочернее окно в деструкторе родителя.
Любой потомок Twin
, который хочет, чтобы его главное окно отображалось, должен определить метод для set_size()
, так так Twin::set_size()
только вызывает этот метод для окон из списка дочерних children
. Аналогично, метод активизации окна Twin::sw_active()
только вызывает этот метод для окон из того-же списка.
Создание конструктором по умолчанию, удаление деструктором. Подробности в листинге.
Ввод и вывод на основе conio.h
Окно с заголовком Tcwin (winitems.h)
Это окно добавляет к Twin
строку заголовка. Чтобы эта строка не мешалась с пользовательским реальным окном, заголовок оформляется как отдельное окно-наследник Twin
, класс Tcwin_caption
.
Окно с заголовком Tcwin (winitems.h)
Заголовок и пользовательское окно добавляются в список дочерних окон Tcwin
. Все декорации пользовательского окна размещаются в списке дочерних окон этого пользовательского окна. Это окно, как и заголовок, должно быть потомком простого окна Twin
. Само окно Tcwin
не имеет отображения, отображается только заголовок и рабочее пользовательское окно.
Окно с заголовком Tcwin (winitems.h)
При создании, конструктор по умолчанию создает окно заголовка как первое в списке дочерних окон. При удалении, деструктор Twin
удалит это окно из списка и вызовет для него delete
. Тоже самое произойдет и с пользовательским окном, если оно было установлено, и для него не сбрасывали специально флаг win_need_free
в элементе списка дочерних окон.
Окно с заголовком Tcwin (winitems.h)
Это работа с заголовком и с пользовательским окном сообщениями [set_|get_]caption()
и [set_|get_]paper()
. Вот методы, которые реализованы для них в Tcwin
| ||
| ||
| ||
|
Параметр skip_set_size==1
позволяет не вызывать настройку размеров дочернего окна согласно размерам Tcwin
, если на этом этапе этот размер еще не определен. Ничего страшного не произойдет, если вызов все-же будет сделан, но это просто трата времени.
Может не устраивать не симметричность методов для заголовка, но это вызвано тем, что определять строку заголовка не стоит через окно, это все же не виндовс. Получение же всего окна дает, в частности, возможность получить и заголовок. Но можно наследовать класс, в котором определить новое сообщение, для получения именно строки заголовка.
Ввод и вывод на основе conio.h
Диалоговое окно нам понадобится для того, чтобы выбирать строку из списка параметров или файлов и отображать помощь. Это окно, все изменения в котором можно подтвердить или отменить, нажав Enter или ESC.
Окно будет отображено по центру экрана. Чтобы убрать отображение окна диалога после выхода из диалога, надо обновить содержимое окон, которые оно перекрывало. Это окно наследуется из Тcwin
. Реальный текст, который будет отображаться, определяется в конструкторе потомка или сообщением set_paper()
для этого класса Tdialog
, если диалоговое окно просто выводит сообщение. По умолчанию, рабочее окно не существует, заголовок пуст. Особенности изменения взаимных размеров окна в зависимости от содержимого заголовка в листинге set_size()
.
Объект не имеет своих конструктора и деструктора, и создается так-же как окно с заголовком Тcwin
.
Это такие операции
| ||
|
Параметр clear_keys==DLG_CLEAR_KEYS
позволит не передавать сообщения от клавиатуры для других окон, как модальный диалог. Тип отмены или подтверждения диалога DLG_CANCEL или DLG_OK. Метод для сообщения execute()
в этом классе возвращает нажат выбор или отмена, в вашем же классе, который будет его наследником, он может возвращать что угодно, например, номер выбранной строки списка.
Ввод и вывод на основе conio.h