ПОЗНАВАТЕЛЬНОЕ Сила воли ведет к действию, а позитивные действия формируют позитивное отношение Как определить диапазон голоса - ваш вокал
Игровые автоматы с быстрым выводом Как цель узнает о ваших желаниях прежде, чем вы начнете действовать. Как компании прогнозируют привычки и манипулируют ими Целительная привычка Как самому избавиться от обидчивости Противоречивые взгляды на качества, присущие мужчинам Тренинг уверенности в себе Вкуснейший "Салат из свеклы с чесноком" Натюрморт и его изобразительные возможности Применение, как принимать мумие? Мумие для волос, лица, при переломах, при кровотечении и т.д. Как научиться брать на себя ответственность Зачем нужны границы в отношениях с детьми? Световозвращающие элементы на детской одежде Как победить свой возраст? Восемь уникальных способов, которые помогут достичь долголетия Как слышать голос Бога Классификация ожирения по ИМТ (ВОЗ) Глава 3. Завет мужчины с женщиной 
Оси и плоскости тела человека - Тело человека состоит из определенных топографических частей и участков, в которых расположены органы, мышцы, сосуды, нервы и т.д. Отёска стен и прирубка косяков - Когда на доме не достаёт окон и дверей, красивое высокое крыльцо ещё только в воображении, приходится подниматься с улицы в дом по трапу. Дифференциальные уравнения второго порядка (модель рынка с прогнозируемыми ценами) - В простых моделях рынка спрос и предложение обычно полагают зависящими только от текущей цены на товар. | Пример. Вычисление факториала Вычисление факториала - классическая в программировании задача на использование рекурсии. Факториал числа N - результат перемножения всех чисел от 1 до N (обозначается N!): N! = 1*2* ... *(N-1)*N = N*(N-1)! урок 10 Обработка исключительных ситуаций Исключительные ситуации в Delphi встречаются постоянно. Исключительная ситуация это такая ситуация, в результате которой генерируется ошибка, и выполнение программы прерывается. Именно потому такая ситуация и называется исключительной. Например, деление на ноль - классический пример исключительной ситуации. Как в такой ситуации действует человек? Если он пытается что-то сделать, и это не получается - он идёт другим путём. Так же и компьютер, следующий программе, умеющей обрабатывать исключительные ситуации. Он не бросает выполнение программы, не виснет, а обходит исключительную ситуацию, выполняя альтернативный вариант фрагмента, в которой исключительная ситуация возникла. Возникает вопрос, почему бы не поставить проверку, например, на равенство нулю знаменателя при делении? Можно и поставить. Но во многих случаях источник исключительной ситуации далеко не так очевиден, а на все случаи жизни проверки не введёшь. Итак, для контроля исключительных ситуаций программист должен подготовить как основной вариант фрагмента, где возможна исключительная ситуация, так и его вариант, в котором она заведомо невозможна, или выводится информационное сообщение для пользователя. Вот как выглядит оператор контроля исключительных ситуаций: try основные операторы фрагмента; except альтернативный вариант фрагмента; end; Вначале производится попытка выполнить операторы секции try/except, содержащие основной вариант программы. При возникновении в каком-либо операторе этой секции исключительной ситуации остальные операторы секции пропускаются, и выполняется секция except/end. Если всё "проходит штатно", то секция except/end пропускается. Ещё один вариант оператора контроля исключительных ситуаций применяется, когда необходимо, чтобы определённый фрагмент кода выполнился в любом случае, возникла исключительная ситуация или нет: try операторы finally заключительные действия end; Основные операторы, находящиеся в секции try, могут пройти штатно, или вызвать исключительную ситуацию. Операторы заключительных действий, находящиеся в секции finally, будут выполнены в любом случае. Есть ещё один способ контроля исключительных ситуаций, касающийся ошибок операций ввода-вывода. Перед участком программы, где возможны ошибки ввода-вывода (а это, по сути, все операторы ввода-вывода), ставится директива {$I-}, заставляющая компилятор не включать в код автоконтроль ошибок ввода-вывода. Таким образом, в случае ошибки ввода или вывода программа не прерывается. В конце участка с операторами ввода-вывода ставится директива, включающая автоконтроль: {$I+}. Затем анализируется результат вызова функции IOResult. Если функция IOResult (вызывается без параметров) возвращает 0, значит ошибок ввода-вывода на данном участке не было. Вот какой пример использования директив {$I} и функции IOResult содержит справка системы Delphi: var F: file of Byte; begin if OpenDialog1.Execute then begin AssignFile(F, OpenDialog1.FileName); {$I-} Reset(F); {$I+} if IOResult = 0 then begin MessageDlg('File size in bytes: ' + IntToStr(FileSize(F)), mtInformation, [mbOk], 0); CloseFile(F); end else MessageDlg('File access error', mtWarning, [mbOk], 0); end; end; Функция IOResult досталась Delphi в наследство от Turbo Pascal. Тот же самый фрагмент можно составить и с использованием оператора try. На мой взгляд, это удобнее и проще. При работе программы под управлением Delphi, система будет сама реагировать на исключительные ситуации, мешая работе операторов обработки исключений. Чтобы проверить их действие, можно запускать программу непосредственно, сворачивая Delphi и пользуясь ярлыком, установленном на Рабочем столе. Или можно отключить реакцию системы на исключительные ситуации, тем самым давая возможность отработать специально для этого написанным фрагментам программы - нашим операторам try/except/end. Для этого откроем пункт системного меню Delphi Tools -> Debugger Options.... В появившемся окошке нужно снять галку в чекбоксе Stop on Delphi Exceptions, расположенном на вкладке Language Exceptions. Теперь система Delphi будет предоставлять вашей программе возможность самостоятельно обрабатывать исключительные ситуации, среди которых могут быть и ситуации, возникновение которых прописано специально как удобный инструмент достижения необходимых результатов. Урок 11 Обзор компонентов Итак, среда разработки Delphi ориентирована, прежде всего, на создание программ для Windows. При этом большое внимание уделяется возможности визуальной разработки приложений с помощью большого набора готовых компонентов Delphi, позволяющих избежать ручного кодирования. Компоненты Delphi охватывают практически все аспекты применения современных информационных технологий. Конечно, для работы в Delphi прежде всего требуется изучить базовые компоненты Delphi, которые требуются при подготовке практически любого приложения. Страница Standart Изучение Delphi естественным образом начинается со страницы палитры компонентов Standart. На этой странице расположены стандартные для Windows интерфейсные элементы, такие как главное и всплывающее меню, кнопка, однострочный и многострочный редакторы, переключатели, метки, списки, и некоторые другие компоненты, применяющиеся наиболее часто.
Страница Additional На страницу Additional помещены дополнительные компоненты, без некоторых из которых сегодня трудно представить программу для Windows: кнопки с дополнительными свойствами, таблицы, компоненты для размещения изображений...
Страница Win32 Эта страница содержит компоненты, представляющие собой интерфейсные элементы для 32-разрядных операционных систем Windows 95/98/NT (В версии системы Delphi 2 эта страница называлась Win95). Использующие эти компоненты программы выглядят в стилистике последних версий операционных систем Windows.
Страница System На этой странице представлены компоненты, которые имеют различное функциональное назначение (например, Timer - очень важный в любой программе компонент), в том числе компоненты, поддерживающие стандартные для Windows технологии межпрограммного обмена данными OLE и DDE. Урок 12 Работа со строками Список строк Delphi TStringList - это структура данных, напоминающая компонент ListBox, но не визуальная, а просто хранящая в памяти и имеющая свойства и методы для работы со строками типа TString. Для работы со списком строк типа TStringList его сначала необходимо создать с помощью конструктора - Create: var StrList: TStringList; begin StrList:=TStringList.Create; Теперь нужно описать способ хранения строк в списке. Список строк типа TStringList может сортировать добавляемые строки или хранить без сортировки, а также может игнорировать попытки добавления новой строки при наличии уже сохранённого дубликата: StrList.Sorted:=True; | //True - сортировать, False - не сортировать | StrList.Duplicates:=dupIgnore; | //dupAccept - сохранять дубликаты (значение по умолчанию), dupIgnore - игнорировать, dupError - вызвать сообщение об ошибке | Теперь можно добавить в список строки типа TString: StrList.Add('Новая строка'); | //Добавление в конец списка (или в порядке сортировки). Возвращается индекс строки | StrList.Insert(Index, 'Новая строка'); | //Строка добавляется на позицию с номером Index. Если список отсортирован, то возникает исключительная ситуация. | Удалить строку: StrList.Delete(Index); // Удаление строки с номером Index; Количество строк в списке: N:=StrList.Count; Доступ к строке с номером Index: Str:=StrList[Index]; Index отсчитывается от 0, поэтому номер последней строки: Last:=StrList.Count-1; Очищаем список строк: StrList.Clear; Если список отсортирован, есть метод для поиска: StrList.Find(S, Index); | // В случае удачного поиска возвращает True, и индекс строки S в переменной Index | Если список не отсортирован, то тоже есть функция поиска: I:=StrList.IndexOf(Text); | // Возвращает индекс строки с заданным текстом Text, или -1, если поиск неудачен | В конце работы со списком его необходимо удалить из памяти: StrList.Free; end; Как видим, список типа TStringList обладает ценным свойством, которым вряд ли обладает какой-либо другой объект в Delphi, а именно возможностью обнаруживать дубликаты строк. Как узнать, что строка уже содержится в списке? Вот алгоритм: 1. Запретить списку запись дубликатов, что возможно только при задании сортировки списка. Это делается один раз, при создании списка, например, по событию Формы OnCreate: StrList.Duplicates:=dupIgnore; StrList.Sorted:=True; 2. Сохранить в переменной количество строк в списке: begin Count:=StrLst.Count; 3. Попробовать записать новую строку: StrList.Add(NewLine); 4. Сравнить количество строк в списке с прежним значением. Если оно совпадёт с количеством перед записью, то такая строка в списке уже есть: if StrList.Count=Count then ShowMessage('Попытка добавления дубликата'); end; Аналогичный, на мой взгляд даже более удобный, алгоритм реализации этой процедуры связан с использованием метода обработки исключений. Если вместо StrList.Duplicates:=dupIgnore для обработки дубликатов использовать значение dupError, это вызовет исключительную ситуацию при попытке добавить дубликат. Соответственно, при добавлении оригинальной строки программа идёт дальше, а при попытке добавления дубликата переходит к операторам секции except/end. Эти методы работают в случае если список отсортирован. Однако есть задачи, где сортировка не нужна, а находить значение в списке всё равно необходимо. В этом случае нужно пользоваться функцией IndexOf. Рассмотрим пример Есть таблица, содержащая список студентов с указанием их роста и веса. Нужно выделить группу студентов, чей рост или вес встречаются наиболее часто. Алгоритм решения задачи будет такой. Создадим три списка строк. В цикле будем просматривать таблицу и добавлять в первый список строк значение анализируемого параметра, если его ещё в списке нет. Во второй список будем сохранять фамилии студентов, обладающих данным ростом или весом, а в третьем - в соответствующей строке подсчитывать сколько раз это значение уже встретилось. Вот что должно получиться: Исходная таблица | Первый список | Второй список | Третий список | Фамилия | Рост | Вес | Иванов | | | Петров | | | Сидоров | | | Ковалёв | | | | Анализ по росту 179 180 175 | Иванов, Сидоров Петров Ковалёв | 2 1 1 | Переходя к новой строке в исходной таблице, мы анализируем нужный параметр, рост или вес - ищем в первом списке. Если такого значения у нас пока нет, мы в каждый список добавляем по строке, в первый записываем значение параметра, во второй - фамилию, а в третий - пишем единичку. А если такое значение параметра уже есть, то в соответствующую строку второго списка добавляем через запятую очередную фамилию, а в третьем значение в этой строке увеличиваем на 1. Естественно, списки строк не должны сортировать вводимые значения, иначе данные перепутаются! Дойдя до конца таблицы, нам останется в третьем списке найти строку с максимальным числом, и вывести как результат содержимое этой строки второго списка. Получилась такая программка:  вот процедура подсчёта: procedure TForm1.Button1Click(Sender: TObject); var i, k: Integer; begin Caption:=''; List1.Clear; List2.Clear; List3.Clear; Param:=ComboBox1.ItemIndex+1; for i:=1 to StringGrid1.RowCount-1 do begin k:=List1.IndexOf(StringGrid1.Cells[Param, i]); if k=-1 then begin List1.Add(StringGrid1.Cells[Param, i]); List2.Add(StringGrid1.Cells[0, i]); List3.Add('1'); end else begin List2[k]:=List2[k]+', '+StringGrid1.Cells[0, i]; List3[k]:=IntToStr(StrToInt(List3[k])+1); end; end; k:=0; for i:=0 to List3.Count-1 do if StrToInt(List3[i])>k then k:=StrToInt(List3[i]); for i:=0 to List2.Count-1 do if StrToInt(List3[i])=k then Caption:=Caption+List2[i]+': '+List1[i]+'; '; end; Сортировка в StringList'е С помощью StringList можно реализовать интересный вариант сортировки чисел. Хотя StringList сортирует строки, он также будет сортировать и записанные в него в виде строк числа. Естественно, напрямую отсортировать числа таким образом не получится, так как строка, например, '100' будет меньше, чем строка '20', что для чисел 100 и 20, естественно, неверно. Однако достаточно выровнять длину строк добавлением к целой части слева, а к дробной справа пробелов ' ', чтобы сортировка сработала верно. Программисты, создавшие класс TStringList, наделили его очень быстрым алгоритмом сортировки (к тому же реализованным, видимо, с использованием низкоуровневого программирования), чем мы просто не можем не воспользоваться. По сравнению с сортировкой пузырьком, которая 100 000 чисел сортирует за 32 с половиной секунды на моём компе (или 24 сек улучшенный алгоритм), сортировка в StringList'е длится всего 530 мсек! Вот процедура для целых чисел: procedure StringListForSort; var S: TStringList; i, max: Integer; Taim: Int64; begin Taim:=GetTickCount; max:=0; S:=TStringList.Create; for i:=1 to Form1.Grid.RowCount-1 do begin if Length(Form1.Grid.Cells[1, i])>max then max:=Length(Form1.Grid.Cells[1, i]); S.Add(Form1.Grid.Cells[1, i]); end; for i:=0 to S.Count-1 do while Length(S[i])<>max do S[i]:=' '+S[i]; S.Sort; Form1.Caption:='Продолжительность сортировки '+IntToStr(GetTickCount-Taim)+' мсек'; for i:=1 to Form1.Grid.RowCount-1 do Form1.Grid.Cells[1, i]:=Trim(S[i-1]); S.Free; end; Здесь Grid - обычная таблица типа TStringGrid, предварительно заполненная целыми числами. Продолжительность сортировки возвращается в заголовке Формы. |