Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Интернет: Образование, Работа и Бизнес" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Август 2009 → | ||||||
1
|
2
|
|||||
---|---|---|---|---|---|---|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
22
|
23
|
25
|
26
|
27
|
28
|
29
|
30
|
|
31
|
Статистика
-1 за неделю
Программирование на Delphi (выпуск 87)
Программирование на DELPHI
Рассылка сайта www.delphi.int.ru
Выпуск #87 (22 августа 2009 г.)
Если Вы хотите где-либо разместить материалы, представленные на www.delphi.int.ru или в данной рассылке, свяжитесь, пожалуйста, с их автором или ведущим рассылки.
Delphi.int.ru Expert Последние новости
Архив: вопросы и ответы В архив попадают вопросы, срок действия которых истёк. Каждый заданный вопрос действителен в течение одной недели, т.е. ответы на него принимаются именно в этот период. В сегодняшнем выпуске опубликованы вопросы # 1000 - 1030. Вопросы, на которые не было дано ни одного ответа, не публикуются. Статистика по выпуску:
Вопрос # 1 000 Приветствую, уважаемые эксперты! Скажите, как можно реализовать некоторое подобие рабочего стола, то есть расположить иконку на форме, при щелчке на которую (иконку) будет открываться соответствующий файл?
Ответ #1. Отвечает эксперт: Вадим К Здравствуйте, Гадлевский Олег Вячеславович! if ListView1.ItemIndex = -1 then exit; ShowMessage(ListView1.Items[ListView1.ItemIndex].Caption);Теперь при двойному клику будет появлятся сообщение с именем элемента. Индекс его тоже известен. А вот что на самом деле должно отображаться - это решать вам. Теперь о том, как "запустить" файл. для этого добавим в список Uses юнит ShellApi и будем использовать такой код ShellExecute (Form1.Handle, nil, PAnsiChar(filename), nil, nil, SW_RESTORE); в качестве filename может быть как имя выполнимого файла так и например вордовский документ. а вот такой строкой можно запустить броузер ShellExecute (Form1.Handle, nil, 'iexplore', 'http://expert.delphi.int.ru', nil, SW_RESTORE); Остался последний вопрос. "а как связать иконку и путь к файлу (действие)? ведь неудобно по имени делать выбор". Тут советую прочитать мою статью о виртуальном ListView Как прицепить всплывающее меню предлагаю подумать самостоятельно.
Вопрос # 1 001 Здравствуйте, уважаемые эксперты! Как стройть графики с помощью TChart.
Ответ #1. Отвечает эксперт: min@y™ В папке %Delphi%DemosTeeChart лежит офигенное демо по построению всевозможных графиков, диаграмм и пр. Файл проекта - teedemo.dpr, скомпили его и запусти ЕХЕ-шник, посмотри. Выбери понравившийся график и изучи исходник его построения.
Вопрос # 1 002 Здравствуйте! Скажите пожалуйста, как добавить иконку в ListView?
Ответ #1. Отвечает эксперт: min@y™ Пишу по памяти. Берёшь ImageList и заполняешь его иконками, какими надо. Затем ставишь у ListView свойства Images и LargeImages равными твоему ImageList. ListView.ViewStyle:= vsIcon; with ListView.Items.Add() do begin Caption:= 'Название новой иконки'; ImageIndex:= <номер иконки в ImageList>; end; Ну вот как-то так.
Вопрос # 1 004 Здравствуйте, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Матвеев Игорь Владимирович Здравствуйте, Anton-L! Clipboard.SetTextBuf(PChar(Memo1.Text)); 2. Вставка текста: Memo1.Text := Clipboard.AsText; Не забудьте включить в uses модуль Clipbrd в котором реализован класс TClipboard.
Ответ #2. Отвечает эксперт: min@y™ У TMemo есть также такие методы как CopyToClipboard(), CutToClipboard(), PasteFromClipboard(), которые копируют/вырезают выделенный текст из БО и вставляют из БО соответственно.
Ответ #3. Отвечает эксперт: Feniks Здравствуйте, Anton-L! procedure TForm1.Cut1Click(Sender: TObject); begin SendMessage (ActiveControl.Handle, WM_Cut, 0, 0); end; procedure TForm1.Copy1Click(Sender: TObject); begin SendMessage (ActiveControl.Handle, WM_Copy, 0, 0); end; procedure TForm1.Paste1Click(Sender: TObject); begin SendMessage (ActiveControl.Handle, WM_Paste, 0, 0); end;
Вопрос # 1 005 Здравствуйте!
Ответ #1. Отвечает эксперт: Матвеев Игорь Владимирович Здравствуйте, POWER!
Ответ #2. Отвечает эксперт: Косолапов Дмитрий Юрьевич Здравствуйте, POWER!
Вопрос # 1 006 Доброго времени суток, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Вадим К Здравствуйте, Soulnet!
Вопрос # 1 007 Здравствуйте! Подскажите пожалуйста, можно ли в ListView сделать фон картинкой а не просто цветом?
Ответ #1. Отвечает эксперт: min@y™ Глянь для начала сюда, сюда и вот сюда.
Вопрос # 1 008 Здравствуйте, эксперты!
Ответ #1. Отвечает эксперт: Вадим К Здравствуйте, Emfs!
Ответ #2. Отвечает эксперт: min@y™ В кратце: плагины делаются в виде DLL, разработчикам этих DLL предоставляется API для взаимодействия с основной программой, т.е. имена и типы параметров экспортируемых и callback-функций (заголовочные файлы). Все DLL подключаются динамически. Советую посмотреть в инете, как пишутся плагины для Far'a и/или Total Commander'a. Я один такой когда-то написал. Для начала, я думаю, хватит.
Вопрос # 1 009 21. Как сделать циклы while и repeat бесконечными, и как в этом случае можно выйти из цикла.
Ответ #1. Отвечает эксперт: Косолапов Дмитрий Юрьевич Здравствуйте, natasha!
Ответ #2. Отвечает эксперт: Ершов Денис Здравствуйте, natasha!
Ответ #3. Отвечает эксперт: min@y™ Добавлю к предыдущим ответам.
Вопрос # 1 010 26. Написать функцию, которая преобразует заданную строку, так, чтобы все прописные русские буквы стали строчными. Написать пример обращения к этой функции.
Ответ #1. Отвечает эксперт: Матвеев Игорь Владимирович Здравствуйте, natasha! function UpRus(input: string): string; var i, l : DWord; c : Char; begin l := Length(input); Result := ''; for i := 1 to l do begin if input[i] in ['а'..'я'] then c := Chr( Ord(input[i]) - 32 ) else c := input[i]; Result := Result + c; end; end; function DownRus(input: string): string; var i, l : DWord; c : Char; begin l := Length(input); Result := ''; for i := 1 to l do begin if input[i] in ['А'..'Я'] then c := Chr( Ord(input[i]) + 32 ) else c := input[i]; Result := Result + c; end; end; Пример обращения: Edit1.Text := UpRus(Edit1.Text); Edit2.Text := DownRus(Edit2.Text);
Вопрос # 1 012 Доброго времени суток, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Dron Здравствуйте, puporev! function MyRandom(Min, Max: Integer): Integer; begin Result:=Random(Max-Min+1)+Min; end;Принцип работы очень прост - сначала мы выбираем случайное число от 0 до длины заданного диапазона, а затем делаем смещение, равное нижней границе. Дальше дело за малым - применить эту функцию. В примере генерируются 20 чисел от -10 до 20 и выводятся в ListBox: procedure TForm1.Button1Click(Sender: TObject); label NewRand; var i,r,min_r,max_r: integer; begin min_r:=-10; {Нижняя граница} max_r:=20; {Верхняя граница} for i := 1 to 20 do begin NewRand: r:=MyRandom(min_r,max_r); if r = 0 then goto NewRand; ListBox1.Items.Add(IntToStr(r)) end end;Обратите внимание, что для отсеивания нулей мы просто "крутим" генератор до тех пор, пока он не сгенерирует число, отличное от нуля. То же самое можно сделать без использования меток - с помощью цикла Repeat. P.S. Не забудьте прописать вызов Randomize. Удачи!
Вопрос # 1 013 Здравствуйте, эксперты! помогите Написать программу вычисления с заданной точностью корня квадратного из числа “a”, используя формулу Ньютона для последовательных приближений xnew = xold – (x2 – a)/(2a)
Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, natasha!
Вопрос # 1 014 Здравствуйте, эксперты! помогите Написать подпрограмму для вычисления с заданной точностью суммы бесконечного ряда 1 - x + x2/2! - x3 /3! + x4 /4! - …, для x<0
Ответ #1. Отвечает эксперт: Dron Здравствуйте, natasha! function GetElement(N: Integer; X: Real): Real; begin if N = 1 then Result:=1 else Result:=Power(X,N-1)/Factorial(N-1); end;Для вычисления факториала воспользуемся такой функцией: function Factorial(X: Integer): LongInt; var i: integer; begin Result:=1; for i := 2 to X do Result:=Result*i; end;Использованная в примере функция Power находится в модуле Math, который нужно подключить, добавив его название в раздел uses. А далее вспоминаем курс математического анализа - остаток ряда начиная с n-го члена не больше самого n-го члена. Этим и пользуемся: procedure TForm1.Button1Click(Sender: TObject); var S,X,A,E: Real; N: Integer; begin X:=StrToFloat(Edit1.Text); {Число X} E:=StrToFloat(Edit2.Text); {Точность вычислений} N:=1; A:=GetElement(1,X); repeat S:=S+A; Inc(N); A:=GetElement(N,X); until A < E; Label1.Caption:=FloatToStr(S); end;В данном примере значение x вводится в Edit1, в Edit2 вводится точность вычисления (например, 0.0001). Полученная сумма выводится в Label1. Ну и наконец, проверить точность достаточно просто - данный ряд является разложением функции ex, т.е. если взять x = 1, то сумма ряда будет равна самому числу e. --- Добавлено: ряд, рассмотренный в примере, является рядом функции ex. Ряд, указанный в вопросе - знакопеременный, он рядом этой функции не является. Подробности в мини-форуме вопроса.
Ответ #2. Отвечает эксперт: Николай Рубан Здравствуйте, natasha! Приложение:
Вопрос # 1 016 Приветствую, уважаемые эксперты! 47. Написать подпрограмму для вычисления с заданной точностью суммы бесконечного ряда 1 + w + w2 + w3 + w4 + …, для w<0
Ответ #1. Отвечает эксперт: Dron Здравствуйте, natasha! Result:=Power(X,N-1);; во втором - точно также, как в вопросе 1014, только убрать факториал.
Вопрос # 1 017 Приветствую, уважаемые эксперты! 45. Написать подпрограмму, которая бы уменьшала аргумент тригонометрических функций до значения меньшего 2pi.
Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, natasha!
Вопрос # 1 018 Приветствую, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, natasha!
Вопрос # 1 019 39. Написать функцию вычисления n!.
Ответ #1. Отвечает эксперт: Dron Здравствуйте, natasha! function Factorial(N: Integer): LongInt; var i: integer; begin Result:=1; for i := 2 to N do Result:=Result*i; end;
Ответ #2. Отвечает эксперт: Николай Рубан Здравствуйте, natasha!
Вопрос # 1 020 37. Написать функцию, которая возвращает среднее арифметическое для N случайных чисел.
Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, natasha!
Вопрос # 1 021 35. Написать функцию, которая возвращает максимальное число из последовательности N случайных чисел.
Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, natasha!
Вопрос # 1 023 Здравствуйте! Скажите, как можно сделать так, чтобы форма при запуске занимала весь экран, то есть накрывала и панель задач, даже если она автоматически не скрывается?
Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, Гадлевский Олег Вячеславович!
Ответ #2. Отвечает эксперт: Ершов Денис Здравствуйте, Гадлевский Олег Вячеславович!
Вопрос # 1 024 Здравствуйте, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Матвеев Игорь Владимирович Здравствуйте, GAZ!
Вопрос # 1 025 Доброго времени суток, уважаемые эксперты!
Ответ #1. Отвечает эксперт: min@y™ Не знаю, в каком виде хранятся данные у тебя во входном файле, но это не принципиально. Вот функция перевода числа S системы счисления с основанием B в целое (пёрто из RxStrUtils.pas): function Numb2Dec(S: string; B: Byte): Longint; var I, P: Longint; begin I := Length(S); Result := 0; S := UpperCase(S); P := 1; while (I >= 1) do begin if S[I] > '@' then Result := Result + (Ord(S[I]) - 55) * P else Result := Result + (Ord(S[I]) - 48) * P; Dec(I); P := P * B; end; end; Как записать числа в файл, я думаю труда не составит (?).
Вопрос # 1 026 Здравствуйте, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Dron Здравствуйте, Тамара!
Ответ #2. Отвечает эксперт: Вадим К Здравствуйте, Тамара!
Ответ #3. Отвечает эксперт: Ершов Денис Здравствуйте, Тамара!
Вопрос # 1 027 Приветствую, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Иусов Сергей Ник. Здравствуйте, natasha!
Вопрос # 1 028 Приветствую, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Николай Рубан Здравствуйте, natasha!
Ответ #2. Отвечает эксперт: Иусов Сергей Ник. Здравствуйте, natasha!
Вопрос # 1 029 Приветствую, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Иусов Сергей Ник. Здравствуйте, natasha!
Вопрос # 1 030 Приветствую, уважаемые эксперты!
Ответ #1. Отвечает эксперт: Иусов Сергей Ник. Здравствуйте, natasha!
» Найти все предыдущие уроки можно на www.delphi.int.ru в разделе "Статьи". Последние 5 уроков: Записи (часть 2)
ВведениеВ позапрошлом уроке мы познакомились с записями: узнали, что это такое, как их заводить в своих программах, и как с ними потом работать. В прошлом уроке мы вели разговор о работе с файлами и научились работать с содержимым файлов. Сегодня мы объединим полученные знания, попутно продолжив знакомство с записями. Записи с вариантамиЗаписи с вариантами - такой тип записей, у которых создано несколько наборов полей, а используемый набор определяется специальным полем-селектором. При этом часть полей могут быть общими для всех наборов. Например, мы хотим в программе хранить информацию об отрезке прямой на плоскости. Математически мы можем представить отрезок двумя способами:
Оба метода проиллюстрированы. Совершенно очевидно, что такую структуру удобно хранить в виде записи. Опишем первый вариант: type TLineSegment = record X1,Y1: Real; X2,Y2: Real; end; Для наглядности точки описаны отдельно, хотя короче будет поместить их в одну строку (X1,Y1,X2,Y2: Real). Теперь второй вариант: type TLineSegment = record X,Y: Real; //Один из концов отрезка Angle: Real; //Угол наклона Length: Real; //Длина отрезка end; Всё хорошо, оба варианта рабочие и удобные... Но теперь представьте, что в программе мы должны предоставить пользователю возможность ввода отрезка и первым, и вторым способом, т.е. он сам будет решать, как ему удобнее. Что делать в этом случае? Не писать же 2 программы, базируясь то на одной структуре, то на другой? Вот тут-то нам и придут на помощь записи с вариантами. Сначала давайте опишем простой перечислимый тип данных, который содержит два значения - тип описания отрезка: type TLineSegmentType = (lsPoints,lsPolar); Второй тип я назвал полярным, потому что это ни что иное, как полярные координаты. Что ж, теперь добавим в нашу запись переменную, которая будет определять тип описания отрезка: TLineSegment = record LType: TLineSegmentType; end; Но тип данных должен быть описан ещё до компиляции программы, поэтому оба набора данных следует описать прямо сейчас. А для выбора варианта применяется уже известный нам оператор case: TLineSegment = record case LType: TLineSegmentType of lsPoints: //Здесь нужно описать первый набор полей... lsPolar: //...а здесь второй end; end; Ещё раз: мы заводим переменную-селектор, применяем к ней оператор множественного выбора case, и для каждого из значений описываем нужный набор полей. Наборы необходимо заключать в круглые скобки. В нашем случае получится вот что: TLineSegment = record case LType: TLineSegmentType of lsPoints: ( X1,Y1: Real; X2,Y2: Real; ); lsPolar: ( X,Y: Real; Angle: Real; Length: Real; ); end; Здесь есть одна особенность: оператор case не требуется закрывать командой end. Варианты наборов должны располагаться всегда в конце списка полей (т.е. сначала описываются фиксированные поля, а затем вариантные) - это объясняет отсутствие end для case - запись так и так будет закрыта с помощью следующего end. В нашем случае структура всё ещё не оптимальна: координаты одной из точек у нас описаны в обоих наборах. Давайте вынесем их как постоянные поля: type TLineSegmentType = (lsPoints,lsPolar); TLineSegment = record X,Y: Real; //Один из концов отрезка case LType: TLineSegmentType of lsPoints: ( X2,Y2: Real; //Второй конец отрезка ); lsPolar: ( Angle: Real; //Угол наклона Length: Real; //Длина ); end; Это окончательный вид нашей записи. Посмотрите ещё раз и осмыслите написанное. Ну а теперь перейдём к более знакомым вещам - сделаем интерфейс для ввода информации об отрезке и запрограммируем внесение всех данных в запись. Уверен, что с интерфейсной частью вы справитесь сами, поэтому привожу лишь код кнопки: procedure TForm1.SaveButtonClick(Sender: TObject); var L: TLineSegment; begin if PointsRadio.Checked then L.LType:=lsPoints else L.LType:=lsPolar; case L.LType of lsPoints: begin L.X:=StrToFloat(X1Edit.Text); L.Y:=StrToFloat(Y1Edit.Text); L.X2:=StrToFloat(X2Edit.Text); L.Y2:=StrToFloat(Y2Edit.Text); end; lsPolar: begin L.X:=StrToFloat(XEdit.Text); L.Y:=StrToFloat(YEdit.Text); L.Angle:=StrToFloat(AngleEdit.Text); L.Length:=StrToFloat(LengthEdit.Text); end; end; end; Сначала мы смотрим, какой способа ввода у нас выбран на форме и соответствующим образом устанавливаем переменную-селектор LType. А затем уже переносим данные из полей ввода в нашу запись: если первый способ - из 4 левых полей, если второй - из 4 правых. С какой целью мы ввели отрезок? Ну например давайте посчитаем его длину. Для этого введём собственную функцию, которая на вход будет принимать запись, а на выходе будет выдавать длину отрезка. Если забыли математику, напомню способ вычисления длины:
function GetLength(L: TLineSegment): Real; begin case L.LType of lsPoints: Result:=Sqrt(Sqr(L.X2-L.X)+Sqr(L.Y2-L.Y)); lsPolar: Result:=L.Length; end; end; Что может быть проще? Ну и в конец обработчика нажатия кнопки добавим: MessageDlg('Длина отрезка: '+FloatToStr(GetLength(L)),mtInformation,[mbOk],0) Проверьте правильность работы, запустив программу и введя какие-нибудь данные. Помните, что программа работает с расчётом на то, что исходные данные верны, т.е. что вместо чисел вы не вписали "всем привет!". Упакованные записиПару слов о том, что такое упакованные записи, и с чем их едят. По умолчанию память под записи выделяется не очень экономно - помимо самих данных добавляются и служебные байты, которые отделяют блоки данных друг от друга. Существует принудительный способ заставить Delphi упаковать запись, т.е. минимизировать занимаемую ей память. Делается это указанием слова packed перед словом record. Разница порой может быть достаточно ощутимой. Пример: запись из строки длиной 5 символов, одного символа и трёх чисел разного типа. Объявим две разные записи: одна обычная, а другая упакованная: TRecord1 = packed record Name: String[5]; A: LongInt; C: Char; D: Double; N: Integer; end; TRecord2 = record Name: String[5]; A: LongInt; C: Char; D: Double; N: Integer; end; А теперь самое интересное: посмотрим, сколько памяти занимает каждая из записей. Сделаем это функцией SizeOf(): var R1: TRecord1; R2: TRecord2; begin ShowMessage(IntToStr(SizeOf(R1))); ShowMessage(IntToStr(SizeOf(R2))); end; В первом сообщении мы увидим 24, а во втором 32. Обычная запись занимает на треть больше памяти, чем упакованная! А теперь представьте, что у вас 100 000 таких записей? Тем не менее, не стоит пренебрегать этим способом экономии памяти. В некоторых случаях использование пакованных записей может создавать разные ошибки в работе программы. Понять, что дело именно в packed, удаётся далеко не сразу. Так что, если храните десяток отрезков - не торопитесь паковать - если и выиграете, то не сильно. Быстрый доступ к полям записейВ нашем примере у записи сравнительно мало полей - 4. Но бывают программы, где создаются записи с десятком полей и работа из-за этого замедляется. Хотя бы потому, что в коде приходится каждый раз набирать имя записи и точку, и лишь затем имя поля. Обрадую: мучаемся не только мы - компьютеру тоже приходится делать больше телодвижений. Каждый раз нужно определять адрес и искать запись в памяти, и лишь после этого можно найти значение поля. Чтобы облегчить участь и программисту и машине, был введён специальный оператор with (англ. "с"). К сожалению, о нём далеко не все знают, а ведь его использование увеличивает эффективность и кода, и работы самого программиста. Итак, общая форма записи: with запись do {обращение к полям записи} Не очень понятно? А теперь на нашем примере: with L do begin X:=StrToFloat(X1Edit.Text); Y:=StrToFloat(Y1Edit.Text); X2:=StrToFloat(X2Edit.Text); Y2:=StrToFloat(Y2Edit.Text); end; Что же мы имеем? А вот что: мы нашу запись "вынесли за скобку", и далее напрямую обращаемся к её полям. Удобно, не правда ли? Этот код абсолютно эквивалентен тому, что был написан нами ранее, только он более эффективен. Несложно догадаться, что использование with для единичного обращения к записи бессмысленно: with L do X:=5; В этом случае мы ни в чём не выигрываем - только пишем больше кода. Помните про оператор with и почаще его используйте - и себе жизнь облегчите, и программы станут профессиональнее. Хранение записей в файлахНу вот мы и подошли к тому, для чего пришлось затронуть тему работы с файлами. Использовать записи мы научились, но тут вопрос: а как их хранить? Сохранять в файлах отдельно каждое поле - совершенно неудобно. А потом его нужно оттуда ещё как-то прочитать... Неужели нет способа проще? Есть! Мы можем создать типизированный файл на основе имеющегося типа записи. Помните, как мы описывали файлы? file of ..., верно? Так вот, теперь в качестве типа будет выступать наша запись. Вернёмся к программе, которая позволяет ввести отрезок. Теперь перед нами задача сохранить этот отрезок в файл. Ну, не в буквальном смысле, конечно - просто сохранить все его параметры. Начнём с создания указателя на файл, который опишем указанным образом: F: file of TLineSegment; Этим мы сказали, что каждый элемент нашего файла - запись типа TLineSegment. А дальше всё как обычно - ничего нового: связываем указатель с файлом, открываем, записываем, закрываем. Без комментариев, что называется: AssignFile(F,ExtractFilePath(Application.ExeName)+'lines.dat'); Rewrite(F); Write(F,L); CloseFile(F); Всё это нужно добавить в конец обработчика кнопки "Сохранить". Запустите программу, введите произвольный отрезок и нажмите кнопку. Если всё было сделано правильно, после сообщения о длине отрезка в папке с программой появится файл lines.dat. Расширение dat - стандартное для нестандартных данных (вот так фразу завернул!). Вы можете открыть этот файл любым текстовым редактором, но прочитать что-либо там будет затруднительно - это бинарный файл. Теперь попробуем прочитать данные из этого файла. Создайте ещё одну кнопку "Загрузить". Код для неё будет такой: procedure TForm1.LoadButtonClick(Sender: TObject); var F: file of TLineSegment; L: TLineSegment; begin AssignFile(F,ExtractFilePath(Application.ExeName)+'lines.dat'); Reset(F); Read(F,L); CloseFile(F); MessageDlg('Длина отрезка: '+FloatToStr(GetLength(L)),mtInformation,[mbOk],0); end; Опять же, если всё было сделано верно, то вы увидите длину введённого ранее отрезка. Теперь давайте изменим нашу программу таким образом, чтобы вводимые отрезки добавлялись в файл, т.е. чтобы файл содержал сразу несколько записей. Но здесь нас подстерегает проблема: функция Append(), предназначенная для добавления данных в конец в файла, работает только с текстовыми файлами. У нас же файл типизированный и здесь такой фокус не пройдёт. Будем выполнять обходной манёвр. Предлагаю вот что: создадим временный файл, перепишем туда все записи из существующего файла, добавим новую запись, после чего удалим старый файл, а новый переименуем. Хитро, сложно? На самом деле не очень. Чтобы провернуть всё это, пришлось добавить 2 переменные - ещё одну запись и один файл. Под буквами "N" и "O" я подразумеваю "new" и "old" (новый и старый). procedure TForm1.SaveButtonClick(Sender: TObject); var L,OL: TLineSegment; F,NF: file of TLineSegment; begin {предыдущий код здесь опущен} SetCurrentDir(ExtractFilePath(Application.ExeName)+'lines.dat'); AssignFile(NF,'temp.dat'); Rewrite(NF); if FileExists('lines.dat') then begin AssignFile(F,'lines.dat'); Reset(F); while not EOF(F) do begin Read(F,OL); Write(NF,OL); end; CloseFile(F); end; Write(NF,L); CloseFile(NF); DeleteFile('lines.dat'); RenameFile('temp.dat','lines.dat'); end; Разберём этот код подробно. Сначала делаем папку с программой рабочей, чтобы каждый раз не писать путь. Далее ассоциируем указатель с новым файлом, и открываем этот файл для записи. Далее проверяем, есть ли файл с предыдущими записями. Как мы договорились, если он есть, то нужно переписать из него все записи: связываемся с файлом, открываем его для чтения, а далее цикл по всем полям записи. Функция EOF() позволяет узнать, дошли ли мы до конца файла. Таким образом, пока файл не кончился, читаем из него одну запись и переписываем её в новый файл. После завершения закрываем старый файл. Осталось самое простое - записать новую запись, что мы и делаем. После этого старый файл lines.dat удаляем, а временный temp.dat переименовываем в новый lines.dat. Таким образом, достигнута требуемая цель. Запустите программу и добавьте в наш файл ещё несколько отрезков. О том, что добавление происходит успешно, можно судить по увеличивающемуся объёму файла. Следующая задача: узнать, сколько записей в файле. Делается это очень просто - функцией FileSize(). Когда мы объявляем "файл из байтов" (file of byte), то получаем объём файла в байтах. Сейчас же мы узнаем, сколько записей в файле: var F: file of TLineSegment; {...} AssignFile(F,ExtractFilePath(Application.ExeName)+'lines.dat'); Reset(F); ShowMessage('В файле '+IntToStr(FileSize(F))+' записей'); CloseFile(F); Код очень простой и понятный. Ну и наконец последнее, о чём мне хотелось бы рассказать - это о "перемотке" файла. Я имею ввиду о том, как добраться до записи в середине файла, не перебирая все предыдущие через Read(). Такая задача встречается очень часто и решается она достаточно просто. Процедура Seek() перемещается по файлу на указанный по номеру элемент: Seek(указатель_на_файл,номер_записи); Пример: добавим на форму TListBox и кнопку "Обновить список": procedure TForm1.UpdateButtonClick(Sender: TObject); var F: file of TLineSegment; I,N: Integer; begin AssignFile(F,ExtractFilePath(Application.ExeName)+'lines.dat'); Reset(F); N:=FileSize(F); CloseFile(F); ListBox1.Items.Clear; for I := 1 to N do ListBox1.Items.Add('Запись #'+IntToStr(I)) end; Как видно, эта кнопка добавляет в ListBox список записей в файле. Теперь кнопка "Загрузить" должна загрузить выбранную в списке запись и отобразить длину отрезка: procedure TForm1.LoadButtonClick(Sender: TObject); var F: file of TLineSegment; L: TLineSegment; begin AssignFile(F,ExtractFilePath(Application.ExeName)+'lines.dat'); Reset(F); Seek(F,ListBox1.ItemIndex); Read(F,L); CloseFile(F); MessageDlg('Длина отрезка: '+FloatToStr(GetLength(L)),mtInformation,[mbOk],0); end; Свойство ItemIndex у ListBox определяет номер строки, выбранной в данный момент (строки нумеруются с нуля). После открытия файла мы прыгаем на запись с таким номером, читаем её и затем определяем длину. Просто? Думаю, что да. Работа с типизированными файлами принципиально ничем не отличается от работы с текстовыми. Зато обратите внимание, как легко можно оперировать записями! Теперь вы легко сможете создать простейшую базу данных. Да, и помните, что при работе с типизированными файлами нельзя использовать функции ReadLn() и WriteLn() - они предназначены исключительно для текстовых файлов. Домашнее заданиеДля закрепления пройденного не буду предлагать новой программы - давайте изменим эту. Итак, требуется:
С первого прочтения кажется сложным? На самом деле нет. Если начнёте делать - сообразите, что и как. И не бойтесь потратить на это полчаса, час... Программированию нельзя научить - ему можно только научиться самому. Одно лишь чтение статей ничего не даст - нужно пробовать, чем больше - тем лучше. В конце концов, позади 25 уроков - это достаточно много, пора начинать активно действовать. Желаю успехов! До встречи на следующем уроке! Оценить данный урок, а также оставить свои комментарии Вы можете, перейдя на сайт: страница этого урока на сайте »
Леворекурсивный парсерАвтор: Вадим К Введение
|
Название |
Описание |
Раздел |
Объём |
Ссылки |
NewSpeedButton | TNewSpeedButton - Кнопка, подобная той, что используется в программе QIP Infium. |
182 Кб |
||
Dp7Lib v3.0 | Что нового? Компоненты TdpTrayIcon и TdpMeleeTrayIcon подверглись модернизации, но не большой (исправлены мелкие ошибки). TdpChoiceSpectr переименован в TdpSpectr (так в принципе и должно было быть) и тоже был подвержен модернизации (много лишнего в нём было). Исправлена ошибка в названии компонента TdpColourSpectr (недоставало буквы "u"). Компонент TdpGradSpectr удален из за лёгкости его создания (куча ненужного кода). TdpPipetteShape
теперь потомок TShape. Добавлены компоненты TdpButton (кнопка), TdpBalloon (воздушный шар), TdpBalloonButton (кнопка закрыть для TdpBalloon), TdpDirectoryChange (позволяет ловить директивные изменения, пришёл на смену класса TdpFileChange), TdpNotice (всплывающее сообщение - можно формировать в дизайне), TdpTrayNotice (своё сообщение в Notification area). Совместимость: Delphi 4, 5, 6, 7, 9, 10, 11, 12. |
176 Кб |
||
Easy Text | Easy Text - текстовый редактор с открытым исходным кодом. |
352 Кб |
||
One Channel IRC Client |
Очень простой IRC-клиент, рассчитанный на работу с одним каналом. В архиве находятся исходники клиента и модуль для работы с IRC. Клиент настроен на IRC-канал сайта и готов к использованию. |
26 Кб |
||
Screen Ball | Данный пример показывает самый простой способ создания приложения, которое будет имитировать шарик, бесконечно двигающийся по экрану, ударяясь об его границы. |
8 Кб |
||
Электронное тестирование ЕГЭ | Программа предназначена для моделирования условий итоговой аттестации выпускников 11-х классов по предмету «Информатика и ИКТ» в рамках Единого государственного экзамена с целью адаптации учащихся к постановке заданий будущего тестирования. |
844 Кб |
||
Inscription On Screen | С помощью программы "InscriptionOnScreen" вы сможете создавать надписи или рисунки на экране вашего монитора. Для этого просто запустите программу и начинайте рисовать. После этого нажмите кнопку "Старт" для того, чтобы увидеть, что получилось. Так же имеется возможность сохранить проект в *.ios файл. |
682 Кб |
||
RGB Color | Программа RGB Color предназначена для определения кода цвета с помощью RGB палитры. Также имеются уже стандартный набор цветов и набор дополнительных цветов, которые выбирает и сохраняет пользователь. Для того, чтобы выбрать нужней вам цвет, просто перемещайте указатели на RGB шкалах. |
615 Кб |
||
OC Irc | Простой IRC-клиент, с помощью которого можно находиться в IRC на одном канале. Минимальный набор функций, необходимых для работы в IRC. Клиент изначально настроен на канал сайта www.delphi.int.ru. |
260 Кб |
||
Text Art Utils | Програма для текстово-графических манипуляций: - превращает картинку в цветной текст (с возможностью сохранения в HTML); - рисует заданный текст текстом; - позволяет рисовать текстом. Исходники программы в комплекте. |
1.34 Мб |
||
JpgGIF | Программа для создания из 3-х произвольных фотографий GIF анимации необходимого размера со специфическим переходом между изображениями. |
580 Кб |
||
Карточная игра "50" | РГЗ по дисциплине "Системы искусственного интеллекта". Тема: программирование игр и головоломок. Суть игры: На столе располагаются 24 раскрытые карты: все карты с номерами от 1 до 6 обычной колоды, где туз считается за 1. Масти карт несущественны. Каждый игрок при своём ходе берёт со стола карту и складывает её значение с суммой тех, которые были взяты ранее (таким образом, подсчитывается общая сумма карт, взятых партнёрами, а не отдельные суммы для каждого партнёра). Первый, кто набирает в точности 50 очков, выигрывает. Если игрок, взяв карту, не может не превысить 50 очков, то он проигрывает. Помимо самой игры в архиве находятся её исходники. |
960 Кб |
||
Представлено файлов: 12 |
6.03 Мб |
Ведущий раздела: Bruder
50 причин, почему компьютеры лучше человека
1. Компьютер предназначен для того, чтобы исполнять ваши желания.
2. У компьютера есть регулятор громкости и кнопка выключения звука.
3. Компьютер никогда не обвинит вас в том, что вы его используете.
4. Чтобы компьютер стал вашим, достаточно заплатить деньги один раз, причем никто вас за это не осудит.
5. Вы можете заказать и получить именно ту конфигурацию компьютера, которая вам нужна.
6. Вы можете сказать компьютеру все, что вы о нем думаете, и он не обидится.
7. Компьютер согласен жить на четверти квадратного метра, да и та на столе.
8. Питание компьютера не требует полуторачасовой возни на кухне.
9. Компьютер не требует от вас разнообразить его меню.
10. Компьютер не чавкает.
11. Вам не придется назначать компьютеру встречу в метро, на которую он к тому же опоздает.
12. На компьютеры дают гарантию.
13. Компьютер не суеверен.
14. Компьютер не курит.
15. Если протереть компьютер спиртом, качество его работы не ухудшится.
16. Компьютер не смотрит сериалы.
17. Компьютер не смотрит футбольные матчи.
18. Компьютер занимает телефон только по делу. Причем по вашему.
19. Родственники компьютера, как правило, не вызывают у вас раздражения.
20. Вам не нужно дарить компьютеру подарки на день рожденья.
21. Вам вообще не нужно помнить, когда у компьютера день рожденья.
22. Компьютер не празднует 8 марта.
23. Компьютер не празднует 23 февраля.
24. Если вы все же что-то купили для своего компьютера, оно принесет пользу и вам тоже.
25. У компьютера не бывает носков.
26. Компьютер не пользуется косметикой.
27. У компьютера не растет щетина.
28. Компьютер не потеет.
29. Когда бы вы ни пошли в туалет, вы можете быть уверены, что он не занят компьютером.
30. Компьютер ни при каких обстоятельствах не возьмет вашу зубную щетку.
31. Ночь, проведенная с компьютером, едва ли обернется для вас неприятностями в будущем.
32. У компьютера нет политических взглядов.
33. POST компьютера - это всего лишь проверка работоспособности после включения, а вовсе не отказ выполнять определенные операции по религиозным соображениям.
34. Чтобы прочистить компьютеру мозги, достаточно одного нажатия на кнопку.
35. Компьютер запоминает с первого раза.
36. Но если надо, чтобы компьютер что-то забыл - это делается одной командой.
37. Компьютер не комплексует по поводу размера и формы своих комплектующих.
38. Компьютер не волнует, где вас носило до двух часов ночи.
39. Компьютеру вообще не важно, чем вы занимаетесь, когда вы не с ним.
40. Компьютер не храпит.
41. Вы можете разбудить компьютер в любое время, и он не станет возражать.
42. Компьютер может работать круглые сутки и ни разу не пожалуется, что вы все это время бездельничаете.
43. Компьютерные вирусы не передаются воздушно-капельным путем.
44. Существуют простые тесты, способные рассказать вам все о вашем компьютере.
45. Менять настройки компьютера легко и просто.
46. Причем, как правило, изменение одной не приводит к непредсказуемому изменению остальных.
47. Компьютер не надоедает вам просьбами научить его работать с компьютером.
48. Никто не станет осуждать вас, если вы замените старый компьютер на новый.
49. Компьютер можно заменять по частям.
50. Ни закон, ни мораль не запрещают вырубить компьютер.
Источник: bayanov.net
:))
Присылайте компьютерные анекдоты, рассказы и истории по этой ссылке и они будут опубликованы в ближайших выпусках рассылки.
Архив рассылки: http://subscribe.ru/archive/comp.soft.prog.delphifaq
В избранное | ||