
- •Первая программа
- •Целые числа
- •Вещественные числа
- •Процедуры
- •Функции
- •События
- •Строковые типы данных
- •Символьные типы данных
- •Логический тип данных
- •Пройденный материал на практике
- •Оператор цикла repeat...Until
- •Форма About средствами Delphi
- •Функции работы с символами
- •Файлы проекта
- •Строка и строки tStrings
- •ListBox – список выбора
- •Примеры исключений с Try ... Finally ...
- •Работа с базами данных в Delphi
Строка и строки tStrings
В практике программирования чаще всего приходится работать со строками. Будь то обычный Edit или Memo, там используются строки. И даже если вы вставляете Edit, чтобы запросить у пользователя число, он все равно вводит его в качестве строки, и вам требуется преобразовать его в числовой тип, чтобы работать с ним, как с числом.
Итак, что такое строка? Фактически, это массив символов. Давайте посмотрим пример:
var
s : String;
a : array [1..7] of Char;
begin
s := 'Привет!';
ShowMessage(s); //Результат: вывод строки "Привет!"
a[1] := 'П';
a[2] := 'р';
a[3] := 'и';
a[4] := 'в';
a[5] := 'е';
a[6] := 'т';
a[7] := '!';
ShowMessage(a); //Результат: вывод строки "Привет!"
ShowMessage(s[1]); //Результат: вывод буквы "П"
ShowMessage(a[1]); //Результат: вывод буквы "П"
К сожалению, мы не можем просто так взять и присвоить массиву строку – это будет ошибкой, поэтому a := s не скомпилируется. Однако после того, как в массив мы посимвольно ввели текст, это получается уже полноценной строкой, поэтому компилятор разрешит директиву ShowMessage(a);, и программа отработает без ошибок. Разумеется, неразумно использовать массив символов там, где проще использовать переменную типа String. Этот пример показывает, что строка – это тот же массив символьного типа!
Однако мы с вами уже сталкивались и с типом TStrings – строки. Такой тип мы использовали в свойстве Lines компонента Memo и вы уже убедились, насколько мощный это тип и как легко с ним работать. Он позволяет добавлять или удалять строку из списка строк, с его помощью легко записать строки в файл или наоборот, загрузить их из файла. Тип TStrings присутствует во многих компонентах, и везде вы с ним можете производить такие вот действия! Раз уж мы заговорили о массивах, то проведем сравнение и для TStrings – это тот же массив, только не типа Char (символ), а типа String (строка):
a : array [1..10] of String;
Однако, хотя TStrings по своему образу похож на такой массив, он имеет массу дополнительных возможностей, поэтому используйте его везде, где встает речь о работе с набором строк!
ListBox – список выбора
Списки выбора хранят в себе какие-то списки, и дают пользователю возможность выбирать одну из указанных строк. Часто их применяют в окнах с заданными параметрами, чтобы пользователь мог выбрать один из параметров.
Чтобы получить доступ к строкам списка, нужно воспользоваться свойством Items компонента ListBox. Это свойство имеет тип TStrings (строки), с таким типом мы сталкивались, когда обрабатывали компонент Memo.
Посмотрим на практике, как работать с данным компонентом. Создайте новое приложение, установите на него один компонент ListBox, и под ним – один Edit для вывода той строки, которую выбрал пользователь:
Рис. 12.1. Внешний вид формы
Затем дважды щелкните по свойству Items компонента ListBox. Перед вами откроется уже знакомый редактор строк. Наберите названия операционных систем:
MS-DOS
Windows 3.10
Windows 95
Windows 98
Windows ME
Windows 2000
Windows XP
Windows Vista
Unix
Linux
OS/2
Каждое название операционной системы должно быть на отдельной строке. Нажмите "ОК", чтобы сохранить результат. Теперь создайте для компонента ListBox обработчик события onClick. Мы уже знаем, что это событие срабатывает всякий раз, когда пользователь выберет одну из строк в указанном списке.
В обработчике событий напишите только одну строку:
Edit1.Text := ListBox1.Items.Strings[ListBox1.ItemIndex];
Эта строка присваивает свойству Text компонента Edit тот текст, который хранится в выбранной строке списка ListBox. Свойство Items имеет свое свойство Strings, которое представляет собой массив из строк списка. Указав индекс массива, мы можем получить доступ к нужной строке. В примере в качестве индекса указано свойство ListBox1.ItemIndex, которое имеет тип Integer и возвращает элемент выбранной строки в массиве строк. Кстати, когда вы поставите точку и откроется список, там вы этого свойства не обнаружите, так что придется писать его вручную.
Сохраните пример в новую папку, откомпилируйте и посмотрите, как он работает.
Кроме того, мы имеем возможность программно добавлять в ListBox новую строку или удалять выбранную. Киньте на форму еще две кнопки и напишите на них – "Добавить строку", "Удалить строку". Добавлять будем строку, написанную в компоненте Edit, а удалять – выделенную.
Для кнопки "Добавить" впишите:
ListBox1.Items.Add(Edit1.Text);
а для кнопки "Удалить":
ListBox1.Items.Delete(ListBox1.ItemIndex);
Сохраните проект, откомпилируйте и посмотрите, как он работает.
Часто бывает необходимым предоставить пользователю возможность множественного выбора. Пользователь, удерживая клавишу <Ctrl>, щелкает по строкам и выбирает нужные. Для этого у ListBox имеется свойство MultiSelect (множественный выбор). По умолчанию оно равно False, то есть запрещает пользователю выбрать несколько строк. Создадим еще одно приложение, в котором продемонстрируем возможность множественного выбора.
Установите на форму один ListBox и один Memo, ниже – кнопку с надписью "Копировать". При нажатии на кнопку будем искать у ListBox выделенные строки и копировать их в Memo. На рисунке 12.2 в левой части установлен компонент ListBox, а в правой – Memo.
Рис. 12.2. Внешний вид приложения
Войдите в редактор строк ListBox и напишите там
Строка № 1
Строка № 2
и так далее, пока не заполните ListBox так, чтобы его не нужно было прокручивать. Установите свойство MultiSelect у ListBox в True. Не забудьте очистить Memo. Теперь для кнопки напишем следующий код:
procedure TForm1.Button1Click(Sender:TObject);
var
i : Integer;
begin
Memo1.Clear;
for i := 0 to ListBox1.Items.Count - 1 do
if ListBox1.Selected[i] then
Memo1.Lines.Add(ListBox1.Items.Strings[i]);
end;
Вначале мы очистили Memo, чтобы пользователь мог несколько раз опробовать выбор и копирование строк, и строки в Memo не скапливались.
Затем мы создаем цикл, чтобы обрабатывать ListBox построчно. Первая строка всегда имеет нулевой индекс, а свойство Count во всех объектах TStrings возвращает количество строк в объекте. Нам приходится вычесть единицу, так как индексы начинаются не с 1, а с 0. Далее в цикл мы поместили условный оператор if – если условие верно (то есть строка выделена), то производим добавление строки в Memo. За это отвечает свойство Selected (Выделено) с указанием индекса строки. Если оно равно True, то строка выделена.
ComboBox – выпадающий список Такие списки вы часто встречаете при работе с Windows и различными программами. Действуют и работают они также как ListBox, с той только разницей, что выглядят по-другому, и не позволяют выбрать несколько элементов сразу. Создайте новое приложение, добавьте туда только один ComboBox и один Edit:
Рис. 12.3. Внешний вид приложения Вызовите редактор строк ComboBox (свойство Items) Впишите несколько городов: Москва Санкт-Петербург Киев Минск Ташкент Душанбе Свойство ItemIndex, которое, как мы знаем, указывает индекс выделенной строки, по умолчанию установлено в -1. Это означает, что ни одна строка не выбрана. Если установить его в 0, то в поле ввода текста появится первая строка списка. Оставим -1, чтобы строк не было видно. Создадим обработчик события OnChange для компонента ComboBox, и там напишем только одну строку: Edit1.Text := ComboBox1.Items.Strings[ComboBox1.ItemIndex]; Как видите, это почти точная копия работы с ListBox. Сохраните пример в новую папку, откомпилируйте и попробуйте как он работает. Управление циклами Вы знаете уже практически все циклы – for..do, while..do, repeat..until. Однако этими циклами можно еще и управлять. Для этого служат директивы break и continue. Break – прерывание цикла. Если внутри цикла встретится такой оператор, происходит немедленный выход из цикла. Как правило, этот оператор используют совместно с управляющей структурой if, например: if a <> b then break; Следовательно, если возникнет какое-то недопустимое для цикла условие, вы всегда имеете возможность прервать цикл досрочно. Continue – прерывание текущего шага цикла. В отличие от break, continue не прекращает цикл вовсе, а лишь прерывает дальнейшую обработку этого шага цикла, после чего цикл сразу начинается со следующего шага. Способ применения такой же, как у break. Рассмотрим работу continue на практическом примере. Нам нужно разделить число 10 на число от -3 до 3 включительно, и результат вывести в ListBox. Поскольку выводить будем также целые числа, нам поможет функция Round(), которая принимает вещественное число, округляет его до ближайшего целого и это целое возвращает. Также мы знаем, что на ноль делить нельзя, это ошибка. Для того, чтобы не допустить это деление, мы прервем этот шаг цикла с помощью директивы continue. Создайте новое приложение. Установите на форму ListBox, а под ним – кнопку:
Рис. 12.4. Внешний вид приложения При нажатии на кнопку, напишите следующий код: procedure TForm1.Button1Click(Sender: TObject); var i, r : Integer; begin for i := -3 to 3 do begin if i = 0 then begin ListBox1.Items.Add('Нанольделитьнельзя!'); Continue; end; //if
r := Round(10/i); ListBox1.Items.Add('10/'+IntToStr(i)+'='+IntToStr(r)); end; //for
end; В тот момент, когда счетчик i станет равным 0, выполнится тело условия if, и после оператора Continue цикл сразу перейдет на новый виток, пропустив деление. Занятие 13
Самостоятельное задание В примере мы жестко задали условия: делить именно число 10 на диапазон чисел от -3 до 3. Измените пример так, чтобы пользователь мог сам указать какое число нужно делить, и на какой диапазон. Это несложное задание, однако, придется подключить к работе мозги.
|
||
|
||
Диалоги Что такое диалоги в Delphi? Это невизуальные, то есть, невидимые пользователю компоненты, которые выполняют стандартные для Windowsдиалоги пользователя и программы. Например, диалог открытия или сохранения файла, диалог выбора шрифта или цвета, и т.п. Любая серьезная программа содержит такие диалоги. Работа с ними несложная, каждый диалог содержит буквально по два свойства, которые нам будут нужны. Изучим работу диалогов на примере. Открываем новый проект. Сразу же форму переименовываем в fMain, в свойстве Caption пишем "Мой блокнот". Сохраните проект под именем Editor. Это будет более профессиональная версия редактора текстов, какой мы уже делали. Считайте, что это вторая версия программы, что и напишете в окне fAbout. Установите на форму компонент Memo, удалите весь текст из его свойства Lines. Поверх Memo установите MainMenu и PopupMenu. Перейдите на вкладку Dialogs в палитре компонентов, и также поверх Memo установите OpenDialog, SaveDialog, FontDialog и ColorDialog. Все эти компоненты не визуальные, пользователь их видеть не сможет. У Memo сразу же укажите свойство Align=alClient, а свойство ScrollBar=ssVertical. Рекомендую для лучшего вида выбрать шрифт (свойство Font) Times New Roman, а размер = 12. На всех компьютерах с русской Windows есть этот шрифт, однако если вы будете писать программу для продажи в Интернет, лучше оставить шрифт по умолчанию, это гарантирует, что он будет читаться на всех компьютерах в мире. Во всех диалогах есть один метод, который нас интересует – Execute. Это метод логического типа, он возвращает True, если диалог с пользователем произошел успешно (например, пользователь выбрал открываемый файл), и False в противном случае (например, пользователь отказался от выбора файла). В связи с этим, диалоги обычно применяют вместе с проверкой: if OpenDialog1.Execute then... В диалогах, связанных с файлами (OpenDialog – открыть файл, и SaveDialog – сохранить файл), есть свойство FileName, которое возвращает строку – адрес и имя выбранного файла. Вот, собственно, и все, что нам нужно от этих диалогов! ДиалогFontDialog в свойстве Font возвращает выбранный шрифт. Это свойство непростое, оно имеет тип TFont, и присвоить его можно только другому шрифту, например: Memo1.Font := FontDialog1.Font; Точно также, диалогColorDialog возвращает свойство Color – цвет, имеющее тип TColor, и это свойство можно присвоить только объекту, имеющему такой же тип: Memo1.Color := ColorDialog1.Color; Продолжимнашпроект. Откройте редактор главного меню. Создайте раздел "Файл" и подразделы "Открыть", "Сохранить", "Закрыть", "-" и "Выход". Создайте раздел "Параметры" и подразделы "Выбрать шрифт" и "Выбрать цвет". Создайте раздел "Справка" и подраздел "О программе". Теперь открываем редактор PopupMenu и вписываем разделы "Открыть", "Сохранить", "Закрыть", "-" и "Выход". Сразу же на форме выделяем саму форму (это можно сделать в окне Object – TreeView), и в свойстве PopupMenu выбираем наше меню. Теперь это меню откроется, если пользователь щелкнет правой кнопкой по любому месту на форме. Теперь нам нужно настроить фильтры в диалогахOpenDialog (Открыть) и SaveDialog (Сохранить). Фильтры позволяют отображать в этих диалогах только нужные форматы файлов, и для этого выбора используется маска файла. К примеру, маска *.* будет отображать файлы всех типов! Дважды щелкнув по свойству FilterдиалогаOpenDialog, откройте редактор фильтров. В первой колонке напишите "Текстовые документы", во второй – "*.txt". В строке ниже укажите "Все файлы", а во второй колонке – "*.*". Тоже самое сделайте для диалогаSaveDialog:
Рис. 13.1. Настройка фильтра файловых диалогов Теперь, открывая файл, вы увидите только эти два типа файлов. Подумаем о том, что программа должна знать – изменился ли текст в Memo. Ведь пользователь может закрыть программу и не сохранить текст, а потом будет ругать программиста за то, что он этого не предусмотрел. При этом имеем в виду, что у нас есть много команд меню, значит, будет много процедур. А чтобы дать программе знать, изменился ли текст, разумнее всего создать переменную логического типа – изменился текст, присваиваем ей True, иначе False. Чтобы с этой переменной можно было работать из всех процедур, она должна быть глобальной. Делаем глобальную переменную перед словом implementation: izmen : Boolean; //изменился ли текст в Memo Событию onChange компонента Memo присвойте строку: izmen := True; Как только изменится текст в Memo, переменная тут же будет выдавать истину. Теперь еще один момент – программа должна знать имя и адрес открытого файла. Если имени файла нет, то программа будет выводить диалоговое окно, а если мы файл открывали и имя есть, то программа просто будет перезаписывать тот файл без вывода диалогового окна. Стало быть, делаем еще одну глобальную переменную: myfile : String; //Адрес и имя открытого файла Я специально не беру широко распространенные слова "File" или "FileName", так как они могут быть зарезервированными или в компонентах могут быть свойства с такими именами, в результате получится конфликт названий. Соображаем дальше. Открыть файл можно будет командой меню "Файл – Открыть", либо командой PopupMenu "Открыть". Стало быть, нам придется дважды писать один и тот же код? А если он будет большим и сложным? Можно конечно и скопировать его, компилятор это выдержит, и программа будет работать нормально. А как же оптимизация кода? Два одинаковых кода в программе будут занимать в два раза больше места в памяти и на диске! Для этого мы имеем пользовательские функции и процедуры. Вспоминаем – функцию или процедуру мы должны описать ВЫШЕ того места, где будем ее использовать, значит, первую нашу процедуру мы должны описать в разделе implementation, прямо под строчкой {$R *.dfm}. Сейчас вы узнаете еще кое-что новенькое. В таких вот пользовательских процедурах и функциях вы не можете напрямую обращаться к компонентам формы, поскольку Ваши процедуры и функции самой форме не принадлежат. Если Вы введете Memo1. то компилятор сразу выдаст ошибку. Обращаться к компоненту нужно, указав сначала имя формы, на которой он находится: fMain.Memo1. Однако такой код будет не слишком удобен – каждый раз придется обращаться к компонентам через форму. Лишний набор кода, излишне длинный текст. Выход есть – функция with (с). Эта функция имеет вид: with fMain do begin ... end; где fMain – имя формы с нужными нам компонентами. Теперь между скобок begin...end этой конструкции мы можем обращаться к компонентам формы напрямую. Пишем общую для всех процедуру открытия файла: {Процедура открытия файла} procedure Otkrivaem; begin with fMain do begin //делатьвместесформой if OpenDialog1.Execute then begin //еслидиалогвыполнен //присваиваем переменной myfile адрес и имя выбранного файла: myfile := OpenDialog1.FileName;
//читаемэтотфайлв Memo: Memo1.Lines.LoadFromFile(myfile); izmen := False; //файлтолькооткрыт, измененийещенет end; //if end; //with end; Теперь создаем обработчик событий для команды меню "Файл – Открыть". Там вызываем нашу процедуру: Otkrivaem; Тоже самое делаем для команды PopupMenu "Открыть".
|
||
|
||
|
||
Дальше – сложней. Открыть файл просто, но вот при сохранении нам придется учитывать много вещей:
Видите? Пользоваться диалогами несложно, но как много приходится учитывать во время проверок действий пользователя! Нужно учитывать каждую мелочь, иначе вам скажут, что ваша программа полна "багов" - мелких неисправностей. Итак, пишем процедуру сохранения, сразу под процедурой открытия: {Процедура сохранения файла} procedure Sohranyaem; begin with fMain do begin //если изменений не было, выходим из процедуры, //ничегонеделая: if not izmen then Exit;
//Если файл уже открывался, и в переменной myfile //есть его адрес и имя, просто перезаписываем этот файл: if myfile <> '' then begin Memo1.Lines.SaveToFile(myfile); izmen := False; Exit; //выходим после сохранения end; //if
{Файл новый, переменная myfile еще пуста. Дальше есть два варианта: пользователь выберет или укажет файл в диалоге, или не сделает этого}
//есливыбралфайл: if SaveDialog1.Execute then begin //прописываем адрес и имя файла в переменную: myfile := SaveDialog1.FileName; //если нет расширения *.txt то добавляем его: if copy(myfile, length(myfile)-4, 4) <> '.txt' then myfile := myfile + '.txt'; //сохраняем Memo вуказанныйфайл: Memo1.Lines.SaveToFile(myfile); //файл сохранен, изменений нет: izmen := False; end //if //если не выбрал файл: else ShowMessage('Вы не указали имени файла, файл не сохранен!');
end; //with end; Приведенный выше код имеет достаточно подробные комментарии, так что все должно быть понятно. Новое, что вы могли увидеть – директива Exit. Эта директива досрочно завершает работу процедуры (или функции). То есть, если выполнено условие и отработан нужный код, Exit заставляет процедуру завершить работу. Остальной код, который есть в этой процедуре, не выполняется. Теперь мы можем создать обработчик главного меню "Файл – Сохранить", и там прописать вызов этой процедуры: Sohranyaem; Тоже самое делаем для команды PopupMenu "Сохранить". Далее идет команда главного и всплывающего меню "Выход". Тут все просто, в обоих случаях пишем команду Close; Далее идет раздел "Параметры". Создаем обработчик "Выбрать шрифт", там все просто: if FontDialog1.Execute then Memo1.Font := FontDialog1.Font; Точно также и с подразделом "Выбрать цвет": if ColorDialog1.Execute then Memo1.Color := ColorDialog1.Color; Далее вернемся в раздел "Файл". Здесь у нас остался подраздел "Закрыть". Создаем для него обработчик, и запишем текст: {если файл не сохранен, предупреждаем пользователя об этом. Если он желает сохранить, то вызываем процедуру сохранения:} if izmen then if Application.MessageBox('Файлизменен. Сохранить?', 'Внимание!', MB_YESNO+MB_ICONQUESTION) = IDYES then Sohranyaem;
//теперь закрываем текущий файл: Memo1.Clear; //очищаем Мемо myfile := ''; //нет имени текущего файла izmen := False; //нет изменений Здесь не так много текста, и он вполне понятен, поэтому не будем для него делать отдельную процедуру. Просто скопируйте текст, создайте обработчик событий для "Закрыть" PopupMenu и вставьте этот же текст туда. Примерно тоже самое нам придется сделать и для события формы onClose – ведь мы заранее не можем знать, каким образом пользователь закроет форму, через команду главного меню "Файл – Закрыть", через команду всплывающего меню "Закрыть", нажмет ли он красный крестик наверху или нажмет горячие клавиши <Alt + F4>! Поэтому для проверки – есть ли в программе несохраненный текст, мы используем событие onClose, которое случается при попытке закрыть форму, то есть в данном случае всю программу. Здесь код будет таким же, как и в предыдущем примере, но раз мы закрываем всю программу, нам не нужно выполнять блок закрытия файла. Просто проверим, есть ли изменения, и если они есть, выведем запрос – сохранить ли их. Если пользователь ответит "Да", значит, вызовем процедуру сохранения: {если файл не сохранен, предупреждаем пользователя об этом. Если он желает сохранить, то вызываем процедуру сохранения:} if izmen then if Application.MessageBox('Файлизменен. Сохранить?', 'Внимание!', MB_YESNO+MB_ICONQUESTION) = IDYES then Sohranyaem; Теперь введем еще одну команду для обоих меню – "Очистить". Она будет предназначена на случай, если пользователь введет абракадабру, а потом решит очистить текст. Я намеренно оставил это действие на конец, чтобы вы могли усвоить, что в процессе работы над программой меню может изменяться! Откройте редактор MainMenu, в разделе "Файл" в самом низу добавьте подраздел "Очистить". Затем мышкой перетащите его на место линии разделов, при этом линия опустится вниз, а новый подраздел встанет на ее место:
Рис. 13.2. Вид главного меню Создайте для команды "Очистить" обработчик, и впишите туда текст: {MainMenu - Файл - Очистить} procedure TfMain.N17Click(Sender: TObject); begin //очищаемМемо: Memo1.Clear; //если открытого файла нет, то нет и изменений: if myfile = '' then izmen := false //иначе текст изменен: else izmen := true; end; Сделайте то же самое для всплывающего меню – создайте раздел "Очистить", а в его обработчик скопируйте тот же текст. Осталось создать модальное окно fAbout, где Вы укажете, что это текстовый редактор, второй версии. Сделайте это самостоятельно и привяжите вызов этой формы к команде главного меню "Справка – О программе". Все, сохраняйте, компилируйте и проверяйте, как работает программа! У нас получился несложный, но вполне профессиональный редактор текстов. Одно замечание: текст мы сохраняем, но вот выбранный шрифт и цвет окна Вы сохранить не можете, об этом мы будем говорить на других лекциях, когда научимся сохранять параметры. Обработка исключений в Delphi
|