- •Литература
- •Содержание
- •1. Основные понятия ооп
- •2. Программирование для Windows
- •3. Визуальное программирование и среда Delphi
- •Создание приложений в средеDelphi
- •Компоненты общего назначения tMainMenu- главное меню формы (программы)
- •TPopupMenu- вспомогательное (локальное) меню
- •TLabel- метка для отображения текста
- •TEdit-ввод и отображение строки
- •TMemo- ввод и отображение текста
- •TButton- кнопка
- •TBitBtn- кнопка с изображением
- •TSpeedButton- кнопка для инструментальных панелей
- •TCheckBox- независимый переключатель
- •TRadioButton- зависимые переключатели
- •TRadioGroup- группа зависимых переключателей
- •TListBox- список выбора
- •TComboBox- раскрывающийся список выбора
- •TPanel- панель
- •TTabControl- набор закладок
- •TPageControl- набор страниц с закладками
- •4. Особенности языка ооп Object Pascal
- •Процедуры и функции Выход из процедур и фукнций и возврат результата
- •Передача параметров
- •Параметры со значениями по умолчанию
- •Перегрузка функций
- •Динамическое распределение памяти
- •Указатели
- •Операции с указателями
- •Операция @
- •Самоадресуемые записи
- •Динамические массивы Одномерные динамические массивы
- •Многомерные динамические массивы
- •Исключения и их обработка
- •Защита кода зачистки в блокахtry...Finally
- •Защита кода зачистки на уровне модуля — разделfinalization
- •Обработка исключений в блокахtry...Except
- •Последовательность обработки исключений
- •5. Классы и объекты
- •Классы и объекты
- •Инкапсуляция
- •Наследование
- •Полиморфизм
- •Составляющие класса Поля
- •Одноименные методы
- •Свойства
- •События
- •Объявление класса
- •Операции с классами
- •Ссылки на классы
- •TObjectи информация о классах
- •Регистрация и обнаружение классов
- •6. Создание объектов во время выполнения, поиск компонентов
- •Клонирование объектов
- •Поиск компонента
- •Двукратное освобождение объекта
- •7. Построение собственных компонентов
- •Как и для чего следует строить компоненты
- •Общие руководящие принципы
- •Ключевые идеи
- •Компиляция компонентов
- •Отладка компонентов
- •Примечание
- •Примечание
- •Примечание
- •8. Работа с потоками
- •Классы потоковDelphi
- •Файловые потоки
- •Примечание
- •Методы потоков в действии: программаMemoStr
- •Потоки памяти
- •Пример программыMemoryS
- •Примечание
- •Написание заказного класса потока
- •9. Работа с com-объектами, использование серверов ole-автоматизации
Примечание
Почему Object Pascal не поддерживает арифметические операции над указателями, хотя C/C++ это умеет? Потому, что арифметические операции над указателями - это наиболее частый источник ошибок. Вместо этого Object Pascal использует информацию о типе данных указателя, что позволяет спокойно применять к указателям процедуры инкремента Inc и декремента Dec.
LongInt = 1;
PChar; Char;
Этот подход интересен, но пользователь должен нажать клавишу ОК много раз. По этой причине мы решили изменить код и показывать начальные символы текста в потоке памяти внутри окна списка в нижней части экрана. Для выполнения этого фактически используется трюк: в потоке памяти записывается пустой символ, чтобы указать конец отображаемой строки. После отображения данных в поле списка исходный символ восстанавливается.
Интересный аспект этого кода состоит в том, что он показывает, как изменить данные в потоке памяти, обращаясь к ним непосредственно по указателю (хотя следует обратить внимание на арифметические операции над указателями в этом методе):
procedure TForml.Button2Click(Sender: TObject);
const ndx:
var pch: tmpC:
begin
pch := MemStrl.Memory;
tmpC := pch[ndx];
pch[ndx] := #0;
ListBoxl.Items.SetText(MemStrl.Memory);
pch[ndx] := tmpC;
if ndx < MemStrl.Size then
Inc(ndx)
else
Button2.Enabled := False;
end;
На сей раз мы получаем доступ к месту внутри блока памяти, используя для ссылки на такой определенный байт памяти, как п-й символ строки, PChar и квадратные скобки.
Обратите внимание, как используется локальная константа для хранения значения в памяти между различными обращениями к этому методу без добавления локального поля в форму. Рис. 3.3 показывает результат загрузки файла в Memo и Последующего просмотра данных потока памяти, добавляя их в список, размещенный внизу.
Написание заказного класса потока
Помимо использования уже существующих классов потока, программисты Delphi могут писать свои собственные классы потоков и использовать их вместо существующих. Чтобы сделать это, необходимо только определить, как обобщенный блок данных будет сохранен и загружен, a VCL будет способна использовать новый класс везде, где это требуется. Вам можно не создавать полностью новый класс потока для работы с новым типом средств, но придется настроить существующий поток. В этом случае требуется только переписать соответствующие методы чтения и записи.
Например, мы решили создать класс для кодирования и декодирования потока генерируемого файла. Хотя этот пример ограничен использованием простого механизма кодирования, он полностью интегрируется с VCL и работает правильно. Новый класс потока просто объявляет два базовых метода чтения и записи и обладает свойством, сохраняющим ключ,
type
TEncodedStream = class(TFileStream)
private
FKey: Char;
public
constructor Create(const FileName: string; Mode: Word);
function Read(var Buffer; Count: Longint):Longint; override;
function Write(const Buffer; Count: Longint):Longint; override;
property Key: Char read FKey write FKey default 'A'; e
nd;
Значение ключа просто добавляется к каждому из байтов при сохранении в файле и вычитается при чтении данных. Вот полный код двух методов:
constructor TEncodedStream.Create(const FileName: string; Node: Word);
begin
inherited Create(FileName, Mode); FKey := 'A';
end;
function TEncodedStream.Write(const Buffer;Count: Longint): Longint;
var
pBuf, pEnc: PChar; I, EncVal: Integer;
begin
// выделение памяти для декодированного буфера
GetNem (pEnc, Count);
try
// использование буфера в качестве массива символов
pBuf := PChar(@Suffer);
// для каждого символа буфера
for I := 0 to Count - 1 do
begin
// кодирование значения и его сохранение
EncVal := ( Ord(pBuf[I]) + Ord(Key)) mod 256;
pEnc[I] := Chr(EncVal);
end;
// запись закодированного буфера в файл
Result := inherited Write(рЕnc^, Count);
finally
FreeMem(pEnc, Count);
end;
end;
function TEncodedStream. Read(var Buffer;Count: Longint): Longint;
var
pBuf, pEnc: PChar; I, CountRead, EncVal: Integer;
begin
// выделение памяти под декодированный буфер
GetNem(pEnc, Count);
try
// чтение декодированного буфера из файла
CountRead := inherited Read(pEnc^, Count);
// использование буфера вывода в качестве строки
pBuf: PChar(@Buffer);
// для каждого прочитанного символа
for I := 0 to CountRead - 1 do
begin
// декодирование значения и его сохранение
EncVal := ( Ord(pEnc[I]) - Ord(Key)) mod 256;
pBuf[I] := Chr(EncVal);
end;
finally
FreeMem(pEnc, Count);
end;
// возвращается количество прочитанных символов
Result := CountRead;
end;
Комментарии в программе должны помочь понять детали. Теперь, когда у нас есть простой кодированный поток, можно попробовать использовать его в демонстрационной программе, названной EncDemo. Форма этой программы имеет два компонента Memo и три кнопки: первая кнопка загружает простой текстовый файл в первый компонент Memo; вторая кнопка сохраняет текст первого Memo в закодированном файле; и последняя кнопка перезагружает закодированный файл во второй Memo, декодируя его.
Изображение на рис. 3.4 показывает форму, отображаемую этой программой при выполнении. На нем файл после кодирования снова загружен в первый Memo как простой текстовый файл, но, конечно, его прочитать нельзя.
Так как у нас есть класс закодированного потока, текст этой программы очень похож на текст любой другой программы, использующей потоки. Например, вот два метода, используемых для загрузки или сохранения закодированного файла (их можно сравнить с методами, основанными на потоках, показанными в этой главе ранее):
procedure TFormEncode.BtnSaveEncodedClick(Sender: TObject);
var
EncStr: TEncodedStream;
begin
if SaveDialogl.Execute then begin
EncStr := TEncodedStream.Create( SaveDialogl.FileName, fmCreate);
try
Memol.Lines.SaveToStream(EncStr);
finally
EncStr.Free;
end;
end;
end;
procedure TFormEncode.BtnLoadEncodedClick(Sender: TObject);
var
EncStr: TEncodedStream;
begin
if OpenDialogl.Execute then begin
EncStr := TEncodedStream.Create(OpenDialogl.FileName, fmOpenRead);
try
Memo2.Lines.LoadFromStream(EncStr);
finally
EncStr.Free;
end;
end;
end;