Снова здравствуйте, в процессе работы программы мне необходимо вычислить производную функции, наткнулся на форуме на "Процедурные типы и переменные". Возник вопрос: Для вычисления производной не обязательно писать объёмного кода, есть встроенные решения или я не так понял эту статью?
RussoTuristo
21.02.2011 22:11
Помогите, пожалуйста с кое-чем: Рассматривается определенный физический процесс, с течением времени изменяются 2 величины, в упрощенном виде выглядит так: G=a(y+b) -dy/dt=G/c+d; a,b,c,d известны, G и y - искомые величины. Я с математикой дружу плохо, поэтому хотелось бы услышать совет знающих людей... Необходимо ли вообще вычислять производную или нет? Глупый вопрос, но серьёзно меня тормозит... С первым уравнением всё понятно, а вот втором - dy/dt и даже не знаю как к этому подступиться...
Мои рассуждения: 1)Подставляем первое уравнение во второе и получаем: -dy/dt=a(y+b)/c+d 2)Вычисляем по формуле производную и получаем: y=a/c 3)Подставляем у в первую формулу
Что-то больно легко получается, но правильно ли это? Вообще производная ли это как таковая? Знакомых математиков особо нет, помогите, пожалуйста.
-TarasBer-
21.02.2011 22:54
> 2)Вычисляем по формуле производную и получаем: y=a/c
Как ты это сделал?
RussoTuristo
21.02.2011 23:01
По формуле производной, хотя уже сомнения закрались: -dy/dt=2(y+3)/5+7 -dy/dt=2y/5+(2/5+7) -dy/dt=2y/5 По формуле получаем -2/5 Или выражение -dy/dt=2y/5 не равно -(2y/5)'?
-TarasBer-
22.02.2011 0:03
> -dy/dt=2y/5+(2/5+7) > -dy/dt=2y/5
А чё, 2/5+7 уже считается нулевым?
> -dy/dt=2y/5 > По формуле получаем -2/5
По какой формуле?! Как можно из левой части сократить d/dt, а из правой y?
Ты в каком классе учишься? Если у вас не было курса дифуров, то я тебе это решу, если был, то читай конспекты.
RussoTuristo
22.02.2011 15:56
Школу давно закончил, но с математикой всегда были проблемы... Пытаюсь разобраться, но чёто везде примеры легкие и без этих примудростей с d/dt, окунаюсь в тёмный лес... Если это плёвое дело - помоги, пожалуйста...
TarasBer
22.02.2011 16:29
> Пытаюсь разобраться, но чёто везде примеры легкие и без этих примудростей с d/dt
ДИФУР без этих "прИмудростей"? Такие вообще бывают? Ты примеры из какой главы смотрел? Надо по дифурам смотреть, а не просто по алгебраическим уравнениям.
RussoTuristo
2.05.2011 0:16
Добрый вечер! Снова нужна помощь форума, помогите, пожалуйста: У меня есть форма, на которой расположены StringGrid, куча Editов и еще компоненты. Как можно сделать сохранение введенных значений, чтобы одновременно, в один файл сохранялись StringGrid и Editы? Наткнулся в интернете на чьи-то комментарии, попытался переделать, но что-то у меня ничего путного не выходит...
Procedure TF_main.Save(Sender: TObject); var j:Byte; f:TextFile; begin AssignFile(f, 'Save.txt'); Rewrite(f); for j := 0 to ComponentCount - 1 do if Components[j] is TEdit then WriteLn(f, (Components[j] as TEdit).Text); CloseFile(f); SaveGrid('grid.dat',GridRoom); end;
Procedure TF_main.SaveGrid(Const S: String; Const Grid: TStringGrid); // Сохранение данных таблицы Var ff: TextFile; t: Integer; Begin AssignFile(ff, S); ReWrite(ff); try With Grid Do For t:=1 to RowCount - 1 Do WriteLn(ff, StringReplace(Rows[t].Text, #13#10, #9, [rfReplaceAll])); finally CloseFile(ff); end; End;
procedure TF_main.ClearGrid(Const Grid : TStringGrid); var i : Integer; begin //Очистка строк. Этот шаг необходим из-за "плавающего" бага //компонента TStringGrid. - Строки, удалённые через уменьшение значения //TStringGrid.RowCount на самом деле не всегда удаляются. - TStringGrid //их прячет и при последующем увеличении TStringGrid.RowCount в таблице опять //могут появиться ранее "удалённые" строки. Именно поэтому необходима очистка //перед удалением. for i := Grid.FixedRows to Grid.RowCount - 1 do begin Grid.Rows[i].Clear; end; //Удаление строк. //Здесь +1 - для того, чтобы после фиксированной строки осталась одна нефиксированная //строка - это необходимо для правильного функционирования таблицы. Grid.RowCount := Grid.FixedRows + 1; end;
Procedure TF_main.LoadGrid(Const S: String; Const Grid: TStringGrid); //Загрузка таблицы из файла Var ff: TextFile; St: String; //Индекс очередной строки в которую мы намереваемся записать данные из файла. RowNum : Integer; Begin //Файловая переменная связывается с именем файла. AssignFile(ff, S); //Открытие файла в режиме "только чтение". Reset(ff); try //Очистка таблицы. ClearGrid(Grid); //Индекс самой верхней нефиксированной строки. RowNum := Grid.FixedRows; //Цикл до тех пор пока не достигнут конец файла. While not Eof(ff) Do Begin //Читаем очередную строку из файла. ReadLn(ff, St); With Grid Do Begin //Если требуется, добавляем строку вниз таблицы. if RowNum = RowCount then begin RowCount := RowCount + 1; end; //Распределяем данные по ячейкам, ориентируюясь на знаки табуляции. Rows[RowNum].Text:=StringReplace(St, #9, #13#10, [rfReplaceAll]); End; End; finally //Закрываем файл. CloseFile(ff); end; End;
procedure Tf_main.N4Click(Sender: TObject); begin Save(Edit1); end;
Этот код у меня не получается адаптировать к своей программе, да и сохранение здесь идет в несколько заранее заданных файлов, моя программа, кстати, ниже есть... Может есть другие способы или это кто-то знает как подключить?
IUnknown
2.05.2011 1:33
Проходи в одной процедуре по всем компонентам, и пиши все в один файл:
procedure TForm1.SaveToFile(const FileName: TFileName); var f : TextFile; j, R: Integer; begin AssignFile(f, FileName); Rewrite(f);
for j := 0 to ComponentCount - 1 do if Components[j] is TEdit then with Components[j] as TEdit do begin // Saving Edits WriteLn(f, 'TEdit' + #13#10 + Name + #13#10 + Text); end else if Components[j] is TStringGrid then with Components[j] as TStringGrid do begin // Saving Grigs WriteLn(f, 'TGrid' + #13#10 + Name + #13#10 + IntToStr(RowCount)); for R := 0 to RowCount - 1 do WriteLn(f, StringReplace(Rows[R].Text, #13#10, #9, [rfReplaceAll])); end; CloseFile(f); end;
procedure TForm1.LoadFromFile(const FileName: TFileName); var f : TextFile; i, R: Integer; TheClassName, TheComponentName, s : string; begin AssignFile(f, FileName); Reset(f); while not Eof(f) do begin ReadLn(f, TheClassName); ReadLn(f, TheComponentName); if TheClassName = 'TEdit' then begin ReadLn(f, s); (FindComponent(TheComponentName) as TEdit).Text := s; end else if TheClassName = 'TGrid' then with FindComponent(TheComponentName) as TStringGrid do begin ReadLn(f, R); RowCount := R; for i := 0 to R - 1 do begin ReadLn(f, s); Rows[i].Text := StringReplace(s, #9, #13#10, [rfReplaceAll]); end; end; end;
CloseFile(f); end;
А потом из него и читай. В обратном порядке.
RussoTuristo
2.05.2011 15:10
Спасибо. сохранение и загрузка происходит, только вот программа содержит очень много сложных расчетов с большой точностью и числами, после нескольки расчетов вылетает ошибка о нехватке памяти. Знаю, что переменные можно очищать с помощью dispose(); Но переменных в памяти очень много, можно ли каким-либо образом очистить всю память, занимаемую программой?
И еще, подскажите, пожалуйста, что делаю не так: Есть TChart1, содержащий Series1, есть StringGrid, в который выводятся данные расчета, мне необходимо сделать график зависимости между несколькими величинами из таблицы:
procedure Tf_main.Grafiki; var i:integer; a1,a2:real; begin Series1.Clear; for i:=1 to 5 do begin if (GridResult.Cells[1, i]<>'') and (GridRoom.Cells[5, i]<>'') then begin a1:=StrToFloat(GridRoom.Cells[1, i]); a2:=StrToFloat(GridRoom.Cells[5, i]); end; Series1.AddXY(a1, a2, '', clRed); end; //Edit для проверки значения, которое записывается в a1 Edit16.Text:=FloatToStr(a1); end;
Почему-то график пустует, хотя ко времени вызова StrinGrid уже заполняется и в Edit почему-то пишется значение 0. Это может быть из-за того, что числа в колонках большие: 5 знаков до запятой и 5 после? Или я просто неправильно пишу код процедуры?
IUnknown
2.05.2011 17:16
Цитата
Знаю, что переменные можно очищать с помощью dispose(); Но переменных в памяти очень много, можно ли каким-либо образом очистить всю память, занимаемую программой?
Перед тем, как очищать память, надо знать, как эта память выделяется. Если выделял через GetMem - то освобождать надо через FreeMem, если выделял конструктором какого-то класса - то вызывай его деструктор, и т.д. При правильно структурированной программе таких ошибок возникать не должно. Я не знаю, как там у тебя память выделяется, поэтому советов, "как очищать" давать не буду. Хочешь - показывай программу, посмотрим, что можно поправить...
Цитата
Почему-то график пустует, хотя ко времени вызова StrinGrid уже заполняется
Почему=то мне кажется, что даже если график и заполнится - там может быть полно "мусора". Лучше все-таки сделать так:
procedure Tf_main.Grafiki; var i:integer; a1,a2:real; begin Series1.Clear; for i:=1 to 5 do if (GridResult.Cells[1, i]<>'') and (GridRoom.Cells[5, i]<>'') then begin a1:=StrToFloat(GridRoom.Cells[1, i]); a2:=StrToFloat(GridRoom.Cells[5, i]); Series1.AddXY(a1, a2, '', clRed); // Добавлять в грид только тогда, когда A1 и A2 изменяются end; // Edit16.Text:=FloatToStr(a1); end;
Цитата
Это может быть из-за того, что числа в колонках большие: 5 знаков до запятой и 5 после?
Вряд ли. Добавляться к графику точки все равно должны.
TarasBer
2.05.2011 19:22
> если выделял конструктором какого-то класса - то вызывай его деструктор
Деструктор, который надо вызывать руками... Ни в одном другом языке такого бреда нету - везде либо ГЦ либо РАИИ, либо вообще понятие деструктора отсутствует. Позор ботланда, вечный костыль дельфи...
IUnknown
2.05.2011 19:30
Ну, что есть - то есть... По мне - так лучше я руками соберу там, где это надо, чем GC будет решать за меня, когда и где память освобождать.
Кстати, что в современном Дельфи (2009 и выше) есть возможность написать аналоги С++-ных auto_ptr, тогда будет чуть проще с освобождением памяти... Но это только на новых версиях...
TarasBer
2.05.2011 20:21
> По мне - так лучше я руками соберу там, где это надо, чем GC будет решать за меня, когда и где память освобождать.
А ещё лучше нормальный RAII.
> Кстати, что в современном Дельфи (2009 и выше) есть возможность написать аналоги С++-ных auto_ptr, тогда будет чуть проще с освобождением памяти... Но это только на новых версиях...
Видел я эти аналоги - только не auto_ptr, а shared_ptr. Я и в Д7 умею делать приведение к интерфейсу. Только это, во-первых, обязательно через счётчик ссылок работает (а если мне нужно другое поведение?), а во-вторых, это дико тормозить будет. Проверяли - делали большой массив, загоняли в него 1000 раз по 10 ссылок на один объект, сортировали. В Д7 большую часть времени занимала работа интерфейсов, С++-ники ржали долго. Адский же код с контролируемыми объектами показал себя на нормальном уровне, правда я не знаю, вызовы деструкторов там виртуальные или статические, надеюсь, что компилятор догадался.
IUnknown
2.05.2011 20:30
Цитата
только не auto_ptr, а shared_ptr
Если б я хотел сказать shared_ptr, я бы сказал "shared_ptr". Я говорил про auto_ptr. На дженериках.
RussoTuristo
2.05.2011 20:45
Извините, код громоздкий, но всё же выложу, не понимаю почему не строятся графики, помогите, пожалуйста, может и про память что-то дельное сказать можно?
Код удален
procedure Tf_main.Button1Click(Sender: TObject); - вызывает функции расчета величин Вывод в GridResult осуществляет процедура procedure TzoneMath.ShowOnTable(grid:TStringGrid; room:integer); После неё я использую процедуру Grafiki Т.о. по моей мысли графики должны строится, но почему-то из таблицы считываются нулевые значения...
Добавлено через 3 мин. Извините еще раз, а как сделать, чтобы в сообщении код показывался с полосой прокрутки?
IUnknown
2.05.2011 21:06
Ты б лучше запаковал весь проект и выложил сюда, а то что ж получается, надо еще восстановить форму, чтоб запустить проект? Только EXE-шник удали, не надо его присоединять, меньше будет архив по размеру.
Цитата
а как сделать, чтобы в сообщении код показывался с полосой прокрутки?
На этом форуме нет такого функционала. Еще раз: если код длинный - лучше его архивировать и прикладывать к посту...
RussoTuristo
2.05.2011 21:10
Код программы прикрепил, удалить то длинное сообщение?
IUnknown
2.05.2011 21:24
Цитата
удалить то длинное сообщение?
Это уже вопрос не ко мне...
А в программе у тебя полный бардак, я попробую посмотреть, что можно сделать... У меня она вообще не запустилась - выбросила сообщение "Недостаточно памяти для осуществления операции". Посмотрю, почему.
RussoTuristo
2.05.2011 21:36
У меня такое сообщение вылетает, когда я раза 3-4 подряд вызываю функцию расчет, я не очищаю память вообще нигде, что больше всего ест памяти? Изображения, что строятся и где-то хранятся или множественные расчеты величин с 5 знаками после запятой? Можно в принципе сократить до 2-х знаков...
IUnknown
2.05.2011 21:57
Так... Во-первых, Buffer типа TImage, можно убрать, он не используется. Только жрет место. И много жрет, ты резервируешь для него достаточно большой размер памяти (увеличением Width и Height). Итого: процедура Tf_main.BitBtn1Click
if (GridResult.Cells[1, i]<>'') and (GridRoom.Cells[5, i]<>'') then
никогда не выполнится. Пятый столбец в GridRoom не заполняется вообще. Ставь другое условие...
RussoTuristo
2.05.2011 22:30
Спасибо большое, понял в чем ошибка с графиками, 2 дня с ними мучался и не заметил, что название StringGrida во втором условии перепутал, поправил, только вот теперь он ругается: EConvertError "" is not a valid floating point value. А по поводу памяти можно еще вопросик: bufferы можно убрать, а изображение при многократном вызове расчета каждый раз ведь память занимает? Значит по идее перед каждым новым вызовым его тоже можно почистить?
-TarasBer-
2.05.2011 22:57
Нет. Буферу надо выделять память только один раз. А в обработчике кнопки надо стирать содержимое буфера.
Понимаешь разницу между уничтожением буфера и стиранием его содержимого?
IUnknown
2.05.2011 22:58
Цитата
Значит по идее перед каждым новым вызовым его тоже можно почистить?
Нужно, а не можно. Очистить.
Цитата
поправил, только вот теперь он ругается: EConvertError "" is not a valid floating point value.
Значит, не везде поправил:
if (GridResult.Cells[1, i]<>'') and (GridResult.Cells[5, i]<>'') then begin a1:=StrToFloat(GridResult.Cells[1, i]); // <--- Здесь тоже надо менять ... a2:=StrToFloat(GridResult.Cells[5, i]); // <--- И здесь ... Series1.AddXY(a1, a2, '', clRed); end;
RussoTuristo
2.05.2011 23:09
Спасибо большое, графики отображаются, сейчас займусь чисткой буфера. Удивляюсь как вы умудряетесь замечать всё. Вот что значит мастера своего дела! Еще раз спасибо большое за помощь!
IUnknown
3.05.2011 15:02
RussoTuristo, ты не думал никогда над тем, что чем меньше строк в программе - тем лучше? Вот тебе 2 хинта, как можно безо всяких проблем убрать по десятку строк в каждом случае, без изменения функционала программы.
Первый - касается вот этого ужаса (из процедуры TzoneMath.ShowOnTable):
Цитата
for i:=1 to steps do begin grid.Cells[0,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].tau,-5)); grid.Cells[1,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Fp,-5)); grid.Cells[2,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Gk,-5)); grid.Cells[3,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].y,-5)); grid.Cells[4,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Qpozh,-5)); grid.Cells[5,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Ro2,-5)); grid.Cells[6,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].T2,-5)); grid.Cells[7,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Gm,-5)); end;
Зачем это делать, расскажи? Что, выводить значения можно только вот таким, допотопным, "строка за строкой" способом? А понадобится тебе уменьшить точность, будешь везде "-5" изменять на "-4" что-ли?
Исправление:(Показать/Скрыть)
1) изменяем описание структуры TiParams на вот такое: TiParams = packed record yP, T2P, Ro2P, T21 : Extended; //пересчет
case Boolean of False: (tau : Extended; //текущее время (с) Fp, Gk, y, Qpozh, Ro2, T2, Gm : Extended); True : (Values : Array[0 .. 7] Of Extended); end; , то есть, вариантная запись, все те элементы, которые будут выводиться в Grid, располагаем в конце структуры в нужном порядке, и совмещаем с ними массив Extended-значений (не забудь добавить слово Packed в описание структуры, иначе вылетишь с ошибкой). А там, где было построчное добавление - один простой цикл (работаем с элементами, как с массивом, он ведь физически располагается на тех же местах, что и переменные, и обращение rooms[room].iParams[i-1].Values[0] эквивалентно rooms[room].iParams[i-1].tau, и т.д.):
for i:=1 to steps do begin for j := 0 to 7 do grid.Cells[j, i] := FloatToStr(RoundTo(rooms[room].iParams[i-1].Values[j], -5)); end;
Функционал не изменился, все работает абсолютно так же, как и раньше.
Второй. Зачем дублировать здесь:
Цитата
function TzoneMath.fGm(iter,CurrentRoom:integer; woll:TWoll; forroom:integer):extended;
function TrapezeSt1(a, b: extended; eps: extended): extended; function func(h: extended): extended; begin curroom:=CurrentRoom; Result:=Woll.Proem[0].Width * Rooms[CurrentRoom].iParams[iter].Ro2P * sqrt((2 * TrapezeInt(Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter].yP, woll.Proem[0].Height, 0.01, fdP_1))/Rooms[CurrentRoom].iParams[iter].Ro2P); end; var xx1,xx2,xx3:extended; c:integer; begin result:=0; for c:=1 to round(abs(b-a)/eps) do begin xx1:=func(a+c*eps); xx2:=func(a+c*eps+eps); if xx2>xx1 then begin xx3:=xx1 end else begin xx3:=xx2; end; result:=result+abs(xx2-xx1)*eps+abs(xx3)*eps; end; end;
begin if (Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter_buf].YP)<woll.Proem[0].Height then begin result:= TrapezeSt1(Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter].yP, Woll.Proem[0].Height, 0.01); end else begin result:=0; end; end;
то, что уже сделано в модуле intfunc? У тебя же уже есть там функция, вычисляющая интеграл. Зачем же ты ее тут опять переписываешь заново? Всё проще:
Исправление:(Показать/Скрыть)
function fdP_1(h: extended): extended; // Эта функция у тебя была... begin result:=9.81*(zoneMath.Rooms[curroom].iParams[0].Ro2P-zoneMath.Rooms[curroom].iParams[iter_buf].Ro2P) end;
// После нее добавляешь еще одну, небольшую, функцию: var currWoll : TWoll; iteration : Integer;
function SecondFunc(h: extended): extended; begin with zoneMath.Rooms[curroom] do Result:=CurrWoll.Proem[0].Width * iParams[iteration].Ro2P * sqrt( (2 * TrapezeInt(Height-iParams[iteration].yP, currwoll.Proem[0].Height, 0.01,fdP_1)) / iParams[iteration].Ro2P ); end;
function TzoneMath.fGm(iter,CurrentRoom:integer; woll:TWoll; forroom:integer):extended; begin curroom:=CurrentRoom; currWoll := woll; iteration := iter;
if (Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter_buf].YP)<woll.Proem[0].Height then begin result:= TrapezeInt(Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter].yP, Woll.Proem[0].Height, 0.01, SecondFunc); end else begin result:=0; end; end;
, и она прекрасно сделает то, что положено...
Функционал опять же, остался прежним, а если так - то зачем писАть больше? Кстати, еще один повод перейти на новую версию Дельфи. в 2009 и выше это делается через анонимные функции, избавляя тебя от необходимости добавлять вон те две глобальные переменные.
Да, и еще... Я бы подумал над переносом хотя бы части глобальных переменных в соответствующие классы (в секцию private). Скажем, curroom. Внести ее в TzoneMath, например. Так же, как и iter_buf. Подумай над этим... И "разгрузи" код, путем использования With. Его ж читать невозможно...
RussoTuristo
4.05.2011 17:32
Дельные замечания, поработаю над исправлением, в будущем пригодится.... И вопросик: Подскажите, пожалуйста, использую для сохранения и загрузки выше указанный код, но после загрузки при попытке Расчета вылетает ошибка: "" is not a valid integer value С чем это может быть связано? Визуально пустых строчек и эдитов нигде нет, ошибка отправляет в строчку:
procedure Tf_main.Button1Click(Sender: TObject);//Функция расчета var i:integer; begin F_main.BitBtn1Click(Sender); widthXX:=StrToFloat(edit15.text); widthYX:=StrToFloat(edit13.text);
Без сохранения/загрузки всё работает нормально, что-то не так считывается?
TarasBer
4.05.2011 18:01
edit15... Хм, что бы это могло быть... Наверное, это пятнадцатый компонент типа TEdit, добавленный на форму, и в нём нет текста.
А потому что, блин, нельзя использовать компоненты с именами, даваемыми по умолчанию.
IUnknown
4.05.2011 18:05
То, что Дельфи останавливается на строке с edit15.text - ни разу не значит, что ошибка именно в нем. Может быть и раньше по ходу программы.
Цитата
что-то не так считывается?
Лишние ячейки грида заполняются пробелом. При проверке
Цитата
if (GridRoom.Cells[2, i]<>'') and (GridRoom.Cells[3, i]<>'') then
Приводит к краху. Ибо пробел - это не число, естественно. Два исправления: во-первых (процедура Tf_main.BitBtn1Click):
if (Trim(GridRoom.Cells[2, i])<>'') and (Trim(GridRoom.Cells[3, i])<>'') then
, тогда пробел не будет пропущен, и во-вторых, при чтении из файла:
if TheClassName = 'TGrid' then with FindComponent(TheComponentName) as TStringGrid do begin ReadLn(f, R); RowCount := R; for i := 0 to R - 1 do begin ReadLn(f, s); if s <> '' then // <--- Вот эту строку добавь, чтоб лишнюю работу не делать Rows[i].Text := StringReplace(s, #9, #13#10, [rfReplaceAll]); end; end;
RussoTuristo
4.05.2011 18:11
Спасибо, исправил, теперь сохраняется и загружается.
RussoTuristo
4.05.2011 19:46
Пишу функцию, чтобы в поля нельзя было вводить недопустимые значения, решил по уму сделать, чтобы сразу всё обрабатывалось, но с синтаксисом проблемки:
function Tf_main.Vvod_dannih:boolean; var i,j:integer; begin for i := 0 to ComponentCount - 1 do if Components[i] is TEdit then with Components[i] as TEdit do begin for j := 0 to Length(Components[i].text) do//Здесь ошибочка с обращением к свойству text if (Components[i].Text[j] not in['0'..'9', ',']) then //not in тоже не пашет, хотя вроде когда-то писал так begin ShowMessage('В поле введено неправильное значение'); Result:=false; Break; end else Result:=true; end; end;
Как правильно можно обращаться к текстам всех Editов? Подскажите, пожалуйста.
TarasBer
4.05.2011 19:59
Нафига ты используешь with, если внутри него всё равно обращаешься через Components[i]? Внимательнее пиши же!
function Tf_main.Vvod_dannih:boolean; var i,j:integer; begin for i := 0 to ComponentCount - 1 do if Components[i] is TEdit then with TEdit(Components[i]) do begin // можно без as, так как проверку ты уже сделал строчку назад for j := 1 to Length(text) do// убрать нафиг Components[i]. и индексировать строки надо от 1 if not (Text[j] in['0'..'9', ',']) then //not in тоже не пашет, хотя вроде когда-то писал так begin ShowMessage('В поле введено неправильное значение'); Result:=false; Break; end else Result:=true; end; end;
IUnknown
4.05.2011 20:02
function Tf_main.Vvod_dannih : boolean; var i, j: integer; begin Result := False; for i := 0 to ComponentCount - 1 do if Components[ i ] is TEdit then with Components[ i ] as TEdit do begin for j := 0 to Length({(Components[ i ] as TEdit).}Text) do if not ({(Components[ i ] as TEdit).}Text[j] {not} in['0'..'9', ',']) then begin ShowMessage('В поле введено неправильное значение'); Exit; end; end; Result := True; end;
Почему закомментировал? Потому что у тебя With работает, и просто Text эквивалентно (Components[i] as TEdit).Text. А not надо вынести в начало, он относится к результату выражения (text[j] in ['0'..'9', ',']). Кстати, пользовался бы ты не запятой, а переменной DecimalSeparator - было бы лучше...
RussoTuristo
4.05.2011 20:04
Спасибо, DecimalSeparator видел в интернете, но честно говоря не знал, что это значит. А если использовать такой синтаксис, то установить фокус уже никак не получится в этот Edit, так как работа идет уже непосредственно с текстом? IUnknown, С днём Рождения, кстати!
IUnknown
4.05.2011 20:25
С чего бы? Ты хочешь оставить фокус в том Edit-е, который некорректно заполнен, что-ли? Вот так попробуй:
function Tf_main.Vvod_dannih : boolean; var i, j: integer; Edit : TEdit; begin Result := False; for i := 0 to ComponentCount - 1 do if Components[i] is TEdit then begin Edit := Components[i] as TEdit; for j := 1 to Length(Edit.Text) do if not (Edit.Text[j] in['0'..'9', ',']) then begin Edit.SelStart := 1; Edit.SelLength := Length(Edit.Text); Edit.SetFocus; ShowMessage('В поле введено неправильное значение'); Exit; end; end; Result := True; end;
У тебя было 2 трудноуловимых ошибки, кстати... Посмотри внимательно, и поймешь, какие. И в чем опасность.
RussoTuristo
4.05.2011 20:31
Первая понял в чем - я не все Editы просматривал, нумерация-то с нуля идет, а вот вторая связана с длиной текста в Editе походу, но что-то сразу не доходит, в чем её серьёзность...
IUnknown
4.05.2011 20:55
Не совсем. Первая - это то, что у тебя есть другое свойство Text в контексте этой процедуры. То есть, вставь строку:
Result := False; ShowMessage(Text); // <--- Вот эту, еще до того, как начинаешь проверять компоненты for i := 0 to ComponentCount - 1 do
, и программа откомпилируется нормально. Какое из свойств будет взято после того, как отработает With - то, что доступно и без With, или то, что относится именно к Edit-ам - я в этом не могу быть уверен. Поэтому я от With избавился, и теперь обращение Edit.Text - это 100% обращение к содержимому компонента типа TEdit.
Вторая ошибка: индексация в строке начинается с 1, а не с 0. Читать ты, конечно, нулевой символ можешь (хотя я бы и это запретил, меньше ошибок будет, вот именно в этом случае ты бы тут же получил "по рукам", и понял бы, в чем дело. Почему этого не сделают никак - не понимаю), а вот попробовать записать в него что-то - уже не получится. Тут же получишь сообщение, что "0-ой символ недоступен, используйте Length/SetLength". Так что и проверять символы в строке надо с первого, а не с нулевого.
TarasBer
4.05.2011 20:56
Я бы делал проверку на корректность содержимого не перебором символов, а через Val. Мне кажется, логичнее проверять, можно ли строку сделать числом, при помощи функции, делающей строку числом.
> а вот вторая связана с длиной текста в Editе походу, но что-то сразу не доходит, в чем её серьёзность...
А ты прочитай мой пост (82), который IUnknown перебил с ошибкой в индексации строки.
IUnknown
4.05.2011 21:02
Цитата
мой пост (82), который IUnknown перебил с ошибкой в индексации строки.
Не льсти себе, я твой пост не перебивал. Я даже не видел его. Я поправил исходный текст из поста №81. Как выяснилось - не всё увидел. Говорю же, стал бы компилятор материться - обратил бы внимание на то, что там происходит. А так - оно осталось без внимания...
Еще один камень в огород Дельфостроителей (про автодеструкторы ты уже говорил)
RussoTuristo
8.05.2011 16:00
Добрый день! Подскажите, пожалуйста, а можно ли в текстовый файл вместе с таблицами и Эдитами вывести графики из TChart и рисунок? Есть такая необходимость, про THcart что-то нашел в интернете, попытался наваять, но вместо графиков выводятся названия TChartов, а изображение вообще вызывает сомнения -можно ли ехо сохранить в текстовый файл или только в bmp/jpeg?
procedure Tf_main.N7Click(Sender: TObject); var f : TextFile; j, R: Integer; BM: TBitmap; begin if SaveDialog1.Execute then begin AssignFile(f, SaveDialog1.FileName); Rewrite(f);
for j := 0 to ComponentCount - 1 do if Components[j] is TEdit then with Components[j] as TEdit do begin // Saving Edits WriteLn(f, 'TEdit' + #13#10 + Name + #13#10 + Text); end else if Components[j] is TStringGrid then with Components[j] as TStringGrid do begin // Saving Grigs WriteLn(f, 'TGrid' + #13#10 + Name + #13#10 + IntToStr(RowCount)); for R := 0 to RowCount - 1 do WriteLn(f, StringReplace(Rows[R].Text, #13#10, #9, [rfReplaceAll])); end else if Components[j] is TChart then with Components[j] as TChart do begin // Saving Grigs BM:=TBitmap.Create; try BM.PixelFormat:=pf24bit; BM.Width:=Chart1.ClientWidth; BM.Height:=Chart1.ClientHeight; Chart1.PrintPartialCanvas(bm.canvas, Chart1.ClientRect); BM.SaveToFile('f'); finally BM.Free; end; end; CloseFile(f); end; end;
-TarasBer-
8.05.2011 16:12
В тестовый? Нет. На то он и текстовый. Можно в вордовый. Можно сохранить картинку в файл, а потом сгенерировать html, в который включена эта картинка.
Только лучше не в bmp сохранять, а в png. Правда, как это делать - я не знаю, но вроде есть какое-то стандартное решение.
IUnknown
8.05.2011 16:44
Цитата
а можно ли в текстовый файл вместе с таблицами и Эдитами вывести графики из TChart и рисунок?
Выше уже сказали, что в текстовый - нет. А просто графику - можно. Либо TChart.SaveToMetafile, либо TChart.SaveToMetafileEnh (про SaveToBitmapFile я не говорю, кому нужен BMP-файл?)
RussoTuristo
8.05.2011 19:49
А как сохранить Chart и Image в вордовский фал, может кто-нибудь подсказать? А-то что-то ничего в интернете нашарить не могу похожего...
IUnknown
8.05.2011 20:22
У приложения Word есть коллекция InlineShapes, к которой и надо добавлять изображение, чтобы оно добавилось в документ. Поскольку и метод AddPicture и метод AddOLEObject этой коллекции требуют имя файла (т.е., файл с изображением уже должен быть на диске), то надо записать картинку во временный файл, оттуда - добавить к документу, а потом - удалить:
fn := ExtractFilePath(Application.ExeName) + 'tmp.bmp'; // Тут будет временная картинка Chart1.SaveToBitmapFile(fn);
WordApp := CreateOleObject('Word.Application'); // А вот с эти приложением работаем WordApp.Visible := True; // Это можно отключить, я включил, чтоб наблюдать за происходящим WordApp.Documents.Add; // Новый документ
// Добавляем картинку из файла WordApp.Selection.InlineShapes.AddOLEObject(ClassType:='Paint.Picture', FileName:=fn, LinkToFile:=False, DisplayAsIcon:=False);
DeleteFile(fn); // Все, картинка больше не нужна, удаляем
Потом сохранить DOC файл, и все... Уж этих примеров в сети - море.
IUnknown
8.05.2011 20:49
Хотя... Что тебе надо делать с этим изображением? Сохранить, а потом восстановить? Или просто для просмотре? Если сохранение/восстановление - то можно изображение закодировать в строку (EncodeBase64), а потом, когда нужно - раскодировать назад: DecodeBase64. На форуме embarcadero было решение подобной задачи.
RussoTuristo
10.05.2011 10:22
Мне надо вывести отчет о задымленности в файл, то есть исходные данные, рассчитанные данные, желательно рисунок(не обязательно, чувствую с ним много проблем будет) и графики зависимостей(TChart).... Кстати, в связи с этим возникает вопрос, а график TChart наверняка выводится по похожим с Image алгоритмам?(То естьTChart нельзя вывести в один файл с Эдитами и таблицами, используя, например не word, а какой-либо более легкий метод вывода)
Кстати, интересно было, что означает эта конструкция в Дельфи? (хахаха, это спецкостыль для OLE)
> WordApp := CreateOleObject('Word.Application');
Ты забыл дописать его удаление, а ведь у них, в отличие от неудалённых указателей, последствия похуже - лишний процесс повиснет в памяти.
И ещё, почему у меня не получалось сделать так, чтобы одновременно работала подобная программа и я мог что-то набирать в другом документе (при выборе другого документа моя программа тоже переключалась на него)?
IUnknown
10.05.2011 15:16
Цитата
Ты забыл дописать его удаление
С чего бы? Я ж ясно написал:
Цитата
Потом сохранить DOC файл
Или удалить надо было до сохранения? Или надо было написать полный код, чтоб ТС только скопировал и добавил к себе?
Цитата
почему у меня не получалось сделать так, чтобы одновременно работала подобная программа и я мог что-то набирать в другом документе
Потому что я использовал свойства, которые относятся к текущему (активному) документу/приложению. Если надо одновременно работать вручную - с одним документом, а автоматически - с другим, то нужно переписывать код по-другому. Обычно такой задачи не стоит.
Цитата
(хахаха, это спецкостыль для OLE)
Это - костыль? Ты еще работу с OLE в Билдере не видел. Вот там - костыль, так костыль... А в Дельфи - практически повторен стиль VBA.
Цитата(RussoTuristo)
используя, например не word, а какой-либо более легкий метод вывода
Пример более легкого метода, чем Word, можно привести? В Word картинка добавляется одной строкой, как видишь.
TarasBer
10.05.2011 15:22
> Или удалить надо было до сохранения? Или надо было написать полный код, чтоб ТС только скопировал и добавил к себе?
Надо было написать "потом сохранить и обязательно удалить не забудь".
> Если надо одновременно работать вручную - с одним документом, а автоматически - с другим, то нужно переписывать код по-другому.
А насколько именно по-другому?
> Ты еще работу с OLE в Билдере не видел.
Да, не видел...
IUnknown
10.05.2011 16:00
Цитата
А насколько именно по-другому?
Ну, как-то вот так (набираю прямо здесь, так что где-то могу и накосячить) :
// во-первых, создаем OLE-объект только тогда, когда он еще не создан, // иначе подключаемся уже к работающему: try WordApp := GetActiveOleObject('Word.Application'); except WordApp := CreateOleObject('Word.Application'); end;
// во-вторых, при создании нового документа надо получить на него ссылку: new_doc := wordapp.Documents.Add; // var new_doc : variant // и потом добавлять объект именно к новому документу new_doc.{selection.}InlineShapes.AddOLEObject(...)
вот насчет необходимости Selection я не уверен, может быть оно там и не надо.