|
Вопрос # 596/ вопрос решён / |
|
Здравствуйте, уважаемые эксперты!
1. Подскажите, пожалуйста, почему форма блокируется во время того пока в программе идут вычисления (в цикле решаются несколько уравнений, количество шагов несколько миллионов).
procedure TForm2.BitBtn1Click(Sender: TObject);
begin
Form2.Label1.Caption := 'Calculating. Wait...';
Calculation();
end;
В процедуре Calculation() выполняется цикл.
По идее до этого на форме должна обновиться метка Label1, но она не обновляется.
2. Хотел таким образом выводить в заголовок метки на каком шаге цикла в настоящее время я нахожусь (чтобы знать сколько времени еще ждать), но метка не обновляется. -(( Может есть другой способ вытащить номер шага цикла? На самом деле хотелось бы, чтобы форма оставалась активной во время вычислений, и чтобы можно было на ней производить операции параллельно с вычислениями.
Спасибо.
 |
Вопрос задал: Ilia Ermakov (статус: 1-ый класс)
Вопрос отправлен: 24 мая 2007, 11:53
Состояние вопроса: решён, ответов: 3.
|
Ответ #1. Отвечает эксперт: Venom
Здравствуйте, Ilia Ermakov!
если просто обновление формы, то
for i:=1 to 10000 do
begin
Label1.Text:=IntToStr(i);
Form1.Update;
end;
но лучше использовать не label,а statusbar или что-либо подобное, так нагляднее. А если необходимо производить манипуляции с формой в процессе выполнения цикла, то придется использовать потоки. Литература по ним в прикреплённом файле.
А если необходимо производить манипуляции с формой, то придется работать с потоками К ответу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки ответа)
 |
Ответ отправил: Venom (статус: 1-ый класс)
Время отправки: 24 мая 2007, 12:34
Оценка за ответ: 5
Комментарий к оценке: Спасибо, посмотрю потоки обязательно. Кстати с обновлением формы программа раз в 100 медленнее стала работать. В случае, если будуиспользовать taskbar скорость также упадет, не знаешь?
|
Ответ #2. Отвечает эксперт: Косолапов Дмитрий Юрьевич
Здравствуйте, Ilia Ermakov!
Если можно приблизительно оценить количество итераций, то прогресс-бар можно обновлять через каждые, допустим, 10000 итераций (то есть если итераций миллион, тогда 1% от миллиона - 10000)
Кстати, в качестве альтернативы Form1.Update можно воспользоваться Application.ProcessMessages (удобно, если, например, используется кнопка отмены), или метод Refresh конкретных компонентов, содержимое которых необходимо обновить.
Ну а форма блокируется как раз из-за того, что выполняется большой код, и обработка сообщений (в терминах WinAPI) временно приостанавливается (для их принудительной обработки и служит Application.ProcessMessages)
Ответ #3. Отвечает эксперт: min@y™
Дополню предыдущие ответы.
Если нужно выводить прогресс выполнения вычислений без использования дополнительного потока, я обычно делаю примерно так:
procedure TMainForm.DoSomething();
var
Index, Progress: Integer;
begin
ProgressBar.Position:= 0;
for Index:= 0 to Count - 1 do
begin
// Вычисления
Progress:= Round(100 * (Index + 1) / Count); // Count > 1
if Progress <> ProgressBar.Position
then begin
ProgressBar.Position:= Progress;
Application.ProcessMessages;
end;
end;
end;
Круче, конечно, все вычисления сделать в отдельном потоке. Если надо, могу написать пример.pas.
З.Ы. В обоих случаях можно также выводить аппроксимированное время, которое осталось до конца выполнения вычислений. Оно легко вычисляется исходя из прогесса выполнения и времени, которое прошло от начала вычислений.
 |
Ответ отправил: min@y™ (статус: Доктор наук)
Время отправки: 25 мая 2007, 08:18
Оценка за ответ: 5
Комментарий к оценке: Пришли, если не сложно, примерчик с потоком и с вычислением времени. Буду признателен.
|
Мини-форум вопроса
Всего сообщений: 3; последнее сообщение — 28 мая 2007, 08:45; участников в обсуждении: 2.
|
min@y™ (статус: Доктор наук), 25 мая 2007, 14:13 [#1]:
[quote]Пришли, если не сложно, примерчик с потоком и с вычислением времени. Буду признателен.[/quote]
Есть кусок электронной книги про работу с потоками. С примерами. Про вычисление времени пришлю в понедельник, щас некогда, сваливаю с работы купацца и пиво пить. 
Куда слать?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Ilia Ermakov (статус: 1-ый класс), 25 мая 2007, 14:36 [#2]:
Понятно, удачи на пляже! адрес ermakov_ilia@mail.ru
|
|
min@y™ (статус: Доктор наук), 28 мая 2007, 08:45 [#3]:
Выслал всё, что обещал. Пример с вычислением времени выкладываю здесь, вдруг кому пригодится.
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin, Gauges, XPMan;
type
TForm1 = class(TForm)
Gauge: TGauge;
ItersSpinEdit: TSpinEdit;
Label1: TLabel;
StartButton: TButton;
IterLabel: TLabel;
XPManifest1: TXPManifest;
ElapseLabel: TLabel;
RemainLabel: TLabel;
procedure StartButtonClick(Sender: TObject);
private
{ Private declarations }
public
FCancelled: Boolean;
procedure Process;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Process;
var
Index, Progress: Integer;
BeginTime, ElapseTime, RemainTime: TDateTime;
Remain: string;
begin
Gauge.Progress:= 0;
BeginTime:= Time();
for Index:= 0 to ItersSpinEdit.Value - 1 do
begin
IterLabel.Caption:= 'Текущая итерация: ' + IntToStr(Index + 1);
Progress:= Round(100 * (Index + 1) / ItersSpinEdit.Value);
{ ElapseTime <---> Progress
RemainTime <---> 100% - Progress
ElapseTime * (100% - Progress)
RemainTime = ------------------------------
Progress
}
ElapseTime:= Time() - BeginTime;
if Progress <> 0
then begin
RemainTime:= ElapseTime * (100 - Progress) / Progress;
Remain:= TimeToStr(RemainTime);
end
else Remain:= 'Неизвестно';
if Progress <> Gauge.Progress
then begin
Gauge.Progress:= Progress;
ElapseLabel.Caption:= 'Прошло времени: ' + TimeToStr(ElapseTime);
RemainLabel.Caption:= 'Осталось времени: ' + Remain;
Application.ProcessMessages;
end;
if FCancelled
then Exit;
end;
StartButtonClick(nil);
end;
procedure TForm1.StartButtonClick(Sender: TObject);
begin
with StartButton do
if Tag = 0
then begin // Старт
FCancelled:= False;
Tag:= 1;
Caption:= 'Стоп';
Process();
end
else begin // Стоп
Tag:= 0;
Caption:= 'Старт';
FCancelled:= True;
Application.ProcessMessages;
end;
end;
end.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
31 января 2011, 19:23: Статус вопроса изменён на решённый (изменил модератор Ерёмин А.А.): Автоматическая обработка (2 и более ответов с оценкой 5)
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|