Добрый день! Необходимо написать графический редактор следующего вида: Окно разбито на 2 части, в левой вводятся параметры фигуры, в правой она отрисовывается. Например: для начала задан прямоугольник высотой 50 и шириной 100. Указываем высоту - 25, на ней ширина 50 и фигура должна преобразоваться, приняв форму песочных часов и далее в этом духе. Надеюсь нормально объяснил...
Программу еще не начал, код писать не прошу, необходима консультация в том, какие элементы выбрать для разработки, TPaintBox или TImage и т.д. и как лучше всё это отрисовывать, может кто может дать совет?
> Я так понимаю, речь идёт об этой строке, но изображение всё равно не сжимается, а часть его остается где-то за пределами....
Да, об этой. Она именно выводит то, что было в Img на форму. То, что там что-то за пределами - ну так что было в Img, то и вывелось. Можешь написать для контроля Img.SvaeToFile() и сравнить.
> При нажатии кнопки первым делом удаляем старое, и строим новое.
Что-то я не увидел, чтобы ты создавал новое при нажатии кнопки. У тебя, видимо полное непонимание происходящего.
TBitmap.Create - это создание изображения для работы, если этого не сделать, то с ним ничего делать нельзя. Эта процедура соответствует доставанию нового листа бумаги из стола. TBitmap.Free - это не стереть изображение ластиком с листа! Это выкинуть лист в мусорку, потому что тебе он больше не нужен. После Free делать с изображением ничего нельзя, поэтому его лучше пропиши в OnDestroy.
Всякие там рисования - это не создание нового листа, это рисование на текущем. А для того, чтобы стереть изображение ластиком, делай так:
with Img.Canvas do begin Brush.Style := bsSolid; // стиль заливки - заливать по полной Brush.Color := clWhite; // цвет заливки - белый Pen.Style := psClear; // линии не рисовать Rectangle(0, 0, Width, Height); // нарисовать прямоугольник на всю область end;
А потом, перед рисованием, не забудь обратно написать Pen.Style := psSolid; (а потом он линии рисовать не будет).
Вроде доработал все, изображение строится, сжимается/растягивается, но как-то иногда очень криво, что-то не прорисовывается, когда изображение большое - иногда целые линии не видны. Увеличил размер кисти, стало лучше, даже нормально, но это, наверное, не правильный способ.... Можно как-то по-другому это реализовать - улучшить качество?
И еще вопрос, добавил панель для расчетов, поместил Editы, туда ввожу значения, но при расчете вылетает ошибка: "EConverError with message "" is not a vali floating point value". Незаполненных Editов нету, странно... Хотя типы должны совпадать:
Qn, Vlin,r:real; tau:integer;
Procedure Init; begin Qn:=StrToFloat(Edit3.text); Vlin:=StrToFloat(Edit4.Text); tau:=StrToInt(Edit7.Text); r:=Vlin*tau; Edit8.text:=FloatToStr®; end;
> о при расчете вылетает ошибка: "EConverError with message "" is not a vali floating point value".
Это не значит, что он не заполнен. Это значит, что его содержимое - не число. Кстати, в качестве разделителя нужна именно запятая (кажется).
> что-то не прорисовывается, когда изображение большое - иногда целые линии не видны
Функцию сжатия писал Микрософт. Видать, хреново написал. У меня тоже при сжатии вместо оттенков серого просто пропадают линии, даже если принудительно задать режим сжатия halftone .
> Можно как-то по-другому это реализовать - улучшить качество?
Да. Изначально задать размер буфера, совпадающий с размером выводимого участко и при рисовании в буфер использовать только относительные координаты, никаких точных чисел. То есть делать так: w := Img.Width; h := Img.Height; ... LineTo(round(w * 0.1), round(h * 0.34));
(для первой координаты через w, для второй через h).
В поля text у Edit3, Edit4 и Edit7 введены значения 1380, 10 и 10 соответственно без запятых и без пробелов, поле для вывода - пустое. Вообще когда добавил 2-ю панель она как не родная))) С первой панели из такого же Edita считывается, а эта панель вообще мёртвая почему-то.... Хотя они по сути идентичные.
Ты хоть сам помнишь, что они означают? Возьми редактор свойств объектов и исправь им значение поля Name на нормальное.
Да, пустое поле тоже вызывает ошибку при попытке перевести в число. Кстати, я в таких случаях делаю примерно так:
function ToFloat(E: TEdit): extended; var c: integer; begin val(E.Caption, Result, c);// пытаемся перевести чесло в строку if c <> 0 then begin // если код ошибки не равен нулю ShowMessage(E.Caption + " не число!!!"); E.SelectText(1, Length(E.Caption)); // как-то так, не помню, там вроде два свойства надо менять для выделения текста end; end;
Спасибо за функцию, думаю пригодится в будущем, только прибавить к ней немного кода на запрет значений, кроме числовых и ","... и вместо caption, наверное, text, а-то что-то не сходится....
Значит, где-то в обработчиках чего-то лишнего понавешал. На пустом проекте прекрасно отработала процедура Init. Прикрепляй свой проект целиком (только не надо EXE-шники и все временные файлы пихать, ладно? Скомпилировать я и сам могу, меня исходники интересуют)
А ничего, что Edit3 и Form1.Edit3 (и так далее) - это разные вещи? Убери напрочь этот свой "страшный Var" (у тебя ж сейчас все переменные, описанные там - NIL-ы, не инициализированные они), и сделай Init методом TForm1, тогда все будут всё видеть...
TForm1 = class(TForm) // тут ничего не меняй private { Private declarations } public { Public declarations }
procedure Init; // <--- Добавляешь прототип end;
procedure TForm1.Init; // <--- Добавляешь Tform1. begin end;
Снова здравствуйте, в процессе работы программы мне необходимо вычислить производную функции, наткнулся на форуме на "Процедурные типы и переменные". Возник вопрос: Для вычисления производной не обязательно писать объёмного кода, есть встроенные решения или я не так понял эту статью?
Помогите, пожалуйста с кое-чем: Рассматривается определенный физический процесс, с течением времени изменяются 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)Подставляем у в первую формулу
Что-то больно легко получается, но правильно ли это? Вообще производная ли это как таковая? Знакомых математиков особо нет, помогите, пожалуйста.
По формуле производной, хотя уже сомнения закрались: -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)'?
Школу давно закончил, но с математикой всегда были проблемы... Пытаюсь разобраться, но чёто везде примеры легкие и без этих примудростей с d/dt, окунаюсь в тёмный лес... Если это плёвое дело - помоги, пожалуйста...
> Пытаюсь разобраться, но чёто везде примеры легкие и без этих примудростей с d/dt
ДИФУР без этих "прИмудростей"? Такие вообще бывают? Ты примеры из какой главы смотрел? Надо по дифурам смотреть, а не просто по алгебраическим уравнениям.
Добрый вечер! Снова нужна помощь форума, помогите, пожалуйста: У меня есть форма, на которой расположены 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;
Этот код у меня не получается адаптировать к своей программе, да и сохранение здесь идет в несколько заранее заданных файлов, моя программа, кстати, ниже есть... Может есть другие способы или это кто-то знает как подключить?
Проходи в одной процедуре по всем компонентам, и пиши все в один файл:
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;
Спасибо. сохранение и загрузка происходит, только вот программа содержит очень много сложных расчетов с большой точностью и числами, после нескольки расчетов вылетает ошибка о нехватке памяти. Знаю, что переменные можно очищать с помощью 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 после? Или я просто неправильно пишу код процедуры?