Помощь - Поиск - Пользователи - Календарь
Полная версия: Графический редактор в Delphi
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Делфи
Страницы: 1, 2, 3
RussoTuristo
Снова здравствуйте, в процессе работы программы мне необходимо вычислить производную функции, наткнулся на форуме на "Процедурные типы и переменные". Возник вопрос: Для вычисления производной не обязательно писать объёмного кода, есть встроенные решения или я не так понял эту статью?
RussoTuristo
Помогите, пожалуйста с кое-чем:
Рассматривается определенный физический процесс, с течением времени изменяются 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-
> 2)Вычисляем по формуле производную и получаем: y=a/c

Как ты это сделал?
RussoTuristo
По формуле производной, хотя уже сомнения закрались:
-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-
> -dy/dt=2y/5+(2/5+7)
> -dy/dt=2y/5

А чё, 2/5+7 уже считается нулевым?

> -dy/dt=2y/5
> По формуле получаем -2/5

По какой формуле?!
Как можно из левой части сократить d/dt, а из правой y?

Ты в каком классе учишься? Если у вас не было курса дифуров, то я тебе это решу, если был, то читай конспекты.
RussoTuristo
Школу давно закончил, но с математикой всегда были проблемы...
Пытаюсь разобраться, но чёто везде примеры легкие и без этих примудростей с d/dt, окунаюсь в тёмный лес...
Если это плёвое дело - помоги, пожалуйста...
TarasBer
> Пытаюсь разобраться, но чёто везде примеры легкие и без этих примудростей с d/dt

ДИФУР без этих "прИмудростей"? Такие вообще бывают?
Ты примеры из какой главы смотрел? Надо по дифурам смотреть, а не просто по алгебраическим уравнениям.
RussoTuristo
Добрый вечер! Снова нужна помощь форума, помогите, пожалуйста:
У меня есть форма, на которой расположены 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
Проходи в одной процедуре по всем компонентам, и пиши все в один файл:
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
Спасибо. сохранение и загрузка происходит, только вот программа содержит очень много сложных расчетов с большой точностью и числами, после нескольки расчетов вылетает ошибка о нехватке памяти.
Знаю, что переменные можно очищать с помощью 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
Цитата
Знаю, что переменные можно очищать с помощью 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
> если выделял конструктором какого-то класса - то вызывай его деструктор

Деструктор, который надо вызывать руками... Ни в одном другом языке такого бреда нету - везде либо ГЦ либо РАИИ, либо вообще понятие деструктора отсутствует.
Позор ботланда, вечный костыль дельфи...
IUnknown
Ну, что есть - то есть... По мне - так лучше я руками соберу там, где это надо, чем GC будет решать за меня, когда и где память освобождать.

Кстати, что в современном Дельфи (2009 и выше) есть возможность написать аналоги С++-ных auto_ptr, тогда будет чуть проще с освобождением памяти... Но это только на новых версиях...
TarasBer
> По мне - так лучше я руками соберу там, где это надо, чем GC будет решать за меня, когда и где память освобождать.

А ещё лучше нормальный RAII.

> Кстати, что в современном Дельфи (2009 и выше) есть возможность написать аналоги С++-ных auto_ptr, тогда будет чуть проще с освобождением памяти... Но это только на новых версиях...

Видел я эти аналоги - только не auto_ptr, а shared_ptr. Я и в Д7 умею делать приведение к интерфейсу. Только это, во-первых, обязательно через счётчик ссылок работает (а если мне нужно другое поведение?), а во-вторых, это дико тормозить будет. Проверяли - делали большой массив, загоняли в него 1000 раз по 10 ссылок на один объект, сортировали. В Д7 большую часть времени занимала работа интерфейсов, С++-ники ржали долго. Адский же код с контролируемыми объектами показал себя на нормальном уровне, правда я не знаю, вызовы деструкторов там виртуальные или статические, надеюсь, что компилятор догадался.
IUnknown
Цитата
только не auto_ptr, а shared_ptr
Если б я хотел сказать shared_ptr, я бы сказал "shared_ptr". Я говорил про auto_ptr. На дженериках.
RussoTuristo
Извините, код громоздкий, но всё же выложу, не понимаю почему не строятся графики, помогите, пожалуйста, может и про память что-то дельное сказать можно?
Код удален

procedure Tf_main.Button1Click(Sender: TObject); - вызывает функции расчета величин
Вывод в GridResult осуществляет процедура
procedure TzoneMath.ShowOnTable(grid:TStringGrid; room:integer);
После неё я использую процедуру Grafiki
Т.о. по моей мысли графики должны строится, но почему-то из таблицы считываются нулевые значения...

Добавлено через 3 мин.
Извините еще раз, а как сделать, чтобы в сообщении код показывался с полосой прокрутки?
IUnknown
Ты б лучше запаковал весь проект и выложил сюда, а то что ж получается, надо еще восстановить форму, чтоб запустить проект? Только EXE-шник удали, не надо его присоединять, меньше будет архив по размеру.

Цитата
а как сделать, чтобы в сообщении код показывался с полосой прокрутки?
На этом форуме нет такого функционала. Еще раз: если код длинный - лучше его архивировать и прикладывать к посту...
RussoTuristo
Код программы прикрепил, удалить то длинное сообщение?
IUnknown
Цитата
удалить то длинное сообщение?
Это уже вопрос не ко мне...

А в программе у тебя полный бардак, я попробую посмотреть, что можно сделать... У меня она вообще не запустилась - выбросила сообщение "Недостаточно памяти для осуществления операции". Посмотрю, почему.
RussoTuristo
У меня такое сообщение вылетает, когда я раза 3-4 подряд вызываю функцию расчет, я не очищаю память вообще нигде, что больше всего ест памяти? Изображения, что строятся и где-то хранятся или множественные расчеты величин с 5 знаками после запятой? Можно в принципе сократить до 2-х знаков...
IUnknown
Так... Во-первых, Buffer типа TImage, можно убрать, он не используется. Только жрет место. И много жрет, ты резервируешь для него достаточно большой размер памяти (увеличением Width и Height). Итого: процедура Tf_main.BitBtn1Click

// ...

Img:=TBitmap.Create;
// buffer:=TBitmap.Create;
img.Width:=l+400;
// buffer.Width:=l+400;
img.Height:=h+400;
// buffer.Height:=h+400;

// ...


А что касается Chart-а - так программа совершенно права. Смотри:
Нажмите для просмотра прикрепленного файла
, то есть, условие:
Цитата
if (GridResult.Cells[1, i]<>'') and (GridRoom.Cells[5, i]<>'') then
никогда не выполнится. Пятый столбец в GridRoom не заполняется вообще. Ставь другое условие...
RussoTuristo
Спасибо большое, понял в чем ошибка с графиками, 2 дня с ними мучался и не заметил, что название StringGrida во втором условии перепутал, поправил, только вот теперь он ругается: EConvertError "" is not a valid floating point value.
А по поводу памяти можно еще вопросик: bufferы можно убрать, а изображение при многократном вызове расчета каждый раз ведь память занимает? Значит по идее перед каждым новым вызовым его тоже можно почистить?
-TarasBer-
Нет. Буферу надо выделять память только один раз.
А в обработчике кнопки надо стирать содержимое буфера.

Понимаешь разницу между уничтожением буфера и стиранием его содержимого?
IUnknown
Цитата
Значит по идее перед каждым новым вызовым его тоже можно почистить?
Нужно, а не можно. Очистить.

Цитата
поправил, только вот теперь он ругается: 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
Спасибо большое, графики отображаются, сейчас займусь чисткой буфера.
Удивляюсь как вы умудряетесь замечать всё. Вот что значит мастера своего дела! Еще раз спасибо большое за помощь!
IUnknown
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" что-ли?

Исправление: (Показать/Скрыть)

Функционал не изменился, все работает абсолютно так же, как и раньше.

Второй. Зачем дублировать здесь:
Цитата
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? У тебя же уже есть там функция, вычисляющая интеграл. Зачем же ты ее тут опять переписываешь заново? Всё проще:

Исправление: (Показать/Скрыть)
Функционал опять же, остался прежним, а если так - то зачем писАть больше? Кстати, еще один повод перейти на новую версию Дельфи. в 2009 и выше это делается через анонимные функции, избавляя тебя от необходимости добавлять вон те две глобальные переменные.

Да, и еще... Я бы подумал над переносом хотя бы части глобальных переменных в соответствующие классы (в секцию private). Скажем, curroom. Внести ее в TzoneMath, например. Так же, как и iter_buf. Подумай над этим... И "разгрузи" код, путем использования With. Его ж читать невозможно...
RussoTuristo
Дельные замечания, поработаю над исправлением, в будущем пригодится....
И вопросик:
Подскажите, пожалуйста, использую для сохранения и загрузки выше указанный код, но после загрузки при попытке Расчета вылетает ошибка: "" 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
edit15...
Хм, что бы это могло быть...
Наверное, это пятнадцатый компонент типа TEdit, добавленный на форму, и в нём нет текста.

А потому что, блин, нельзя использовать компоненты с именами, даваемыми по умолчанию.
IUnknown
То, что Дельфи останавливается на строке с edit15.text - ни разу не значит, что ошибка именно в нем. Может быть и раньше по ходу программы.
Цитата
что-то не так считывается?
Лишние ячейки грида заполняются пробелом. При проверке
Цитата
if (GridRoom.Cells[2, i]<>'') and (GridRoom.Cells[3, i]<>'') then
заходит внутрь условия, и попытка
Цитата
    a1:=10*StrToInt(GridRoom.Cells[2, i]);
a2:=10*StrToInt(GridRoom.Cells[3, i]);
Приводит к краху. Ибо пробел - это не число, естественно. Два исправления: во-первых (процедура 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
Спасибо, исправил, теперь сохраняется и загружается.
RussoTuristo
Пишу функцию, чтобы в поля нельзя было вводить недопустимые значения, решил по уму сделать, чтобы сразу всё обрабатывалось, но с синтаксисом проблемки:
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
Нафига ты используешь 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
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
Спасибо, DecimalSeparator видел в интернете, но честно говоря не знал, что это значит.
А если использовать такой синтаксис, то установить фокус уже никак не получится в этот Edit, так как работа идет уже непосредственно с текстом?
IUnknown, С днём Рождения, кстати!
IUnknown
С чего бы? Ты хочешь оставить фокус в том 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
Первая понял в чем - я не все Editы просматривал, нумерация-то с нуля идет, а вот вторая связана с длиной текста в Editе походу, но что-то сразу не доходит, в чем её серьёзность...
IUnknown
Не совсем. Первая - это то, что у тебя есть другое свойство 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
Я бы делал проверку на корректность содержимого не перебором символов, а через Val. Мне кажется, логичнее проверять, можно ли строку сделать числом, при помощи функции, делающей строку числом.

> а вот вторая связана с длиной текста в Editе походу, но что-то сразу не доходит, в чем её серьёзность...

А ты прочитай мой пост (82), который IUnknown перебил с ошибкой в индексации строки.
IUnknown
Цитата
мой пост (82), который IUnknown перебил с ошибкой в индексации строки.
Не льсти себе, я твой пост не перебивал. Я даже не видел его. Я поправил исходный текст из поста №81. Как выяснилось - не всё увидел. Говорю же, стал бы компилятор материться - обратил бы внимание на то, что там происходит. А так - оно осталось без внимания...

Еще один камень в огород Дельфостроителей (про автодеструкторы ты уже говорил)
RussoTuristo
Добрый день! Подскажите, пожалуйста, а можно ли в текстовый файл вместе с таблицами и Эдитами вывести графики из 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-
В тестовый? Нет. На то он и текстовый.
Можно в вордовый.
Можно сохранить картинку в файл, а потом сгенерировать html, в который включена эта картинка.

Только лучше не в bmp сохранять, а в png. Правда, как это делать - я не знаю, но вроде есть какое-то стандартное решение.
IUnknown
Цитата
а можно ли в текстовый файл вместе с таблицами и Эдитами вывести графики из TChart и рисунок?
Выше уже сказали, что в текстовый - нет. А просто графику - можно. Либо TChart.SaveToMetafile, либо TChart.SaveToMetafileEnh (про SaveToBitmapFile я не говорю, кому нужен BMP-файл?)
RussoTuristo
А как сохранить Chart и Image в вордовский фал, может кто-нибудь подсказать? А-то что-то ничего в интернете нашарить не могу похожего...
IUnknown
У приложения 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
Хотя... Что тебе надо делать с этим изображением? Сохранить, а потом восстановить? Или просто для просмотре? Если сохранение/восстановление - то можно изображение закодировать в строку (EncodeBase64), а потом, когда нужно - раскодировать назад: DecodeBase64. На форуме embarcadero было решение подобной задачи.
RussoTuristo
Мне надо вывести отчет о задымленности в файл, то есть исходные данные, рассчитанные данные, желательно рисунок(не обязательно, чувствую с ним много проблем будет) и графики зависимостей(TChart)....
Кстати, в связи с этим возникает вопрос, а график TChart наверняка выводится по похожим с Image алгоритмам?(То естьTChart нельзя вывести в один файл с Эдитами и таблицами, используя, например не word, а какой-либо более легкий метод вывода)
TarasBer
> AddOLEObject(ClassType:='Paint.Picture',
FileName:=fn, LinkToFile:=False, DisplayAsIcon:=False);

Кстати, интересно было, что означает эта конструкция в Дельфи?
(хахаха, это спецкостыль для OLE)

> WordApp := CreateOleObject('Word.Application');

Ты забыл дописать его удаление, а ведь у них, в отличие от неудалённых указателей, последствия похуже - лишний процесс повиснет в памяти.

И ещё, почему у меня не получалось сделать так, чтобы одновременно работала подобная программа и я мог что-то набирать в другом документе (при выборе другого документа моя программа тоже переключалась на него)?
IUnknown
Цитата
Ты забыл дописать его удаление
С чего бы? Я ж ясно написал:
Цитата
Потом сохранить DOC файл
Или удалить надо было до сохранения? Или надо было написать полный код, чтоб ТС только скопировал и добавил к себе?

Цитата
почему у меня не получалось сделать так, чтобы одновременно работала подобная программа и я мог что-то набирать в другом документе
Потому что я использовал свойства, которые относятся к текущему (активному) документу/приложению. Если надо одновременно работать вручную - с одним документом, а автоматически - с другим, то нужно переписывать код по-другому. Обычно такой задачи не стоит.

Цитата
(хахаха, это спецкостыль для OLE)
Это - костыль? Ты еще работу с OLE в Билдере не видел. Вот там - костыль, так костыль... А в Дельфи - практически повторен стиль VBA.

Цитата(RussoTuristo)
используя, например не word, а какой-либо более легкий метод вывода
Пример более легкого метода, чем Word, можно привести? В Word картинка добавляется одной строкой, как видишь.
TarasBer
> Или удалить надо было до сохранения? Или надо было написать полный код, чтоб ТС только скопировал и добавил к себе?

Надо было написать "потом сохранить и обязательно удалить не забудь".

> Если надо одновременно работать вручную - с одним документом, а автоматически - с другим, то нужно переписывать код по-другому.

А насколько именно по-другому?

> Ты еще работу с OLE в Билдере не видел.

Да, не видел...
IUnknown
Цитата
А насколько именно по-другому?
Ну, как-то вот так (набираю прямо здесь, так что где-то могу и накосячить) :

// во-первых, создаем 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 я не уверен, может быть оно там и не надо.

Цитата
Да, не видел...
Посмотри:
С++ Builder6 & Excel
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.