Как сделать проверку на пустую строку делфи

Обновлено: 07.07.2024

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

Примеры операции со строками Delphi

1) Функция length возвращает длину указанной строки. Данная функция обладает одним параметром, который представляет собой выражение, имеющее строковый тип данных. В качестве значения функции length выступает целое число, обозначающее количество символов, входящих в состав строки.

Примеры

b:=length(‘na beregu’);

В результате выполнения этих инструкций переменная a пример значение 6, а переменная b получит значение 9. 2)

2) Процедура delete. С помощью процедуры delete можно удалить определенную часть строки. Общий вид процедуры delete выглядит следующим образом:

  • строка обозначает переменную или константу с строковым типом данных;
  • n есть номер символа, начиная с которого удаляется заданная подстрока;
  • m представляет собой длину удаляемой впоследствии подстроки.

Пример

При выполнении инструкции

переменная st примет значение-строку ‘Город’. 3)

3) Функция роs. С помощью функции pos возможно определение положения подстроки в указанной строке. Общий вид инструкции функции pos представляется так:

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

Пример

При выполнении следующей инструкции:

Переменная n примет значение 2. В случае, если строка не содержит искомую подстроку, то функция pos возвращает значение 0. Приведем пример инструкции оператора while, которая позволит удалить начальные пробелы из указанной строки:

Здесь процедура delete(s, 1, 1) удаляет пробелы до тех пор, пока пробел есть начальный символ строки (то есть пока значение функции pos(‘ ‘,s) совпадает с единицей). Проверка условия length(s) > 0 применяется здесь для того, чтобы учесть возможность включения в строку только одних пробелов.

4) Функция copy выделяет фрагмент указанной строки. Общий вид инструкции функции copy представляется следующим образом:

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

Пример

При выполнении инструкции

town:=copy(s, 7, 12) ;

переменная town примет значение-строку ‘Екатеринбург‘.


Короткие строки

Сразу после объявления длина строки sPascal равна нулю, хотя в памяти компьютера она всегда будет занимать 11 байтов. Почему 11, а не 10, как указано в объявлении?

Дело в том, что, действительно, для хранения каждого символа в памяти компьютера требуется 1 байт, что для 10 символов и составляет 10 бай­тов. А ещё 1 байт нужен для хранения текущей длины строки. Он имеет нулевой индекс в массиве, а символы строки - от 1 до заданной макси­мальной длины строки. Так как под хранение длины строки отводится 1 байт, то и длина строки не может превышать 255 символов.

Чтобы яснее представить, как хранятся строки в памяти компьютера, об­ратимся к Рис., верхний.

Строки в Delphi, или Жестокие игры со словами

Итак, при запуске программы процессор компьютера выполняет машин­ный код, соответствующий строке исходного кода var sPascal: string[10]; При этом создаётся переменная sPascal, под неё отводится 11 байтов памяти, начиная, например, с адреса 1000 (конечно, адрес вы­мышленный, но точный адрес нам и не нужен) и по адресу 1000 заносится число 0 (на самом деле не число, а символ с кодом 0!), соответствующее текущей длине строки, то есть наша строка пустая: sPascal =

Присвоим строке какое-нибудь значение, к примеру, Pascal:

Содержимое памяти изменится (Рис. У10.1, средний). Теперь по адресу 1000 находится число 6 (длина строки), а далее - символы строки, которые имеют тип AnsiChar.

Если присваивать переменной sPascal другие значения, то, соответственно, будет изменяться и содержимое ячеек памяти. Как именно, вы теперь лег­ко можете догадаться. Нас могут заинтересовать только 2 предельных случая. Чтобы уничтожить строку (не саму переменную, а только её зна­чение!), достаточно её сделать пустой:

В этом случае строка вернётся в исходное состояние, показанное на рисун­ке Рис., верхний.

Если переменной присвоить строку, длина которой больше указанной в объявлении максимальной, например,

Таким образом, Delphi нещадно пресекает все ваши - даже неумышленные - попытки испортить программу. В самом деле, под переменную отводится 10 байтов памяти, а вы желаете втиснуть туда строку, длина которой на 2 символа больше. Значит, остальные символы должны занять следующие 2 байта памяти, в которых уже есть что-то жизненно необходимое для про­граммы, и тем безнадёжно испортить её. А сможете ли вы потом найти ошибку в исходном коде?

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

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

sPascal[1] ='P', sPascal[2] = 'a', и так далее до

Но вы никогда не узнаете, что же находится дальше - sPascal[11] :

Delphi сочтёт ваше любопытство необоснованным и выдаст ошибку при первой же попытке запустить программу.

Наверное, вы думаете, что значение sPascal[0] имеет тип byte и вы легко сможете узнать длину строки? - А вот и нет! Оно тоже имеет тип AnsiChar - как и символы строки (это значит, что для Delphi там находится не число, а символ, код которого равен длине строки).

и получите длину строки

Хотя можно было не стараться, а просто расширить кругозор, найти функцию Length и воспользоваться ею:

Результат будет тем же самым, но программа лишится части своей загадочности, которая так же гипнотически действует на не­окрепшие умы, как удав на кролика.

Если мы имеем право считать значение элемента sPascal[0], то мы можем и записать туда всякую ерунду.

(почему не просто 255?) - и длина строки увеличится до 255. Однако попробуйте что-нибудь записать в новую строку:

- всё равно ничего не получится.

Если вы присваивали строке значение Pascal123456, а потом Pascal, то в них останутся символы 1234, хотя длина строки теперь только 6 символов.

В других случаях эти ячейки могут занимать любые символы, поэтому ни­когда не используйте в своих программах значения символов за предела­ми присвоенного строке значения!

Если вы создаёте несколько строковых переменных равной длины, то удобнее объявить новые типы строк:

Затем вы можете использовать эти типы для объявления строковых переменных ограниченной длины:

AnsiString, или длинные строки, - основной тип строк в Delphi до послед­него времени. Они могут содержать до 231 символов и занимать в памяти компьютера до 2 гигабайтов.

Для объявления длинных строк также используется зарезервированное слово AnsiString, но максимальная длина строки в скобках не указывается, поскольку длина этих строк изменяется динамически:

При изменении строки Delphi автоматически уменьшает или увеличивает размер памяти под строку так, чтобы она целиком могла там разместить­ся. Это значит, что вам не нужно заранее заботиться и высчитывать мак­симальную длину строки, в то время как при объявлении коротких строк это делать необходимо. Более того, даже пустая короткая строка всегда занимает в памяти заказанное число байтов. Интересный вопрос: сколько памяти занимает пустая длинная строка? Интересный ответ: нисколько, пустые строки в памяти не хранятся. Так что при объявлении длинной строки система выделяет только 4 байта для хранения адреса памяти, начиная с которого будет размещаться сама строка, и для пустой строки там будет константа nil.

Строки с нулевым символом в конце используются во многих язы­ках программирования, например в C и C++, а также в Windows API, чем и вызвано появление таких строк в Delphi.

Таким образом, переменная типа AnsiString - это указатель на об­ласть памяти, в которой хранятся символы строки.

Как мы уже выяснили, при объявлении длинной строки место в памяти для неё не выделяется. Если же присвоить строке значение (не пустую строку!), например,

то в памяти выделяется столько байтов, чтобы поместились все символы заданной строки, плюс ещё 1 байт для нулевого символа в конце строки (не нуля, а нулевого символа типа AnsiChar!), плюс 4 байта для хранения длины строки (они занимают в памяти место перед первым символом строки), плюс ещё 4 байта для подсчёта ссылок на строку (нам это значе­ние не потребуется) + 4 байта для хранения кодовой страницы.

В картинках это выглядит так

Delphi

Очень похоже на короткую строку, к которой добавлен нулевой символ. Поэтому доступ к отдельным символам строки осуществляется точно так же, как и в случае коротких строк - по их индексу в массиве символов. За­помните, что индекс первого символа равен 1!

Таким образом, если

то после присвоения символьной переменной ch значения первого симво­ла строки sDelphi

её значение будет равно D, второго символа - е, шестого - i.

Если задать индекс, превышающий длину слова (в нашем случае 7 и боль­ше), то значение переменной ch будет равно нулевому символу.

Длинные строки Юникода

Длинные строки Юникода типа UnicodeString - основной тип строк в по­следних версиях языка Delphi. Они очень похожи на длинные ANSI-строки, но для каждого символа строки в них отводится 2 байта, поэтому они мо­гут содержать до 230 символов (вдвое меньше, чем строки ANSI) и занимать в памяти компьютера до 2 гигабайтов.

Для объявления длинных строк используются зарезервированные слова UnicodeString и string:

Таким образом, ключевое слово string - это всего лишь псевдоним более длинного слова UnicodeString. Оба эти слова обозначают один и тот же тип данных.

Длинные строки Юникода имеют ту структуру и те же свойства, что и ANSI-строки, поэтому мы не будем повторяться.

Объявление глобальных строковых переменных и типизированных констант можно совмещать с их инициализацией, то есть присваи­вать им начальное значение:

Обратите внимание: нулевой символ после строки указывать не нужно, он будет добавлен автоматически!

Другие типы строк

Строки типа PAnsiChar, PChar (PUnicodeChar) и PWideChar- также очень похожи на длинные строки Delphi (точнее, наоборот: длинные строки по­хожи на эти строки), они также заканчиваются нулевым символом, но в строках этих типов отсчёт индексов ведётся от нуля, а не от единицы (вечная головная боль от массивов в языке С).

Строки типа PChar используются не только в языках C и C++ (нам до этого и дела нет), но и в функциях Windows API, без которых обойтись не удастся.

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

Мешанина из строк разных типов

Таким образом, строки типа string сочетают в себе все достоинства корот­ких строк паскаля и строк PChar языка С, избегая при этом их недостатков. Им можно присваивать значения коротких строк и строк PChar:

Строки PChar вреднее строк Delphi: они не позволяют присвоить им всуе значения ни коротких, ни длинных строк. Для этого необходимо явно пре­образовать их к типу PChar:

Если же ваши строки имеют тип string, то следует привести их к типу PChar:

Впрочем, для таких случаев лучше сразу использовать тип PChar:

Простые операции со строками

Строки типа string можно объединять в одну строку с помощью оператора + (оператор сцепления строк; сама операция называется конкатенацией строк). В качестве операнда можно использовать не только длинную, но и короткую строку, а также символьные и строковые переменные и кон¬станты.

Значением строки s3 будет новая строка s3 = stringl + string2. Длина строки будет равна длине всех строковых операндов, входящих в выражение. В нашем случае - 22.

Эти и многие другие операции со строками можно выполнить с помощью процедур и функций, рассматриваемых на одном из следующих уроков.

Для сравнения строк используются операторы отношения ( = <> =). Результат сравнения имеет логический тип, то есть значение true или false.

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

Если очередные символы двух сравниваемых строк не совпали, то меньше та, код символа которой меньше:

Если строки имеют разную длину и все символы более короткой строки совпали с соответствующими символами более длинной строки, то мень­ше первая строка:

Если строки имеют одинаковую длину и все символы совпали, то строки равны:

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

Для начала покажу как определить строку и присвоить ей значение

Разберемся теперь с функциями обработки строк:

Функция Length()

Функция Length() – возвращает количество символов в строке. Выглядит она так:

Function Length(S): Integer;

Передаем один параметр – строку, в результате получаем число символов.

Функция Copy()

Функция Copy() – функция возвращаем заданный отрывок строки.

function Copy ( str1 : string, Index, Count : Integer ) : string;

  • str1 – строка, из которой мы хотим извлечь часть.
  • Index – порядковый номер начального символа.
  • Count – сколько символов мы хотим извлечь.

Приведу пример и все станет на свои места

Функция Pos()

Функция Pos() – возвращает позицию одной строки в другой. Так сказать, ищет подстроку в строке. Если что-то находит, то возвращает номер символа начиная с которого началось совпадение.

function Pos ( const str2, str1 : string ) : Integer;

  • str2 – строка, которую ищем.
  • str1 – строка, в которой ищем.

Процедура Delete()

Процедура Delete() – удаляет часть строки.

procedure Delete ( var Str1 : string; Index : Integer, Count : Integer );

  • str1 – строка из которой удаляем символы.
  • Index – позиция с которой начинаем удалять.
  • Count – сколько символов удаляем

Процедура Insert()

Процедура Insert() – вставляет одну строку в другую, начиная с указанного символа.

procedure Insert(str2: String; var Str1: String; Index: Integer);

  • str2-страка, которую вставляем.
  • str1-строка, в которую вставляем.
  • Index – позиция, с которой начнется вставка

Эти основные функции помогут сделать со строками в delphi любые манипуляции.

Я попытался использовать это кодирование для выполнения задачи:

Но я не уверен, что помещать в "индексное" пространство.

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

Итак, в вашем примере, например,

Это может быть медленным в больших файлах, поскольку IndexOfName пеет каждую строку в TStringList и проверяет каждую строку по очереди, пока не найдет совпадение.

Отказ от ответственности: Протестировано/работает с Delphi 2007, Delphi 7 может быть разным.

Я не понимаю, почему так много людей делают это так тяжело. Это довольно просто:

Как говорит Ариоч, если вы сохраняете одно имя файла, вы рискуете потерять свои данные, когда сбой не удастся, поэтому вы можете сделать что-то вроде

Это сохраняет резервную копию исходного файла как FileName + '.old' .

Разъяснения

Работа назад

Зачем работать назад? Потому что если у вас есть следующие пункты

И вы удаляете элемент в ^ , тогда следующие элементы будут перемещаться вниз:

Если вы перейдете вперед, вы теперь укажете на

и E никогда не проверяются. Если вы вернетесь назад, то вы укажете на:

Обратите внимание, что E , F и G уже были рассмотрены, поэтому теперь вы действительно изучите следующий элемент C , и вы не пропустите ни одного. Кроме того, если вы продвигаетесь вверх с помощью 0 to Count - 1 и удаляете, Count станет меньше, а в конце вы попытаетесь получить доступ к границе списка. Это не может произойти, если вы работаете в обратном направлении, используя Count - 1 downto 0 .

Программированию нельзя научить, можно только научится

Компонент TDBGrid

TDBGrid - таблица, в которой строки представляют собой записи, а столбцы — поля набора данных. Свойство DataSource содержит ссылку на выбранный набор данных.

Столбцы DBGrid

Столбцы – поля подключенного набора данных. Этими значениями можно манипулировать, показывая или скрывая поля НД, меняя их местами или добавляя новые столбцы. Требуемый набор полей можно составить при помощи специального Редактора столбцов (рис. 1), который открывается при двойном щелчке на компоненте, перенесенном на форму.
В верхней части окна вы видите четыре кнопки, слева - направо:

  1. Add New (Добавить новый столбец).
  2. Delete Selected (Удалить выделенный столбец).
  3. Add All Fields (Добавить все столбцы из набора данных).
  4. Restore Defaults (Восстановить значения по умолчанию для выделенного столбца).



Рис. 1. Редактор колонок компонента TDBGrid
Для выбранного в списке столбца доступные для редактирования свойства появляются в Инспекторе объектов. Столбцы в списке можно редактировать, удалять, менять местами.
Изменить параметры заголовка столбца можно в раскрывающемся свойстве Title, которое имеет ряд собственных свойств:
Alignment - свойство устанавливает выравнивание заголовка и может быть taCenter (по центру), taLeftJustify (по левому краю) и taRightJustify (по правому краю).
Caption - свойство содержит текст, который отображается в заголовке столбца.
Color - цвет заголовка.
Font - шрифт заголовка.
Свойства Font, Alignment и Color внутри свойства Title меняют шрифт, выравнивание и цвет фона только заголовка столбца, а не его содержимого. Но у столбца имеются эти же свойства, они меняют шрифт, выравнивание и цвет фона выводимых в столбце данных.
Свойство Visible разрешает или запрещает отображение столбца, а свойство Width позволяет изменить его ширину.

Пустые столбцы

Если добавить в редактор столбцов сетки DBGrid новый столбец, но в свойстве FieldName не выбирать поле БД, а оставить его пустым, мы получим пустой столбец. Для чего нужны пустые столбцы в сетке? В них можно выводить обработанные данные из других столбцов.

Задание 2. К примеру, пользователю неудобно просматривать три столбца "Фамилия", "Имя" и "Отчество" из таблицы Pers базы данных Сотрудники. Ему было бы удобней просмотреть один сборный столбец в формате "Фамилия И.О.". .
1. Это и все последующие задания выполнять в программе из задания 1..
2. Создайте новый столбец, но не назначайте ему поле из НД. Выделите этот столбец, и в его свойстве Title.Caption впишите "Фамилия И.О.", а в свойстве Width укажите ширину в 200 пикселей. .
3. Столбцы "Фамилия", "Имя" и "Отчество" нам уже не нужны, скройте их, установив их свойство Visible в False. А новый столбец перетащите мышью наверх, его индекс будет равен 0..
4. Для компонента DBGrid1 создайте обработчик события OnDrawColumnCell. Это событие наступает при прорисовке каждой ячейки столбца. В него внесите код:.

var s: String;
begin
if Column.Index = 0 then //если это пустой столбец
begin
if ADOTable1['Fam']<>Null then s:=ADOTable1['Fam'] + ' ';
if ADOTable1['Nam']<>Null then s:=s + Copy(ADOTable1['Nam'], 1, 1)+ '.';
if ADOTable1['Par'] <>Null then s:=s + Copy(ADOTable1['Par'], 1, 1) + '.';
DBGrid1.Canvas.TextOut(Rect.Left, Rect.Top, s);
end;
end;


Здесь мы вначале проверяем - наш ли это столбец (равен ли индекс нулю)? Если наш, то в переменную s начинаем собирать нужный текст. При этом имеем в виду, что пользователь мог и не заполнить некоторые поля. Чтобы у нас не произошло ошибки, вначале убеждаемся, что поле не равно Null (то есть, текст есть). Если текст есть, добавляем его в переменную s. Причем если это имя или отчество, с помощью функции Copy() получаем только первую букву и добавляем к ней точку. Когда s сформирована, добавляем этот текст в наш столбец с помощью метода TextOut() свойства Canvas сетки. В метод передаются три параметра: координаты левой позиции, верхней позиции и сам текст. Эти координаты мы берем из параметра события OnDrawColumnCell - Rect, который имеет такие свойства, как Left и Top, показывающие, соответственно, левую и верхнюю позиции текущей ячейки.
В результате программа будет иметь вид:

Рисунок 3. Заполнение пустого столбца

Список выбора в столбце - PickList

DBGrid позволяет устроить список, аналогичный ComboBox в одном из своих столбцов без использования каких-либо других компонентов.

Наличие такого списка не препятствует пользователю ввести какое-то иное значение. Этот список нужен не для контроля, а только для облегчения пользователю ввода данных. Если же вы не желаете, чтобы пользователь имел возможность вводить другие данные, контроль следует организовать иным способом.

В практике программирования список чаще формируется во время работы программы, а строки списка берутся, как правило, из другой связанной таблицы. Добавить в список новую строку очень просто: DBGrid1.Columns.Items[4].PickList.Add('абв');

Список свойства PickList автоматически заполняется для поля синхронного просмотра (lookup-поле).

Выделение отдельных строк

Очень часто в практике приходится выделять какие-то строки, изменяя их фон или цвет шрифта. Например, в бухгалтерии обычно выделяют строки, в которых значение меньше нуля. Допустим, ваша программа показывает клиентов, а какой-то столбец содержит их баланс на счету вашей компании. Если этот баланс меньше 0, значит, клиент имеет задолженность перед вашей фирмой. Бухгалтеру будет очень удобно, если дебиторы (должники) будут выделяться в общем списке красным цветом.

Способ прорисовки данных в DBGrid зависит от значения его свойства DefaultDrawing. По умолчанию свойство равно True, то есть данные прорисовываются автоматически. Если свойство содержит False, то прорисовку придется кодировать самостоятельно в свойстве OnDrawColumnCell.
Если мы написали алгоритм прорисовки, но свойство DefaultDrawing содержит True, то вначале сетка заполнится данными автоматически, а затем будет выполнен наш алгоритм. Другими словами, прорисовка некоторых частей сетки будет выполнена дважды. Это не очень хорошо для быстродействия программы, однако нам придется поступать именно так: ведь мы не все строки и столбцы собираемся выводить другим способом, а только некоторые. Остальные будут заполнены данными по умолчанию.

Разберем этот метод подробней. Если найти его в справке Delphi, то увидим:

property OnDrawColumnCell: TDrawColumnCellEvent;

То есть, этот метод имеет тип TDrawColumnCellEvent. Описание типа такое:

type TDrawColumnCellEvent = procedure (Sender:TObject; const Rect:TRect;
DataCol:Integer; Column:TColumn; State:TGridDrawState) of object;

Разберемся с параметрами.
Rect - координаты прорисовки.
DataCol - порядковый номер текущего столбца (начиная с 0).
Column - данные текущего столбца.
State - состояние ячейки. Может быть:

  • gdSelected - ячейка выделена
  • gdFocused - фокус ввода в ячейке
  • gdFixed - ячейка - заголовок столбца.


Задание 5. Изменение цвета шрифта записей сотрудников, относящихся к отделу Бухгалтерия, на красный.

Рисунок 6. Выделение строк
Заметим сразу, что наличие пустых столбцов создает дополнительные, но решаемые проблемы. Код события OnDrawColumnCell придется переделать, он будет таким:

var s: String;
begin Null then s:= ADOTable1['fam'] + ' ';
if ADOTable1['nam'] <> Null then s:= s + Copy(ADOTable1['nam'], 1, 1) + '.';
if ADOTable1['par'] <> Null then s:= s + Copy(ADOTable1['par'], 1, 1)+ '.';
DBGrid1.Canvas.TextOut(Rect.Left, Rect.Top, s);
end
else
if Column.Index = 5 then //если это пустой столбец с кнопкой ". "
begin
DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
Exit;
end
else TextOut(Rect.Left+2, Rect.Top+2, Column.Field.Text); //все остальные столбцы
end;
end;

TextOut(Rect.Left+2, Rect.Top+2, Column.Field.Text);


Обратите внимание, что мы добавили по два пикселя к крайней левой и крайней верхней координате ячейки. Если этого не сделать, то новая прорисовка не будет целиком закрашивать старую (рис.7):

Рисунок 7. Некорректная прорисовка
Количество добавляемых 2пикселей зависит от формата данных и размера шрифта. Обычно это определяется путем проб. Например, ячейка может содержать цифры, которые обычно прижимаются к правому краю, и тут двумя пикселями не обойтись.
Сделать проверку на тип данных можно, например, так:

//если текст, сдвинем только на 2 пикселя
if Column.Field.DataType = ftString then TextOut(Rect.Left, Rect.Top+2, Column.Field.Text)
//если цифры, сдвинем их вправо на 28 пикселей
else TextOut(Rect.Left+28, Rect.Top+2, Column.Field.Text);

Выделение строки красным текстом может оказаться недостаточным для заказчика. Что, если он потребует, чтобы эти строки выделялись красной строкой с белым шрифтом? Тогда вместо

Font.Color:= clRed;
FillRect(Rect);

вам придется написать

//выводим все ячейки строки белым текстом по красному фону:
Brush.Color:= clRed;
Font.Color:= clWhite;
FillRect(Rect);


Как видите, подсвойство DBGrid1.Canvas.Brush.Color отвечает за цвет заливки ячейки, а DBGrid1.Canvas.Font.Color за цвет выводимого в ней шрифта.

Компонент TDBCtrlGrid

Компонент TDBCtrlGrid (стр.DataControls) внешне напоминает компонент TDBGrid, но никак не связан с классом TCustomDBGrid, а наследуется напрямую от класса TWinControl.
Этот компонент позволяет отображать данные в строках в произвольной форме. Компонент представляет собой набор панелей, каждая из которых служит платформой для размещения данных отдельной записи набора данных. На панели могут размещаться любые компоненты отображения данных, предназначенные для работы с отдельным полем. С каждым таким компонентом можно связать нужное поле набора данных. При открытии набора данных в компоненте TDBCtrlGrid на каждой новой панели создается набор компонентов отображения данных, аналогичный тому, который был создан на одной панели во время разработки.
На панель можно переносить только те компоненты отображения данных, которые показывают значение одного поля для единственной записи набора данных. Нельзя использовать компоненты TDBGrid, TDBCtrlGrid, TDBRichEdit, TDBListBox, TDBRadioGroup, TDBLookupListBox.
Компонент может отображать панели в одну или несколько колонок. Для задания числа колонок панелей используется свойство ColCount. Число видимых строк панелей определяется свойством RowCount. Вертикальное или горизонтальное размещение колонок панелей зависит от значения свойства Orientation.
Размеры одной панели определяются свойствами panelHeight и Panelwidth. Они взаимосвязаны с размерами самого компонента. При изменении значений свойств PanelHeight и Panelwidth размеры компонента изменяются таким образом, чтобы в нем помещалось указанное в свойствах colcount и RowCount число панелей и наоборот.
Не рекомендуется размещать на панели компоненты TDBMemo и TDBimage, т. к. это может привести к значительному снижению производительности.

Читайте также: