Как сделать список в делфи
Списки
Указатели и динамические переменные позволяют создавать сложные динамические структуры данных, такие как списки и деревья.
Список можно изобразить графически (рис. 8.6).
Рис. 8.6. Графическое изображение списка
Каждый элемент списка (узел) представляет собой запись, состоящую из двух частей. Первая часть — информационная. Вторая часть отвечает за связь со следующим и, возможно, с предыдущим элементом списка. Список, в котором обеспечивается связь только со следующим элементом, называется односвязным.
Для того чтобы программа могла использовать список, надо определить тип компонентов списка и переменную-указатель на первый элемент списка. Ниже приведен пример объявления компонента списка студентов:
TPStudent = ^TStudent; // указатель на переменную типа TStudent
// описание типа элемента списка
surname: string[20]; // фамилия
group: integer; // номер группы
address: string[60]; // домашний адрес
next: TPStudent; // указатель на следующий элемент списка
head: TPStudent; // указатель на первый элемент списка
Добавлять данные можно в начало, в конец или в нужное место списка. Во всех этих случаях необходимо корректировать указатели. На рис. 8.7 изображен процесс добавления элементов в начало списка.
После добавления второго элемента в список head указывает на этот элемент
Рис. 8.7. Добавление элементов в список
Следующая программа (ее текст приведен в листинге 8.4) формирует список студентов, добавляя фамилии в начало списка. Данные вводятся в поля редактирования диалогового окна программы (рис. 8.8) и добавляются в список нажатием кнопки Добавить (suttoni).
Рис. 8.8. Окно программы Динамический список 1
Листинг 8.4. Добавление элемента в начало динамического списка
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;
Edit1: TEdit; // фамилия
Button1: TButton; // кнопка Добавить
Button2: TButton; // кнопка Показать
procedure ButtonlClick(Sender: TObject);
procedure Button2Click(Sender: TObject);
TPStudent=^TStudent; // указатель на тип TStudent
next: TPStudent; // следующий элемент списка
head: TPStudent; // начало (голова) списка
// добавить элемент в начало списка
procedure TForml.Button1Click(Sender: TObject);
curr: TPStudent; // новый элемент списка
new(curr); // выделить память для элемента списка
// добавление в начало списка
curr^.next := head; head := curr;
// очистить поля ввода
procedure TForml.Button2Click(Sender: TObject);
curr: TPStudent; // текущий элемент списка
n:integer; // длина (кол-во элементов) списка
st:string; // строковое представление списка
curr := head; // указатель на первый элемент списка
while curr <> NIL do begin
st := st + curr^.f_name + ‘ ‘ + curr^.1_name
// указатель на следующий элемент end;
then ShowMessage(‘Список:’ + #13 + st)
else ShowMessage(‘В списке нет элементов.’);
Добавление элемента в список выполняет процедура TForm1.Button1Click, которая создает динамическую переменную-запись, присваивает ее полям значения, соответствующие содержимому полей ввода диалогового окна, и корректирует значение указателя head.
Вывод списка выполняет процедура TForm1.Button2Click, которая запускается нажатием кнопки Показать. Для доступа к элементам списка используется указатель curr. Сначала он содержит адрес первого элемента списка. После того как первый элемент списка будет обработан, указателю curr присваивается значение поля next той записи, на которую указывает curr. В результате этого переменная curr содержит адрес второго элемента списка. Таким образом, указатель перемещается по списку. Процесс повторяется до тех пор, пока значение поля next текущего элемента списка (элемента, адрес которого содержит переменная curr) не окажется равно NIL.
Delphi site: daily Delphi-news, documentation, articles, review, interview, computer humor.
Класс TList позволяет создать набор из произвольного количества элементов и организовать индексный способ доступа к ним, как это делается при работе с массивом. Списки отличаются от массивов двумя важными особенностями. Во-первых, их размер может динамически меняться в ходе работы программы, фактически ограничиваясь лишь доступной памятью. Во-вторых, в списках могут храниться элементы разных типов.
Далее перечислены наиболее важные свойства класса TList.
property Capacity: Integer;
Содержит количество элементов массива указателей списка. Всегда больше Count. Если при добавлении очередного элемента значение Count стало равно Capacity, происходит автоматическое расширение списка на 16 элементов.
property Count: Integer;
Количество элементов списка. Это свойство изменяется при добавлении или удалении элемента.
property Items(Index: Integer): Pointer;
Возвращает указатель на элемент списка по его индексу. Самый первый элемент списка имеет индекс 0.
property List: pPointerList;
Возвращает указатель на массив элементов списка.
Тип pPointerList определен следующим образом:
TPointerList « array [0..MaxListSize] of Pointer;
Константа MaxListSize для Delphi 1 ограничена значением 16 379 элементов. Для 32-разрядных версий Delphi она ограничивается доступной памятью.
Далее перечислены некоторые методы класса TList. function Add(Item: Pointer): Integer;
Добавляет элемент Item в конец списка и возвращает его индекс, procedure Clear;
Очищает список, удаляя из него все элементы. Не освобождает память, связанную с каждым удаленным элементом. Устанавливает в свойства Count и Capacity значение 0.
procedure Delete(Index: Integer);
Удаляет из списка элемент с индексом Index. Все элементы, расположенные за удаляемым, смещаются на одну позицию вверх.
procedure Exchange(Indexl, Index2: Integer);
Меняет местами элементы с индексами Indexl и Index2. function Expand: TList;
Расширяет массив элементов, увеличивая значение Capacity.
function First: Pointer;
Возвращает указатель на самый первый элемент списка, function IndexOf(Item: Pointer): Integer;
Отыскивает в списке элемент Item и возвращает его индекс.
procedure Insert(Index: Integer; Item: Pointer);
Вставляет элемент Item в позицию Index списка: новый элемент получает индекс Index, все элементы с индексами Index и больше увеличивают свой индекс на 1. При необходимости расширяет список.
function Last: Pointer;
Возвращает указатель на последний элемент списка.
procedure Move(Curlndex, Newlndex: Integer);
Упаковывает список: удаляет пустые элементы в конце массива индексов, function Remove(Item: Pointer): Integer;
Отыскивает в списке элемент Item и удаляет его.
procedure Sort(Compare: TListSortCompare);
Сортирует коллекцию с помощью функции Compare.
Методы Add и insert получают указатель на вставляемый элемент. Чтобы воспользоваться ими, программист должен сам разместить в куче данные и получить соответствующий указатель. Точно так же методы Delete, Remove и Clear не уничтожают распределенные в памяти данные, которые программист должен, если это необходимо, уничтожить сам. Пример:
List: TList; Item: Pointer; Value: AnyType; begin
List := TList.Create; // Создаем список
Item := New (Value); // Размещаем в куче данные
List.Remove(Item); // Удаляем элемент из списка
Dispose(Item); // Удаляем его из кучи
List.Free; // Удаляем ненужный список
Метод Sort сортирует список по критерию, устанавливаемому функцией Compary. Тип TListSortCompare определен следующим образом:
TListSortCompare = function(Iteml, Item2: Pointer): Integer;
Функция Compare получает указатели на два элемента списка. Результат сравнения:
• любое отрицательное число, если ItemlА Item2A.
Критерий сравнения данных устанавливается программистом и реализуется в функции Compare.
Function Compdteml, Item2: Pointer): Integer;
// С помощью этой функции реализуется сортировка чисел
if PDouble(Iteml)л PDouble(Item2)л then
procedure TfmExample.bbRunClick(Sender: TObject);
// Обработчик щелчков на кнопке bbRun выполняет основную работу
List := TList.Create; // Создаем список
for к := 1 to 20 do // Наполняем его begin
New(pD); // Резервируем память
pDA := Random; // Помещаем в нее случайное число
List.Add(pD); // Добавляем к списку end;
List.Sort(Comp); // Сортируем список по возрастанию
pD := List [к]; // Очередное число из списка
Программирование списков в среде Delphi
Цель: Ознакомить учащихся с основными свойствами и методами создания списков при составлении программ в среде Delphi
Сегодня на занятии мы познакомимся с созданием и программированием списков.
Как вы понимаете, что такое список?
Под списком будем понимать упорядоченную последовательность текстовых строк.
Вопрос учителя: Ребята, а где в повседневной жизни вы встречались с понятием “СПИСОК”?
Учащиеся: В журнале список учащихся, список дел на текущую неделю в еженедельнике.
Давайте познакомимся с различными видами списков, используемых при составлении программ в среде Delphi.
Откройте файл C:\МОИ ДОКУМЕНТЫ\ПРИМЕР1\пример1.exe.
Вашему вниманию представлена демонстрация трех, наиболее часто используемых видов списков.
Листинг программы представлен ниже.
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
procedure ListBox1Click(Sender: TObject);
procedure ComboBox1Change(Sender: TObject);
procedure ColorBox1Change(Sender: TObject);
procedure TForm1.ListBox1Click(Sender: TObject);
case ListBox1.itemindex of
procedure TForm1.ComboBox1Change(Sender: TObject);
case ComboBox1.itemindex of
procedure TForm1.ColorBox1Change(Sender: TObject);
Оформление программы представлено на рис. 1.
Учитель: В курсе БКП вы учились работать со многими готовыми программами. Вспомните, в каких программах вы встречались с рассмотренными видами списков.
Учащиеся: В Microsoft Word и Microsoft Excel – параметры шрифта.
Сегодня мы посмотрим, какие компоненты применяются для программирования списков, какими свойствами и методами они обладают.
На наших занятиях мы уже изучали компоненты, представляющие собой список текстовых строк. Это многострочный редактор Memo и группа зависимых переключателей RadioGroup.
Свойства указанных выше компонентов схожи со свойствами списков. Давайте вспомним их.
Для этого поиграем в игру “Домино”.
После выполнения данного задания поменяться карточками с ребятами, сидящими за компьютером справа, Проверить выполнение заданий, поставить оценку и написать фамилии проверявших на визитке (находится на лицевой стороне холста) и вложить в соответствующий конверт.
Правильные ответы зачитываются преподавателем
Время проверки 20 – 30 секунд
Вопросы и Ответы:
Вопрос | Предлагаемые варианты ответов | |
Правильные | Неправильные | |
Свойство, определяющее порядковый номер выбранного переключателя в радиогруппе | ItemIndex | ItemName |
Компонент, представляющий собой группу взаимозависимых переключателей | Radiogroup | Radiobutton |
Свойство радиогруппы, определяющее названия и количество переключателей | Items | Text |
Метод Memo для добавления строки текста в конец текста | Add | Load |
Метод Memo, позволяющий вставить строку текста перед заданной строкой | Insert | Insert |
Свойство Memo, определяющее количество строк текста и их содержание | Lines | MultiSelect |
Очистка Memo | Clear | Align |
Удаление строки текста из текста Memo | Delete | DeleteLines |
Метод, позволяющий загрузить данные из текстового файла в Memo | LoadFromFile | Visible |
Метод сохранения текста Memo в текстовый файл | SaveToFile | Save |
Вывод: мы повторили основные свойства и методы компонентов Memo и Radiogroup.
А теперь познакомимся со свойствами и методами простого списка ListBox.
Откройте файл C:\МОИ ДОКУМЕНТЫ\ПРИМЕР2\пример2.exe.
Внешний вид программы представлен на рис. 2.
Листинг программы представлен ниже:
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Не так уж и часто, но бывает надо в программе получить список файлов или поддиректорий в каталоге. Для тех, кто использует KOL и MCK открываются аж 3 способа решения этой проблемы. Правда нормальный, по моему мнению, все-таки только один 🙂 Рассмотрим все.
Пояснения на счет атрибутов для искомых файлов:
Это конечно интересный способ получать список файлов, но не функциональный 🙂 Не создавать ведь на окне каждый раз ListBox или СomboBox (он тоже имеет это же свойство), чтобы получить список файлов. Да и почему-то выводимый список файлов в виде » коротких имен » (т.е. как будто в DOS). Скорее всего Владимир Кладов добавил это свойство как интересную фичу и не более.
3-й способ. » Как положено «
Ну и самое интересное 🙂 В KOL есть объект предназначенный для создания списка фалов. Это PDirList. Вот его конструктор:
Список методов и свойств для работы с этим обьектом:
Сортировка списка файлов. Rules (условие сортировки) может быть следующим :
Возвращает количество пунктов в списке
Пример. Наверху в окне находится список дисков. Ниже находится список файлов и подкаталогов, находящихся в центральных каталогах этих дисков.
Размер кода 1,8 Кб. Размер программы 34,5 Кб (без сжатия и замены модулей). На экране увидите Вы примерно следующее:
Коллекции и работа с ними
1.1. Почему коллекции?
Главное отличие класса TCollection от класса TList состоит в том, что он, во-первых, предназначен, в основном, для создания не обычных, а как бы «визуальных» списков и, во-вторых, Delphi содержит готовые средства, поддерживающие работу с коллекциями в design-time.
Только ли для построения «визуальных» списков предназначены коллекции? Естественно, нет, с их помощью можно создавать любые списки. Но именно при построении «визуальных» списков преимущества коллекций проявляются особенно отчетливо. Вы легко убедитесь в этом, поработав, например, с компонентом THeaderControl и его свойством Sections.
1.2. Основные особенности коллекций и их элементов
Других свойств класс TCollectionItem не содержит, а его остальные методы, в общем, вполне стандартны (за исключением конструктора и деструктора, которые, конечно, выполняют свои обычные функции, но имеют несколько необычную реализацию, а также дополнительных методов для взаимодействия с IDE в design-time). События в этом классе не определены, но, если требуется, то никто не мешает нам определить любые события в потомках этого класса.
Теперь рассмотрим особенности класса TCollection.
1.3. Владелец коллекции и класс TOwnedCollection
В большинстве случаев коллекции используются, как свойства компонентов (собственно, это и есть их основное назначение). Пусть, например, мы разрабатываем компонент, который должен содержать список некоторых объектов. Тогда сначала мы определяем класс «элемент коллекции», затем класс самой коллекции и, наконец, вводим в наш компонент свойство, как объект этого класса. Это свойство и будет представлять искомый список объектов, причем мы сможем работать с ним в design-time, не предпринимая для этого никаких дополнительных усилий.
1.4. Резюме по теоретической части
2.1. Создание элемента коллекции
Итак, элемент нашей коллекции будет представлять визуальную точку. Такая точка имеет две координаты центра и цвет. Конечно, можно ввести еще множество других параметров (размер, форма, вид кисти и т.д.), но мы не будем усложнять и ограничимся перечисленными тремя.
В разделе interface сразу после слова type пишем следующее объявление класса, который и будет представлять элемент нашей коллекции.
Теперь ставим курсор куда-то в середину этого объявления и нажимаем Ctrl+Shift+C. Умница Delphi добавляет еще три метода «Set» и создает скелет реализации. Остается только на языке Object Pascal объяснить, чего же мы, собственно, хотим. Итак, пишем реализацию.
Весь этот код, в общем-то, совершенно стандартный, но для тех, кто не имеет достаточного опыта в написании классов, приведу все же некоторые пояснения.
Конструктор. Здесь его замещение нужно только для того, чтобы присвоить полям объекта начальные значения. Те же значения указаны в объявлениях свойств, но это не значит, что они будут присвоены автоматически. Наоборот, описатель default в объявлении свойства просто информирует IDE о том, какое значение это свойство получает по умолчанию. Если текущее значение свойства и его значение по умолчанию совпадают, то IDE не будет сохранять текущее значение в файле формы, что уменьшает размер программы.
Методы «Set». Это так называемые методы доступа к свойствам (точнее, методы их записи), причем в данном случае все они практически одинаковы. После присваивания вызывается метод Changed, что информирует коллекцию об изменении элемента и, как мы увидим далее, приводит к перерисовке. Предварительная проверка равенства нового и текущего значений позволяет избежать ненужных действий, особенно, лишней перерисовки.
Если в программе написано, например, Color:=clRed, то вместо прямого присваивания компилятор сгенерит вызов метода записи SetColor(clRed) и, таким образом, перерисовка будет выполнена автоматически. Почти то же самое происходит и при установке свойства в design-time.
2.2. Создание самой коллекции
Создание элемента коллекции полностью закончено. Возвращаемся в раздел interface и сразу же после объявления класса TSpot пишем две следующие строки.
Вторая строка определяет так называемый тип обработчика события. Наше событие будет означать, что произошло какое-то изменение элемента коллекции (параметр Item). Собственно говоря, введение такого события совсем не обязательно и сделано лишь с целью иллюстрации.
Теперь мы можем объявить класс самой коллекции.
Практически весь приведенный код реализации коллекции можно рассматривать, как совершенно стандартный и использовать его аналог чуть ли не для всех коллекций. Как видим, замещение методов класса-предка нужно, в общем-то, лишь для поддержки работы с конкретными используемыми классами элемента коллекции и ее владельца.
Замещение метода Update позволяет обновить компонент-владелец при изменении любого элемента коллекции (а также при их добавлении к коллекции и удалении из нее). Использованный в данном примере способ обновления не является оптимальным (поскольку при изменении всего лишь одного элемента перерисовывается весь компонент) и выбран лишь из-за своей простоты.
Итак, коллекция создана. Но для того, чтобы использовать ее по назначению, нужно сначала «вживить» ее в компонент.
2.3. Внедрение коллекции в компонент
С самого начала Delphi создала нам скелет объявления класса TDappledShape и сейчас, наконец, настало время его оживить. Пишем следующее.
Весь этот код, в общем, очевиден и некоторых комментариев, пожалуй, требует только метод SetSpots. Тем более, что его код опять-таки стандартен для внедренного в компонент объектного свойства, в частности, для свойства-коллекции.
Вот и все! Теперь осталось только сохранить готовый модуль, вспомнить, что где-то в недрах экрана висит окно пакета HelloWorld, найти его и нажать кнопку Compile. После этого можем с удовольствием пользоваться собственным компонентом с собственной коллекцией.
А мне остается попрощаться и пожелать Вам, читатель, хорошего коллекционирования!