
- •Часть 1. Введение в turbo vision...............................14
- •Глава 1. Наследование велосипеда...............................14
- •Глава 2. Разработка прикладных программ с использованием
- •Часть 2. Глава 3. Иерархия классов..........................88
- •Глава 4. Отображаемые элементы................................108
- •Глава 5. Программирование, управляемое событиями..............143
- •Глава 6. Разработка надежных программ.........................170
- •Глава 7. Коллекции............................................177
- •Глава 8. Объекты, хранимые с потоками.........................199
- •Глава 9. Ресурсы..............................................211
- •Часть 1. Введение в turbo vision
- •Глава 1. Наследование велосипеда
- •Глава 2. Разработка прикладных программ
- •Часть 2. Глава 3. Иерархия классов
- •Глава 4. Отображаемые элементы
- •Глава 5. Программирование, управляемое событиями
- •Глава 6. Разработка надежных программ
- •Глава 7. Коллекции
- •Глава 8. Объекты, хранимые с потоками
- •Глава 9. Ресурсы
- •Глава 10. Дополнительная информация....................................5
- •Часть 3. Справочник по turbo vision...................................13
- •Глава 11. Как использовать справочник.................................13
- •Глава 12. Заголовочные файлы turbo vision.............................16
- •Глава 13. Справочник по классам.......................................35
- •Глава 10. Дополнительная информация
- •Часть 3. Справочник по turbo vision
- •Глава 11. Как использовать справочник
- •Глава 12 описывает различные заголовочные файлы Turbo
- •Глава 16 описывает в алфавитном порядке все глобальные конс-
- •Глава 12. Заголовочные файлы turbo vision
- •Глава 13. Справочник по классам
- •Глава 14. Классы редактора......................................6
- •Глава 15. Стандартные диалоговые окна..........................41
- •Глава 16. Глобальный справочник................................70
- •Глава 14. Классы редактора
- •Глава 15. Стандартные диалоговые окна
- •Глава 16. Глобальный справочник
Глава 9. Ресурсы
-----------------------------------------------------------------
Ресурсы можно определить как все, что можно поместить в файл
ресурсов. Для внесения ясности файлом ресурсов называется место
для хранения последних! В компьютерной терминологии под словом
"ресурсы" понимается более широкий набор элементов. Вообще гово-
ря, в книгах на эту тему такие объекты как меню, сообщения, пане-
ли диалога и многое другое называются ресурсами.
В Turbo Vision файл ресурсов - это объект, который может
сохранять обработанные им экземпляры классов, а затем восстанав-
ливать их по имени. Прикладные программы могут выбирать, каким
образом они могут создать объект: посредством вызова конструктора
или восстановлением из файла ресурсов. Вместо того, чтобы прог-
рамма создавала и инициализировала объекты, она может просто
восстановить объект, созданный, возможно, другой программой. Ре-
сурсы могут быть как частью выполняемого .EXE файла, так и самос-
тоятельным файлом.
В Turbo Vision имеются классы TResourceCollection и
TResourceFile. Они дают возможность сохранения и восстановления
элементов (обычно это объекты других классов) из потоков в более
гибкой форме, чем та, которая описана в главе 8. Это достигается
за счет индексирования по именам объектов TResourceFile. Ключ ин-
дексирования представляет собой обыкновенную символьную строку -
имя объекта, которое используется для чтения этого объекта из
файла. Пользователь не заботится о том, где сохранен объект или
каковы его размеры. Таким образом, Turbo Vision обеспечивает
очень удобную быструю форму доступа к сохраненным объектам.
Дополнительным преимуществом является возможность подсоеди-
нения файла ресурсов к файлу .EXE. Это означает, что прикладная
программа может загружаться в "готовом виде", то есть с уже соз-
данными объектами, что значительно упрощает ее использования. Ес-
ли ресурсы являются частью файла .EXE или представлены внешним
файлом, то это повышает возможности в достижении большей гибкости
и многосторонности прикладной программы. Многие элементы прог-
раммного обеспечения, такие как подсказки, различного вида по-
мощь, могут быть отделены от программы и помещены в файл ресур-
сов. Редактор ресурсов еще больше увеличит эти возможности.
Элементы ресурсов сохраняются в fpstream, который владеет
всеми объектами TResourceFile, однако для повышения эффективности
ключевые строки хранятся в виде отсортированной коллекции в
TResourceCollection. Позднее объясняются принципы хранения ресур-
сов в потоке расположения объектов и полей данных.
Класс TResourceCollection получен из класса TString-
Collection, который, в свою очередь, получен из TSorted-
Collection. TResourceCollection добавляет к элементам, унаследо-
ванным от TStringCollection, новые элементы, обеспечивающие ин-
дексацию ресурсов. Для большинства прикладных программ нельзя
Turbo Vision для С++ = 212 =
прямо использовать объекты TResourceCollection, ассоциированные с
файлом ресурсов. Конструктор TResourceFile создает набор
ресурсов, а функции этого класса взаимодействуют и поддерживают
эти наборы.
Используя один из конструкторов fpstream с необходимыми па-
раметрами, такими как имя файла, режим доступа (ios::in,
ios::out, и т.д.) и режим защиты, можно создать необходимый по-
ток.
Этот механизм крайне прост: файл ресурсов можно рассмотреть
как поток с произвольным доступом, который работает с объектами
доступными по ключевому полю (индексу). Заметьте, что класс
TNSortedCollection имеет поле данных duplicates (дублирование),
унаследованное от класса TSortedCollection. Оно принимает значе-
ние False по умолчанию. Это означает, что дублирование ключей
запрещено. Для обыкновенных ресурсов это дает возможность избе-
жать повторения ключей, поэтому имеет смысл хранить значение это-
го поля. Следуя этим принципам, при попытке сохранения ресурса с
уже имеющимся именем, он будет записан вместо уже существующего
объекта. Однако, иногда может понадобиться изменить этот меха-
низм. Такая возможность, делая ресурсы еще более гибкими, предус-
мотрена.
Почему надо использовать ресурсы?
-----------------------------------------------------------------
Использование ресурсов дает большое количество преимуществ.
1. Использование ресурсов позволяет выполнять настройку
прикладных программ без изменения их кода. Например:
текст панелей диалога, строки в окнах меню, цвета отобра-
жаемых элементов и многое другое можно внести в ресурсы и
изменить при помощи редактора ресурсов, что позволяет
без изменения кода программы изменять ее содержание.
2. Обычно использование ресурсов приводит к уменьшению раз-
меров программы. Разделение действий между основной прог-
раммой и программой для создания комплексных объектов,
используемых первой, является хорошей практикой програм-
мирования.
3. Использование ресурсов облегчает создание программ, ори-
ентированных на язык определенной страны. Прикладная
программа загружает объекты по имени, а что в них нахо-
дится известно только самим объектам.
4. Если необходимо иметь несколько версий одной и той же
программы с различными возможностями, то можно, например,
разработать два множества меню; одно будет обеспечивать
доступ ко всем возможностям программы, а второе - только
к определенным функциям. При этом нет надобности перепи-
Turbo Vision для С++ = 213 =
сывать текст программы, достаточно изменить или создать
новый ресурс.
Иначе говоря, ресурсы изолируют представление объектов от
программы, облегчая ее изменения.
Как устроены ресурсы?
-----------------------------------------------------------------
Для понимания внутреннего строения ресурсов необходимо знать
как устроены потоки и коллекции, так как ресурсы используют их
механизмы. Применять ресурсы можно и без знания принципов их ра-
боты, однако при создании сложных систем будут полезны детали,
рассмотренные ниже.
Объекты класса TResourceFile владеют как объектами сортируе-
мых наборов строк (класс TResourceCollection), так и объектами
потока ввода/вывода (класс fpstream). Объекты TResourceFile вла-
деют двумя полями данных:
TResourceCollection *index;
// указатель на набор, которым владеет объект
fpstream *stream;
// указатель на поток, которым владеет объект
Строка в наборе является ключом объекта в потоке. Заметьте,
что наборы могут динамически расширяться в соответствии с их по-
лями данных limit и delta.
Каждый элемент TResourceCollection является экземпляром
структуры TResourceItem:
struct TResourceItem
{
long pos;
long size;
char *key;
};
Поле key является ключевым для объекта, находящегося в пото-
ке в позиции pos (информация заголовка игнорируется). Поле size
дает длину объекта, который был проиндексирован.
Наборы строк создаются конструктором TResourceFile, а под-
держиваются и являются доступными посредством функций этого же
класса get и put. Однако файл потока должен быть открыт (создан и
инициализирован) до создания файла ресурсов. Фактически это озна-
чает, что необходимо вызвать конструктор, у которого в качестве
аргумента будет уже существующий указатель на fpstream:
TResourceFile::TResourceFile(fstream *aStream);
Turbo Vision для С++ = 214 =
// создание файла ресурсов при помощи указателя aStream,
// передаваемого в качестве аргумента
Turbo Vision для С++ = 215 =
Создание ресурсов
-----------------------------------------------------------------
Процесс создания и использования ресурсов включает в себя
четыре шага. Сначала необходимо открыть поток, затем проинициали-
зировать файл ресурсов в потоке, затем сохранить нужное количест-
во объектов вместе с их ключами и, наконец, закрыть поток по
окончанию работы.
Примечание: В демонстрационном примере GENFORM показываются
ресурсы Turbo Vision в действии, а также их
практические возможности.
Ниже приводится отрывок в котором описано создание простого
файла ресурсов с именем MY.REZ, используемого для сохранения од-
ного ресурса - строки состояния с ключом "Waldo". Функция
TResourceFile::put имеет два аргумента: указатель TStreamable*,
указывающий на элемент, который будет сохранен и ключ const char*
key. Имейте в виду, что директива #define должна предшествовать
директиве #include<tv.h> для обеспечения правильного включения
файлов заголовков и регистрации классов, взаимодействующих с по-
токами.
/* в реальных прикладных программа директива #define и #include
обычно помещаются в различные файлы */
#define Uses_TRect
#define Uses_TStatusLine
#define Uses_TStatusDef
#define Uses_TStatusItem
/* последние две директивы #define, хотя и избыточны, но безвред-
ны - смотрите комментарий после определения Uses_TResource-
Collection */
#define Uses_TResourceFile
#define Uses_TResourceCollection
/* определение #define Uses_TResourceCollection делать не обяза-
тельно, но ошибки не произойдет: TV.H уже знает, что RESOURCE.H
будет включен, так как сделано определение Uses_TResourceFile
*/
#define Uses_fpstream
...
// дополнительные определения для каждого используемого класса
...
// регистрация классов, использующих потоки:
__link(RStatusLine);
__link(RResourceCollection);
/* запомните, что TResourceFile не использует потоки!
Потоки используют только коллекции ресурсов */
Turbo Vision для С++ = 216 =
...
#include<tv.h>
// необходимые дополнительные стандартные файлы заголовков
...
const char rezFileName[] = "MY.REZ";
cout << "Создание " << rezFileName << end;
fpstream *ifps;
ifps = new fpstream(rezFileName, ios:out|ios::binary);
if (!ifps->good())
{
cerr << rezFileName << ": init failed..." << end;
exit(1);
}
// проверка потока на пригодность перед вызовом
// конструктора TResource;
// открытие fpstream для вывода в двоичном режиме;
// значение третьего аргумента по умолчанию принимается
// как filebuf::openprot;
// ошибка будет обработана с выдачей сообщения;
// более подробно это приводится в
// демонстрационном файле LISTDLG.CPP
TResourceFile *myRez;
myRez = new TResourceFile(ifps);
if(!myRez)
{
cerr << "Resource file init failed...";
exit(1);
}
// теперь myRez.stream связан с ifps и готов к работе
// создание строки состояния
// для будущих прикладных программ
TRect r(0, 24, 80, 25);
TStatusLine *sl;
sl = new TStatusLine (r
*new TStatusDef(0, 0xFFFF)+
*new TStatusItem("-Alt-X- Exit", kbAltX, cmQuit)+
new TStatusItem(-Alt-F3- Close", kbAltF3, cmClose));
if (!sl)
{cerr << "Statusline init failed...";
exit(1);
}
myRez->put(sl,"Waldo");
/* Сохранение строки состояния в ресурсе с ключом "Waldo".
Более полная программа должна вначале проверить ключ на
уникальность. Если он уже существует, то пользователь
должен опасаться перезаписи объекта в ресурс.
Turbo Vision для С++ = 217 =
*/
destroy sl;
// предполагается, что больше ничего не нужно!
destroy myRez;
// окончание работы программы. Объект myRez теперь сохранен
// в файле MY.REZ
...
Turbo Vision для С++ = 218 =
Чтение ресурсов
-----------------------------------------------------------------
Восстановление ресурсов из файла также просто, как и их сох-
ранение. Сначала нужно вызвать функцию TResource::get с именем
восстанавливаемого объекта в качестве аргумента. Она возвратит
указатель void* на искомый элемент. Это сделано для того, чтобы
можно было указывать на объект любого типа.
Ресурс строки состояния, созданный в предыдущем примере, мо-
жно восстановить и использовать как показано в приведенной ниже
программе. Основная идея заключается в замене обычного объекта
initStatusLine, который создан конструктором TProgInit, "готовым
к употреблению" объектом, сохраненным в файле ресурсов MY.REZ.
Примечание: В примере пропущены директивы #define и
#include, чтобы не переполнять программу избы-
точной информацией.
const char rezFileName[] = "MY.REZ";
class TMyApp: public TApplication
{
public:
TMyApp();
static TStatusLine *initStatusLine(TRect);
...
};
// для этого примера пропущены определения для строки меню
// и рабочей области
TMyApp::TMyApp():TProgInit(&TMyApp::initStatusLine)
{
}
TStatusLine *TMyApp()::initStatusLine(TRect)
{
fpstream *ofps;
ofps = new fpstream(rezFileName, ios::in|os::binary);
if (!ofps->good())
massageBox("Ошибка открытия потока", mfError|mfOKButton);
// контроль ofps на пригодность к использованию перед вызовом
// конструктора TResource (ofps должен быть не ноль)
// открытие потока в режиме двоичного ввода; значение третьего
// аргумента, принимаемое по умолчанию, filebuf::openprot
TResourceFile *myRez;
myRez = new TResourceFile(ofps);
if (!myRez)
messageBox("Ошибка файла ресурсов", mfError|mfOKButton);
else
Turbo Vision для С++ = 219 =
return (TStatusLine *) myRez->get (Waldo);
}
...
int main()
{
TMyApp waldoApp;
waldoApp.run;
return 0;
}
При считывании объекта из ресурса необходимо учитывать воз-
можность получения нулевого указателя. Если имя индекса неверно
(т.е. ресурс с таким ключом в файле отсутствует), то функция get
возвратит 0. Однако, после отладки программы эта проблема скорее
всего отпадет.
Объект можно восстанавливать из файла ресурсов неоднократно.
Маловероятно, что вы захотите проделать это со строкой состояния
из нашего примера, хотя пользователю может неоднократно понадо-
биться, например, панель диалога. В этом случае ресурс будет мно-
гократно выдавать объект по запросу пользователя.
Turbo Vision для С++ = 220 =
Списки строк
-----------------------------------------------------------------
Кроме стандартного механизма ресурсов, Turbo Vision поддер-
живает два специализированных объекта, которые обрабатывают
списки строк. Рисунок 9.1 показывает их место в иерархии классов
Turbo Vision (как принято в С++ стрелки указывают прямо на базо-
вый класс).
┌───────────────┐ ┌───────────────┐
│ TObject │ │ TStreamable │
└───────────────┘ └───────────────┘
┌─────────────┐ ^ ^
│ TStrindex │ │ ┌────────────────┤
└─────────────┘ ├─────┼────────────┐ │
┌─────┴─────┴───┐ ┌─────┴───┴─────┐
│ TStrListMaker │ │ TStringList │
└───────────────┘ └───────────────┘
Рисунок 9.1. Иерархия списков строк
Примечание: Хотя списки строк менее гибки, чем остальные ресурсы,
но если их хорошо разработать, то можно быстро и
удобно использовать.
Список строк является простейшим ресурсом, который позволяет
выполнять доступ к объектам не по ключевой строке, а по номеру,
который имеет тип unsigned short. Это облегчает задачи настройки
и международного использования программ. Необходимо четко разли-
чать классы TStringList и TStringCollection. Список строк ассоци-
ируется с объектом ifpstream, тогда как набор строк является
просто упорядоченной последовательностью без какой-либо связи с
потоком.
Интегрированная среда фирмы Borland использует для всех со-
общений об ошибках списки строк. Это означает, что программа вы-
зывает сообщение об ошибке просто по его номеру и различные вер-
сии сообщений, написанные для различных стран, будут выданы
независимо от языка на котором они реализованы. Различия между
списками строк и обыкновенными ресурсами видны при сравнении
классов TStrIndexRec и TResourceItem. Последний из них использует
индекс для поиска ресурсов.
struct TResourceItem
{
long pos;
long size;
char *key;
};
class TStrIndexRec
{
public;
Turbo Vision для С++ = 221 =
ushort key;
ushort count;
ushort offset;
};
Примечание: Сведения о конструктора-строителях (build) находятся
в главе 8 и в разделе TStreamable главы 13.
Класс TStringList имеет только конструктор-строитель, кото-
рому в качестве аргумента передается streamableInit. Это является
следствием того, что списки строк существуют только в файлах
ресурсов: они доступны только через файлы ресурсов и не могут
быть созданы где-либо вне их. Списки строк могут быть только про-
читаны, поэтому для них реализована функция get, а функция put не
реализована.
Создание списков строк
-----------------------------------------------------------------
Примечание: Класс TStringList взаимодействует с потоками, обеспе-
чивая доступ к строкам. Класс TSringMaker создает
списки строк.
Класс TStrListMaker создает списки строк в файлах ресурсов
для последующего их использования объектами класса TStringList.
Объекты класса TStrListMaker могут только записывать данные в
файл, в отличие от объектов класса TStringList, которые могут
лишь считывать эти данные. Поэтому для TStrListMaker реализована
функция put, а функция get отсутствует. Все, что может сделать
объект этого класса - это инициализировать список строк, записать
в него строки и сохранить их в потоке. Следующий пример иллюстри-
рует эти действия.
#define Uses_TStringList
#define Uses_TStringListMaker
...
#include <tv.h>
__Link(RStringList);
...
TStrListMaker myStrListMaker(strSize, indexSize);
// создается массив строк размером в strSize каждая
// создается массив объектов типа TStrIndexRec размером
// в indexSize, каждый из которых поддерживает элементы данных
// key, count и offset (ключ, счетчик и смещение)
// поля индекса устанавливаются в точку массива
// объектов TStrIndexRec.
myStrListMaker.put( 1, "Pass, Do not GO!");
myStrListMaker.put( 2, "Collect $500!");
...
opfstream("STR.LST");
Turbo Vision для С++ = 222 =
ops << myStrListMaker;
...
TStringList *myStringList;
// установка indexSize, index и basePos в 0
char legend[maxLeg];
ipfstream ifs("STR.LST");
ifs >> myStringList;
myStringList->get(legend,1);
count << "Legend 1: " << legend << end;
// displays "Pass, Do not GO!"
Оглавление
Turbo Vision для С++ = 1 =